2017-02-10 3 views
2

У меня есть следующая грамматика и тестовый пример:Pyparsing не разбирая всю строку

from pyparsing import Word, nums, Forward, Suppress, OneOrMore, Group 

#A grammar for a simple class of regular expressions 
number = Word(nums)('number') 
lparen = Suppress('(') 
rparen = Suppress(')') 

expression = Forward()('expression') 

concatenation = Group(expression + expression) 
concatenation.setResultsName('concatenation') 

disjunction = Group(lparen + OneOrMore(expression + Suppress('|')) + expression + rparen) 
disjunction.setResultsName('disjunction') 

kleene = Group(lparen + expression + rparen + '*') 
kleene.setResultsName('kleene') 

expression << (number | disjunction | kleene | concatenation) 

#Test a simple input 
tests = """ 
(8)*((3|2)|2) 
""".splitlines()[1:] 

for t in tests: 
    print t 
    print expression.parseString(t) 
    print 

Результат должен быть

[['8', '*'],[['3', '2'], '2']] 

, но вместо этого, я получаю только

[['8', '*']] 

Как я получаю pyparsing для синтаксического анализа всей строки?

ответ

1

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

expression << OneOrMore(number | disjunction | kleene) 

С этим изменением, я получаю этот результат:

[['8', '*'], [['3', '2'], '2']] 

EDIT: Вам также избежать приоритет << над |, если вы используете оператор <<= вместо этого:

expression <<= OneOrMore(number | disjunction | kleene) 
+0

Спасибо! Почему это работает, если просто написать определение для конкатенации, правда? –

+0

Потому что ваше оригинальное выражение соответствует 'kleene', и ничто в вашем первоначальном определении' expression' не говорит о продолжении разбора. Когда вы включали «конкатенацию» как часть «выражения», это передало бы эту идею, но взяло бы вас за левое рекурсивное отверстие кролика. Или, если вы заменили операторы '' 'операторами'^'(чтобы дать выражение« match-longest »Or вместо MatchFirst), вы также получите оценку конкатенации - но опять же, вы должны были бы оставить рекурсию, пытаясь оценивать «выражение», оценивая «выражение». – PaulMcG

+0

Какую версию pyparsing вы используете? Текущие версии включают некоторые полезные методы, особенно 'expression.runTests', которые будут использовать многострочную последовательность тестовых входов и запускать ваше выражение в каждой строке и печатать анализируемые результаты или диагностический вывод. В вашем примере вы можете заменить цикл for в конце с помощью только 'expression.runTests (tests)'. По правде говоря, на протяжении многих лет я писал то же самое для цикла около тысячи раз, и, наконец, я понял, что вспомогательный метод выражения будет полезен. – PaulMcG

2

parseString имеет параметр parseAll. Если вы вызываете parseString с parseAll=True, вы получите сообщения об ошибках, если ваша грамматика не анализирует всю строку. Иди оттуда!