【发布时间】:2020-07-23 08:03:23
【问题描述】:
作为家庭作业的一部分,我正在尝试使用 PLY 构建扫描仪和解析器。
下面是我想要达到的语法:
我认为我能够处理扫描仪部分,但我需要一些关于解析器部分的帮助。我正在努力在 和 中添加规则。我不断收到以下消息。根据语法,就像某种循环引用。在这种情况下,我不确定如何正确实施它。我对编译器概念和 Python 编程相当陌生。非常感谢任何帮助。
警告:1 减少/减少冲突
警告:使用规则(语句 -> binop)解决状态 3 中的减少/减少冲突
警告:在状态 3 中拒绝规则(术语 -> binop)
这是我的源代码:
import sys
sys.path.insert(0, "../..")
tokens = ('ID', # ID represents a variable name
'NUM', # NUM represents the signed integer data type
'EQL', # EQL represents the equal sign (=)
'ADD', # ADD represents the addition operator (+)
'SUB', # SUB represents the subtraction operator (-)
'MUL', # MUL represents the multiplication operator (*)
'DIV', # DIV represents the division operator (/)
'EXP', # EXP represents the exponentiation operator (**)
'STR', # STR represents the string data type
'VAR' # var represents the literal string 'VAR'
)
# Regular expresssion rules for the equal sign and literals
t_EQL = r'\='
t_ADD = r'\+'
t_SUB = r'-'
t_MUL = r'\*'
t_DIV = r'\/'
# create a method for parsing VAR tokens
# regex for finding VAR tokens
# return token
def t_VAR(t):
r'VAR'
return t
# create a method for parsing ID tokens
# regex for finding ID tokens
# return token
def t_ID(t):
r'[a-zA-Z_][0-9a-zA-Z_]*'
return t
# create a method for parsing NUM tokens
# regex for finding NUM tokens
# convert token from str to int
# return token
def t_NUM(t):
r'-?\d+'
t.value = int(t.value)
return t
# create a method for parsing EXP tokens
# regex for finding EXP tokens
# return token
def t_EXP(t):
r'\*{2}'
return t
# create a method for parsing STR tokens
# regex for finding STR tokens
# return token
def t_STR(t):
r'"[\s.a-zA-Z_]+"'
return t
t_ignore = " \t"
def t_newline(t):
r'\n+'
t.lexer.lineno += t.value.count("\n")
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# Build the lexer
import ply.lex as lex
lexer = lex.lex()
# Parsing rules
precedence = (
('left','ADD','SUB'),
('left','MUL','DIV'),
('left', 'EXP'),
('right', 'UMINUS')
)
# dictionary of names
names = { }
def p_statement(p):
'''statement : assign
| declare
| binop
'''
p[0] = p[1]
def p_statement_print(p):
'''statement : term'''
print(p[1])
def p_assign(p):
'''assign : ID EQL term
| ID EQL STR'''
names[p[1]] = p[3]
def p_binop(p):
'''binop : term ADD term
| term SUB term
| term MUL term
| term DIV term
| term EXP term
| STR ADD STR'''
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] == '**': p[0] = p[1] ** p[3]
def p_declare(p):
'''declare : VAR ID
| VAR assign'''
names[p[0]] = p[2]
def p_uminus(p):
'term : SUB term %prec UMINUS'
p[0] = -p[2]
def p_term_binop(p):
'term : binop'
p[0] = p[1]
def p_term_number(p):
'term : NUM'
p[0] = p[1]
def p_term_name(p):
'term : ID'
try:
p[0] = names[p[1]]
except LookupError:
print("Undefined name '%s'" % p[1])
p[0] = 0
def p_error(p):
print("Syntax error at '%s'" % p.value)
import ply.yacc as yacc
parser = yacc.yacc()
while True:
try:
s = input("Enter a line of code: ")
except EOFError:
break
if not s:
continue
yacc.parse(s)
【问题讨论】:
标签: python-3.x parsing lexer ply