2016-02-18 6 views
1

У меня возникли проблемы с тем, чтобы правильно разобрать рекурсивную грамматику, используя pyparsing. Тест # 5 в коде ниже не удается, несмотря на мое мышление, что она признает его в качестве трех матчей «парам» парсер (два из которых вложены в один «родителя»):pyparsing с рекурсивной грамматикой

import pyparsing as p 

DOUBLE_QUOTE = p.Word('"') 
SINGLE_QUOTE = p.Word("'") 
COMMA   = p.Suppress(p.Word(",")) 
EQUALS  = p.Suppress(p.Word("=")) 
RIGHT_PAREN = p.Suppress(p.Word(")")) 
LEFT_PAREN = p.Suppress(p.Word("(")) 
WORD   = p.Word(p.alphanums + '<' + '<' + '>' + '/' + '.' + ':' + \ 
     ';' + '-' + '_' + '$' + '+' + '*' + '&' + '!' + '%' + '?' + '@' + '\\') 
QUOTED_STRING = p.QuotedString("'") | p.QuotedString('"') 
value   = WORD | QUOTED_STRING 
value_list = value + p.ZeroOrMore(COMMA + value) 
keyword  = WORD 
pv1   = value 
pv2   = (LEFT_PAREN + value_list + RIGHT_PAREN) 
pv3   = p.Forward() 
param   = keyword + EQUALS + p.Group(p.OneOrMore(pv3) | pv2 | pv1) 
pv3 << (LEFT_PAREN + param + RIGHT_PAREN) 

parser = p.OneOrMore(p.Group(param)) 

tests = [] 
tests.append("""l1=v1""") 
tests.append("""l1=(v1,v2,v3)""") 
tests.append("""l1=(v1,v2,v3) l1=(v4, v5, v6)""") 
tests.append("""l1=(l2=v1)""") 
tests.append("""l1=v1 l1=v2""") 

# This test fails 
tests.append("""l1=(l2=(l3=v1))""") 

results = [] 
for (i, test_string) in enumerate(tests): 
    try: 
     results.append(parser.parseString(test_string)) 
    except Exception as e: 
     print("Failed test #{}".format(i)) 
     print(e) 

Где я Неправильно здесь?

+0

Последние версии Pyparsing включают 'runTests()' метод на ParserElements, так что вы могли бы упростить код тестирования, поставив все тесты на отдельных строках в тройном кавычках, а просто запустить 'parser.runTests (тесты) '. – PaulMcG

+1

Я дам вам попробовать @PaulMcGuire. Кроме того, спасибо за pyparsing - это было фантастично! – dfdashh

ответ

2

Мне потребовалось некоторое время, чтобы понять это, поскольку я проверял, была ли ваша рекурсия правильной. Но оказалось, что ваш код ожидал от двух строк кода вверху вашего кода (который, как я предполагал, был исправлен)

Ошибка была вызвана тем, что вы установили parenthese, используя p.Word вместо p.Literal. Таким образом, изменяя вам код в этом он должен работать:

RIGHT_PAREN = p.Suppress(p.Literal(")")) 
LEFT_PAREN = p.Suppress(p.Literal("(")) 

Просто напоминание от PyParsing wiki:

Буквальное - построить с строку, которая будет соответствовать именно

Слово - один или несколько смежных символов; построить со строкой, содержащей набор разрешенных начальных символов, и необязательную вторую строку разрешенных символов тела;

+0

Ага! Это было именно так. Спасибо! – dfdashh