我已经尝试了this code并将其转换为我正在编写的用于编程语言处理的项目,但我遇到了一个简化版本的问题:
op = oneOf( '+ - / *')
lparen, rparen = Literal('('), Literal(')')
expr = Forward()
expr << ( Word(nums) | ( expr + op + expr ) | ( lparen + expr + rparen) )
我已经玩过这个简单设置的许多不同修改。通常,尝试类似:
print(expr.parseString('1+2'))
将返回['1']
。虽然我被深深的递归所吸引,但是:
print(expr.parseString('(1+2)'))
关于简单递归而我无法解释的是我无法解析任意算术表达式,例如1+(2 * 3-(4*(5+6)-(7))...
?
答案 0 :(得分:25)
如果我们抑制左右括号符号,并使用Group对带括号的表达式进行分组,则pyparsing将是一个更接近AST的结构化结果。
from pyparsing import Literal,Word,ZeroOrMore,Forward,nums,oneOf,Group
def Syntax():
op = oneOf('+ -')
lpar = Literal( '(' ).suppress()
rpar = Literal( ')' ).suppress()
num = Word(nums)
expr = Forward()
atom = num | Group(lpar + expr + rpar)
expr << atom + ZeroOrMore(op + atom)
return expr
if __name__ == "__main__":
expr = Syntax()
def test(s):
results = expr.parseString(s)
print s,'->', results
test( "(9 + 3)" )
test( "(9 + 3) * (4 / 5)" )
,并提供:
(9 + 3) -> [['9', '+', '3']]
(9 + 3) * (4 / 5) -> [['9', '+', '3'], '*', ['4', '/', '5']]
否则,pyparsing只是标记化,你必须遍历解析的标记列表才能找到嵌套的表达式。
由于op被定义为oneOf(“+ - * /”),因此没有优先级的操作。在https://github.com/pyparsing/pyparsing/tree/master/examples手动方式定义此(4Fn.py)的pyparsing repo上有一些示例,或者使用infixNotation
帮助器(simpleArith.py)的更新方法。同样,这使得pyparsing增加的价值不仅仅是标记化。
对于OP,请查看这些示例,我认为它们将帮助您推进项目。
- 保罗
答案 1 :(得分:9)
这或多或少是你想要的......?
from pyparsing import Literal,Word,ZeroOrMore,Forward,nums,oneOf
def Syntax():
op = oneOf( '+ - / *')
lpar = Literal( '(' )
rpar = Literal( ')' )
num = Word(nums)
expr = Forward()
atom = num | ( lpar + expr + rpar )
expr << atom + ZeroOrMore( op + expr )
return expr
if __name__ == "__main__":
expr = Syntax()
def test(s):
results = expr.parseString( s )
print s,'->', results
test( "(9 + 3)" )
test( "(9 + 3) * (4 / 5)" )
发射
(9 + 3) -> ['(', '9', '+', '3', ')']
(9 + 3) * (4 / 5) -> ['(', '9', '+', '3', ')', '*', '(', '4', '/', '5', ')']
?这通过将“原子”(数字或带括号的表达式)与“表达式”(一个或多个“原子”与中间的运算符)分开来“锚定”递归。
答案 2 :(得分:4)
语法如:
expr :: expr op expr
很难处理,因为递归只是潜入左侧。
正常的算术语法看起来像:
expr :: mulxp | mulxp '+' expr
mulxp :: atom | atom '*' expr
atom :: Word(nums) | '(' + expr + ')'
基本上,你永远不会得到S :: S
;任何时候非终结符号出现在语法的一行的左侧和右侧,中间必须有一些文字供解析器使用。
答案 3 :(得分:0)
使用operatorPrecedence
构建表达式。它将构建正确的表达式,并在其处理运算符优先级:
num = Word(nums)
plusop = oneOf( '+ -')
multop = oneOf('/ *')
expr = operatorPrecedence(num,
[(multop, 2, opAssoc.LEFT),(plusop, 2, opAssoc.LEFT)])
示例:
>> print parsetime.expr.parseString("1+(2 * 3-(4*(5+6)-(7)))")
[['1', '+', [['2', '*', '3'], '-', [['4', '*', ['5', '+', '6']], '-', '7']]]]