2010-12-31 18 views
5

Sto cercando di capire come eseguire un'espressione associativa di sinistra in cui sono possibili espressioni ricorsive (non racchiuse in qualsiasi cosa). Ad esempio, mi piacerebbe fare:Espressioni ricorsive con pyparsing

expr + OP + expr 

che analizza 2 operazioni come 1 x 2 x 3 in (expr OP expr) OP expr risultato.

Se cerco di evitare che expr analisi da ricorsione infinita, posso fare qualcosa di simile:

expr -> Group(simple_expr + OP + expr) 
     | simple_expr 

ma poi mi piacerebbe ottenere il risultato expr OP (expr OR expr).

Come si impone il binding sul lato sinistro?

Modifica: conosco lo operatorPrecedence ma quando l'operatore è "IS" + Optional("NOT") o simile, non sembra corrispondere correttamente.

risposta

8

Ecco un esempio di azione parse che prendere le liste piatte di gettoni e loro nido come se analizzato a sinistra in modo ricorsivo:

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] 

Stampe:

(normali)

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

(simile a LR)

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

Pyparsing produce alberi di analisi a sinistra. Aggiungi un'azione semantica per modificare l'albero di analisi subito dopo l'analisi di expr.