我想寻求帮助,做一个计算器,该计算器可以识别Python中的英语单词和数字,但现在使用PLY(Python Lex-Yacc)
数字和运算符可以用两种形式给出,使用英语单词写成字符串,"plus" = "+","two" = 2,"一百一十二" = 112,等等。
例如,这些条目:
"二十五除以 5"或"25/5" 或"二十五除以五"
结果应该是相同的,一个数字 5(不是字符串)。
" -3 乘以 4" 将得到 -12
除以 0 将得到"错误" 34 除以 0" 将给出 "错误"
这应该适用于几个基本运算符"-","+","x"和"/"(减号,加号,乘以和除以),如果我键入数学符号或键入文本或混合。
以下是我的代码的某些部分:
# ------- Calculator tokenizing rules
tokens = (
'NAME','NUMBER', 'times', 'divided_by', 'plus', 'minus'
)
literals = ['=','+','-','*','/', '(',')']
t_ignore = " t"
t_plus = r'+'
t_minus = r'-'
t_times = r'*'
t_divided_by = r'/'
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
precedence = (
('left','+','-'),
('left','plus','minus'),
('left','times','divided_by'),
('left','*','/'),
('right','UMINUS'),
)
#Changed 这里的同名def p_statement_assign(p):'语句:表达式乘以divided_by加减表达式"变量[p[1]] = p[3]p[0] = 无
def p_statement_expr(p):
'statement : expression'
p[0] = p[1]
def p_expression_binop(p):
'''expression : expression '+' expression
| expression 'plus' expression
| expression '-' expression
| expression 'minus' expression
| expression '*' expression
| expression 'times' expression
| expression 'divided_by' expression
| expression '/' expression'''
if p[2] == '+' : p[0] = p[1] + p[3]
elif p[2] == '-': p[0] = p[1] - p[3]
elif p[2] == '*': p[0] = p[1] * p[3]
elif p[2] == '/': p[0] = p[1] / p[3]
我的代币定义不好吗?我怎么知道这个数字可以用英文字母或数字来介绍?
表达式(p[2] == '+' : p[0] = p[1] + p[3])
必须具有单个字符。为什么以这种形式书写p[2] == 'plus' : p[0] = p[1] + p[3]
无效?
我已经添加了 sfk 建议的代码,但我仍然无法识别以英文单词形式输入的数字和运算符。
Generating LALR tables
WARNING: 12 shift/reduce conflicts
Enter your input: calc > one + two
Undefined name 'one'
Undefined name 'two'
P1 is : 0
Enter your input: calc > 1+2
P1 is : 3
3
Enter your input: calc > 1 plus 2
Syntax error at 'plus'
P1 is : 2
2
你知道我做错了什么吗?
首先,为英语单词添加标记定义
t_plustext = r'plus'
将这些新令牌添加到tokens
tokens = (
'NAME','NUMBER', 'times', 'divided_by', 'plus', 'minus', 'plustext', ....
)
最后,以这种方式在语法中使用这些新标记:
def p_expression_binop(p):
'''expression : expression '+' expression
| expression plustext expression
'''
更新:这是语法的工作子集
#!/usr/bin/python
from __future__ import print_function
import sys
import ply.lex as lex
import ply.yacc as yacc
# ------- Calculator tokenizing rules
tokens = (
'NUMBER', 'times', 'divided_by', 'plus', 'minus', 'plustext',
'one', 'two', 'three',
)
literals = ['=','+','-','*','/', '(',')']
t_ignore = " tn"
t_plustext = r'plus'
t_plus = r'+'
t_minus = r'-'
t_times = r'*'
t_divided_by = r'/'
t_one = 'one'
t_two = 'two'
t_three = 'three'
def t_NUMBER(t):
r'd+'
try:
t.value = int(t.value)
except ValueError:
print("Integer value too large %d", t.value)
t.value = 0
return t
precedence = (
('left','+','-','plustext'),
('left','times','divided_by'),
('left','*','/'),
)
def p_statement_expr(p):
'statement : expression'
p[0] = p[1]
print(p[1])
def p_expression_binop(p):
'''expression : expression '+' expression
| expression plustext expression
| expression '-' expression
| expression '*' expression
| expression '/' expression'''
if p[2] == '+' : p[0] = p[1] + p[3]
elif p[2] == '-': p[0] = p[1] - p[3]
elif p[2] == '*': p[0] = p[1] * p[3]
elif p[2] == '/': p[0] = p[1] / p[3]
elif p[2] == 'plus': p[0] = p[1] + p[3]
def p_statement_lit(p):
'''expression : NUMBER
| TXTNUMBER
'''
p[0] = p[1]
def p_txtnumber(p):
'''TXTNUMBER : one
| two
| three
'''
p[0] = w2n(p[1])
def w2n(s):
if s == 'one': return 1
elif s == 'two': return 2
elif s == 'three': return 3
assert(False)
# See http://stackoverflow.com/questions/493174/is-there-a-way-to-convert-number-words-to-integers-python for a complete implementation
def process(data):
lex.lex()
yacc.yacc()
#yacc.parse(data, debug=1, tracking=True)
yacc.parse(data)
if __name__ == "__main__":
data = open(sys.argv[1]).read()
process(data)