[英]How to implement for circular dependency grammar structure in parser using PLY
作為家庭作業的一部分,我正在嘗試使用 PLY 構建掃描儀和解析器。
以下是我試圖實現的語法:
我想我能夠處理掃描儀部分,但我需要解析器部分的幫助。 我正在努力在兩者中添加規則。 我不斷收到以下消息。 根據語法,就像某種循環引用。 在這種情況下,我不確定如何正確實施它。 我對編譯器概念以及 Python 編程相當陌生。 任何幫助深表感謝。
警告:1減少/減少沖突
警告:使用規則解決 state 3 中的減少/減少沖突(語句 -> binop)
警告:state 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)
你有這三個規則:
statement : binop
statement : term
term : binop
這是模棱兩可的,因為由binop
組成的語句可以直接解析為binop
或作為binop
的term
。 (碰巧,這兩種情況下的操作不同,但即使操作相同,Ply 也會抱怨,因為 Ply 並沒有真正看到這些操作;它們是不透明的 Python 代碼。)
因此,您需要通過刪除其中一個模棱兩可的產品來解決這個問題。 原始語法應該指導你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.