2014-12-17 4 views
5

Продолжение моего квеста PyParsing - синтаксический анализ вложенных тернарных выражений (например, (x == 1 ? true : (y == 10 ? 100 : 200))). Таким образом, я построил следующее выражение. Который, для меня, кажется интуитивным. Однако я не получаю совпадений:Разбор вложенных тернарных выражений

any = Word(printables) 

conditional = Forward() 
sub_exp = (conditional | any) 
conditional = Literal('(') + sub_exp + Literal('?') + sub_exp + Literal(':') + sub_exp + Literal(')') 

    for exp in conditional.scanString(block_str): 
     print exp 

Первоначально я думал, что проблема связана с печатаемыми вещами, потребляющими все; Я установил excludeChars не в соответствие с :?)(, но это тоже не помогло. Альтернативой было построение вложенных выражений, по одному для « »,« ?: »и« :) «блоки. Но этот подход очень запутан. Есть ли у кого-нибудь рекомендации по разбору терминов?

UPDATE Используя ответ снизу, но модифицированный для работы с scanString:

При использовании scanString однако, он возвращает много других матчей тоже (в основном, все, что соответствующий атом).

lpar = Literal('(').suppress() 
rpar = Literal(')').suppress() 
any = Combine(OneOrMore(Word(printables, excludeChars='()?:') | White(' ', max=1))) 
expr = Forward() 
atom = any | Group(lpar + expr + Literal('?') + expr + Literal(':') + expr + rpar) 
expr << Literal('(') + atom + ZeroOrMore(expr) + Literal('?') + atom + ZeroOrMore(expr) + Literal(':') + atom + ZeroOrMore(expr) + Literal(')') 

for ternary_exp in expr.scanString(block_str): 
    print ternary_exp 
+1

Возможно, это проблема с интервалом. Соответствует ли ваше выражение «' (x == 1? True: (y == 10? 100: 200)) ''? – Kevin

+0

Нет, безрезультатно. Нет совпадений (и никаких ошибок). – JB2

+2

Вы назначаете «условный» дважды, это предназначено? Кроме того, я бы определил местозаполнитель выражений, который является вашим «(условным | любым)», и может быть протестирован отдельно. BTW: Какую часть частей вы используете отдельно? –

ответ

1

Для такого рода арифметического выражения синтаксического анализа, попробуйте использовать Pyparsing-х infixNotation встроенный (ранее известный как operatorPrecedence):

from pyparsing import * 

integer = Word(nums) 
variable = Word(alphas, alphanums) 
boolLiteral = oneOf("true false") 

operand = boolLiteral | variable | integer 

comparison_op = oneOf("== <= >= != < >") 
QM,COLON = map(Literal,"?:") 
expr = infixNotation(operand, 
    [ 
    (comparison_op, 2, opAssoc.LEFT), 
    ((QM,COLON), 3, opAssoc.LEFT), 
    ]) 

print expr.parseString("(x==1? true: (y == 10? 100 : 200))") 

Печать

[[['x', '==', '1'], '?', 'true', ':', [['y', '==', '10'], '?', '100', ':', '200']]] 

infixNotation заботится о всех рекурсивных выражений, и решает приоритет операций и переопределение этого старшинства с помощью() 'ы.

3

Я думаю, ваша проблема заключается в два раза: пробельные (не обрабатывается хорошо вашим any определению), и рекурсия (который должен использовать оператор <<):

lpar = Literal('(').suppress() 
rpar = Literal(')').suppress() 
any = Combine(OneOrMore(Word(printables, excludeChars='()?:') | White(' ',max=1))) 
expr = Forward() 
atom = any | Group(lpar + expr + Literal('?') + expr + Literal(':') + expr + rpar) 
expr << atom + ZeroOrMore(expr) 

Например,

t2 = '(x == 1 ? true : (y == 10 ? 100 : 200))' 
expr.parseString(t2) 
([(['x == 1 ', '?', 'true ', ':', (['y == 10 ', '?', '100 ', ':', '200'], {})], {})], {}) 
+0

Спасибо, я изменил свой пост с ответом. – JB2

+0

Многое, хотя я ценю upvotes, другой ответ - ведущий разработчик 'pyparsing', поэтому, возможно, должен быть принят. – xnx

+0

ОК :-) Я нашел ваше решение более понятным. Но, читая информацию о infixNotation, я думаю, его решение является «более правильным способом» этого. Спасибо, xnx! – JB2

Смежные вопросы