Python 方程赋值

Python 方程赋值,python,parsing,equation,ply,Python,Parsing,Equation,Ply,我正在使用PLY创建一个计算器。 我希望能够将等式分配给字典,就像我能够将变量分配给另一个字典一样 我分配变量的方式:x=10(在dictx中将是键,10将是值) 我希望能够分配公式的方式:fun(x)=x+42(在dictfun中,将是键,元组('x','x+10')将是值) 它正在使用这种书写方式fun | x |=x+42(注意此处的“管道”符号)。但它不适用于括号 我怎样才能使它以正确的方式工作 以下是我目前的代码: 将ply.yacc导入为yacc 将ply.lex导入为lex ###

我正在使用PLY创建一个计算器。 我希望能够将等式分配给字典,就像我能够将变量分配给另一个字典一样

我分配变量的方式:
x=10
(在dict
x
中将是键,
10
将是值)

我希望能够分配公式的方式:
fun(x)=x+42
(在dict
fun
中,将是键,元组
('x','x+10')
将是值)

它正在使用这种书写方式
fun | x |=x+42
(注意此处的“管道”符号)。但它不适用于括号

我怎样才能使它以正确的方式工作

以下是我目前的代码:

将ply.yacc导入为yacc
将ply.lex导入为lex
##################################雷克瑟################################
代币=(
“姓名”,
“数字”,
)
t_NAME=r'[a-zA-Z]+'
文字='+=-*/|()'
t\u ignore=“\t”
def t_编号(t):
r'(?:\d+(?:\。\d*)?)
t、 value=int(t.value)
返回t
def t_错误(t):
打印('非法字符\'{}''.format(t.value[0]))
t、 lexer.skip(1)
##################################分析器################################
函数={}
变量={}
def p_操作(p):
“”语句:表达式
表达方式:第五
第五:第四
第四:第三
第三:第二
第二:第一
第一:数字
"""
p[0]=p[1]
def p_plus(p):
“第五:第五”+“第四”
如果isinstance(p[1],str)或isinstance(p[3],str):
p[0]=str(p[1])+p[2]+str(p[3])
其他:
p[0]=p[1]+p[3]
def p_减(p):
“第五:第五”-“第四”
如果isinstance(p[1],str)或isinstance(p[3],str):
p[0]=str(p[1])+p[2]+str(p[3])
其他:
p[0]=p[1]-p[3]
def p_隐式时间(p):
“第四:第四秒”
如果isinstance(p[1],str)或isinstance(p[2],str):
p[0]=str(p[1])+str(p[2])
其他:
p[0]=p[1]*p[2]
def p_时间(p):
“第四:第四”*“第三”
如果isinstance(p[1],str)或isinstance(p[3],str):
p[0]=str(p[1])+p[2]+str(p[3])
其他:
p[0]=p[1]*p[3]
def p_除法(p):
“第四:第四”/“第三”
如果isinstance(p[1],str)或isinstance(p[3],str):
p[0]=str(p[1])+p[2]+str(p[3])
其他:
p[0]=p[1]/p[3]
def p_一元数减(p):
“第三名:-“第三名”
如果存在(p[2],str):
p[0]='-'+p[2]
其他:
p[0]=-p[2]
def p_电源(p):
“”“第二:第一个”“^”“第三个”“”
如果isinstance(p[1],str)或isinstance(p[3],str):
p[0]=str(p[1])+p[2]+str(p[3])
其他:
p[0]=p[1]**p[3]
def p_块(p):
“第一个:”(“表达式”)“”“
p[0]=p[2]
################################这里有问题############################
def p_语句_赋值(p):
''语句:名称'='表达式''
变量[p[1]]=p[3]
p[0]=p[3]
def p_功能分配(p):
''语句:名称'|'表达式'|''''='表达式''
函数[p[1]=(p[3],p[6])
p[0]=函数[p[1]]
def p_变量表达式(p):
''第一:名字''
尝试:
p[0]=变量[p[1]]
除:
p[0]=p[1]
def p_错误(t):
打印(“语法错误!”)
##################################主要#################################
lexer=lex.lex()
parser=yacc.yacc()
尽管如此:
尝试:
问题=原始输入(“>>>”)
除:
问题=输入(“>>>”)
answer=parser.parse(问题)
如果答案不是无:
打印(答案)

您允许隐式乘法。这意味着
f(x)
可以被解析为乘积,在这种情况下,根据隐式乘法规则,
f
必须减少到
fourth
。但如果要将其解析为赋值,则需要将其保留为
名称
。这是一个shift-reduce冲突,在
解析器中很容易看到。out

state 3

    (16) statement -> NAME . = expression
    (17) statement -> NAME . ( expression ) = expression
    (18) first -> NAME .

  ! shift/reduce conflict for ( resolved as shift
您在这里看到的是,当解析器看到
名称
后接
)时,它不知道是将
名称
缩减为
第一个
(然后是
第二个
,直到
第四个
),期望语句是一个简单的计算,还是移动
),从而承诺将其视为函数定义

您可能已经遇到过类似的问题,因为函数定义的自然语法是:

statement : NAME '(' NAME ')' '=' expression
但是您已经将第二个
名称
替换为
表达式
。这将避免移位减少
之前的冲突,代价是接受有问题的函数定义(
f(a+3)=2a

可以采取类似的措施来避免这种转变,减少冲突(但这是一种非常临时的解决方案):

从接受正确表达式的意义上说,它“有效”。但它也默默地(或有点默默地)接受许多其他表达式:

这个很好:

>>> f(a) = a + 3
('a', 'a+3')
但这些都很奇怪:

>>> -f(a) = a + 3
('a', 'a+3')
>>> 3f(a) = a + 3
('a', 'a+3')
>>> 3f(a+2) = a + 3
('a+2', 'a+3')
或者,您可以忽略shift-reduce冲突,因为默认情况下,PLY将执行移位(如
parser.out
:“解析为移位”)。这将防止解析器接受上述奇怪的示例,但也会错误地解析一些似乎合理的表达式:

这些似乎是合适的:

>>> f(a) = a + 3
('a', 'a+3')
>>> -f(a) = a + 3
Syntax error!
a+3
>>> 3f(a) = a + 3
Syntax error!
a+3
但我们可能期望这会打印105:

>>> a=7
7
>>> a(2a+1)
Syntax error!
如果你不介意的话,你现在可以停止阅读了


您的语法没有歧义,如果您编写的定义语法更加具体,也不会有歧义:

statement : NAME '(' NAME ')' '=' expression
或者,如果希望允许函数具有多个参数:

statement : NAME '(' name_list ')' '=' expression
name_list : NAME
name_list : name_list ',' NAME
但它不是LR(1),要使它成为LR(1)是非常困难的。上面提到的两种语法都是LR(4),而且由于每个LR(k)语法理论上都可以机械地转换为(非常臃肿且难以阅读的)LR(1)克
statement : NAME '(' name_list ')' '=' expression
name_list : NAME
name_list : name_list ',' NAME
statement : fourth '(' expression ')' '=' expression