Python 考虑到'|';?(Ply/Yacc)

Python 考虑到'|';?(Ply/Yacc),python,abstract-syntax-tree,yacc,ply,Python,Abstract Syntax Tree,Yacc,Ply,考虑到以下语法: expr : expr '+' term | expr '-' term | term term : term '*' factor | term '/' factor | factor factor : '(' expr ')' | identifier | number 这是我使用ply的代码: from ply import lex, yacc tokens = [ "identifier", "number", "plus", "mi

考虑到以下语法:

expr : expr '+' term | expr '-' term | term
term : term '*' factor | term '/' factor | factor
factor : '(' expr ')' | identifier | number
这是我使用ply的代码:

from ply import lex, yacc

tokens = [
    "identifier",
    "number",
    "plus",
    "minus",
    "mult",
    "div"
]

t_ignore = r" \t"
t_identifier = r"^[a-zA-Z]+$"
t_number = r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?"
t_plus = r"\+"
t_minus = r"-"
t_mult = r"\*"
t_div = r"/"

def p_stmt(p):
    """stmt : expr"""
    p[0] = ("stmt", p[1])

def p_expr(p):
    """expr : expr plus term 
            | expr minus term 
            | term"""
    p[0] = ("expr", p[1], p[2]) # Problem here <<<

def p_term(p):
    """term : term mult factor 
            | term div factor 
            | factor"""

def p_factor(p):
    """factor : '(' expr ')' 
              | identifier 
              | number"""


if __name__ == "__main__":
    lex.lex()
    yacc.yacc()
    data = "32 + 10"
    result = yacc.parse(data)
    print(result)
来自ply import lex,yacc
代币=[
“标识符”,
“数字”,
“加”,
“负”,
“骡子”,
“部门”
]
t_ignore=r“\t”
t_identifier=r“^[a-zA-Z]+$”
t\U编号=r“[+-]?(\d+(\.\d*)?\.\d+([eE][+-]?\d+)?”
t\u plus=r“\+”
t_减=r“-”
t\u mult=r“\*”
t_div=r/“
def p_stmt(p):
“”“stmt:expr”“”
p[0]=(“stmt”,p[1])
def p_expr(p):
“”“expr:expr+term
|表达式负项
|术语“”

p[0]=“expr”,p[1],p[2])#这里的问题据我所见,在
p[0]=“expr,p[1],p[2])
p[1]
将是左手表达式,
p[2]
将是运算符,
p[3]
(您没有使用)将是右手项

只需使用
p[2]
来确定操作员,添加
p[3]
,因为您需要它,您应该可以随时使用

此外,您必须验证
p
有多少项,因为如果最后一条规则,
|term”“
匹配,
p
将只有两项而不是四项

请看一段来自


问题是,当我使用P[3 ]时,我得到一个列表索引超出范围。操作符没有被考虑。在PDF中,我已经链接了,他们明确地保存了操作符:(+,p(1),p(2))。问题是,它可以是任何操作符,我需要考虑优先权。噢,对。肯定是因为最后一行,<代码>名词“”。
:当最后一条规则匹配时,
p
将只有两项而不是四项。这很奇怪,因为“32+10”应该匹配“expr+term”,因为expr和term最终都是一个数字。首先,是的,但请注意规则是递归的,因此将再次匹配与最后一条规则匹配的“32”。我建议在函数的开头放一个断点或一个日志,这样你就可以更好地理解我的意思了。。。我看到了递归的结束(如此明显,不知何故我忘记了那里的基本原理)。非常感谢。我不明白你为什么因为优先权而觉得“不能分离功能”。优先权没有问题。你没有使用优先权,真的;语法是明确的,运算符优先级是语法中固有的。在两个不同的动作函数之间划分一个非终结符不会改变语法,并产生更简单的动作。
def p_comparison(p):
    """comparison : comparison PLUS comparison
                  | comparison MINUS comparison
                  | comparison MULT comparison
                  | comparison DIV comparison
                  | comparison LT comparison
                  | comparison EQ comparison
                  | comparison GT comparison
                  | PLUS comparison
                  | MINUS comparison
                  | power"""
    if len(p) == 4:
        p[0] = binary_ops[p[2]]((p[1], p[3]))
    elif len(p) == 3:
        p[0] = unary_ops[p[1]](p[2])
    else:
        p[0] = p[1]