Analysis of nested ternary expressions

The continuation of my PyParsing quest is the parsing of nested 3D expressions (for example, (x == 1 ? true : (y == 10 ? 100 : 200)) ). So I built the following expression. Which, for me, seems intuitive. However, I am not getting matches:

 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 

Initially, I thought the problem was with printable materials that consumed everything; I did not set excludeChars to :?)( But that didnโ€™t help either. An alternative was to create nested expressions, one for the blocks "(?", "?:" And ":)". But this approach is very confusing. There is Does anyone have any recommendations on parsing ternary expressions?

UPDATE Using the answer below, but modified to work with scanString:

However, when using scanString, it also returns many other matches (basically something like an atom).

 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 
+5
source share
2 answers

For such parsing of arithmetic expressions, try using the built-in pyparsing infixNotation (formerly known as 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) )") 

Print

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

infixNotation executes all recursive expressions and decides the priority of operations and overriding this priority using ().

+1
source

I think your problem is twofold: a space (which is poorly handled by your definition of any ) and recursion (which should use the << operator):

 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 ) 

For instance,

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

Source: https://habr.com/ru/post/1209358/


All Articles