Recursive expressions with pyparsing

后端 未结 2 1076
深忆病人
深忆病人 2021-01-05 22:04

I\'m trying to figure out how to do a left-associative expression where recursive (not-enclosed in anything) expressions are possible. For example, I\'d like to do:

相关标签:
2条回答
  • 2021-01-05 22:12

    Pyparsing produces left parse trees. Add a semantic action to edit the parse tree right after expr has been parsed.

    0 讨论(0)
  • 2021-01-05 22:30

    Here is an example parse action that will take the flat lists of tokens and nest them as if parsed left-recursively:

    from pyparsing import *
    
    # parse action -maker
    def makeLRlike(numterms):
        if numterms is None:
            # None operator can only by binary op
            initlen = 2
            incr = 1
        else:
            initlen = {0:1,1:2,2:3,3:5}[numterms]
            incr = {0:1,1:1,2:2,3:4}[numterms]
    
        # define parse action for this number of terms,
        # to convert flat list of tokens into nested list
        def pa(s,l,t):
            t = t[0]
            if len(t) > initlen:
                ret = ParseResults(t[:initlen])
                i = initlen
                while i < len(t):
                    ret = ParseResults([ret] + t[i:i+incr])
                    i += incr
                return ParseResults([ret])
        return pa
    
    
    # setup a simple grammar for 4-function arithmetic
    varname = oneOf(list(alphas))
    integer = Word(nums)
    operand = integer | varname
    
    # ordinary opPrec definition
    arith1 = operatorPrecedence(operand,
        [
        (None, 2, opAssoc.LEFT),
        (oneOf("* /"), 2, opAssoc.LEFT),
        (oneOf("+ -"), 2, opAssoc.LEFT),
        ])
    
    # opPrec definition with parseAction makeLRlike
    arith2 = operatorPrecedence(operand,
        [
        (None, 2, opAssoc.LEFT, makeLRlike(None)),
        (oneOf("* /"), 2, opAssoc.LEFT, makeLRlike(2)),
        (oneOf("+ -"), 2, opAssoc.LEFT, makeLRlike(2)),
        ])
    
    # parse a few test strings, using both parsers
    for arith in (arith1, arith2):
        print arith.parseString("A+B+C+D+E")[0]
        print arith.parseString("A+B+C*D+E")[0]
        print arith.parseString("12AX+34BY+C*5DZ+E")[0]
    

    Prints:

    (normal)

    ['A', '+', 'B', '+', 'C', '+', 'D', '+', 'E']
    ['A', '+', 'B', '+', ['C', '*', 'D'], '+', 'E']
    [['12', 'A', 'X'], '+', ['34', 'B', 'Y'], '+', ['C', '*', ['5', 'D', 'Z']], '+', 'E']
    

    (LR-like)

    [[[['A', '+', 'B'], '+', 'C'], '+', 'D'], '+', 'E']
    [[['A', '+', 'B'], '+', ['C', '*', 'D']], '+', 'E']
    [[[[['12', 'A'], 'X'], '+', [['34', 'B'], 'Y']], '+', ['C', '*', [['5', 'D'], 'Z']]], '+', 'E']
    
    0 讨论(0)
提交回复
热议问题