python - Python PLY:在输入的每一行上都出现语法错误
问题描述
正在为 C 的 for 循环构造编写编译器。但是,我仍然停留在解析 C 程序的起始部分的初步任务,即要包含的头文件和主函数。
这是我的代码:
import ply.lex as lex
import ply.yacc as yacc
tokens = ('HASH','INCLUDE','HEADER_FILE','MAIN','FLOW_OPEN','FLOW_CLOSE','SEMI_COLON','TYPE','SMALL_OPEN','SMALL_CLOSE','OTHERS')
t_HASH = r'\#'
t_INCLUDE = r'include'
t_HEADER_FILE = r'<stdio.h>'
t_MAIN = r'main'
t_FLOW_OPEN = r'{'
t_FLOW_CLOSE = r'}'
t_SMALL_OPEN = r'\('
t_SMALL_CLOSE = r'\)'
t_SEMI_COLON = r';'
t_OTHERS = r'[a-zA-Z][a-zA-Z]*'
t_TYPE = r'int|void'
def t_error(token):
print(f'Illegal character: {token.value}')
def t_whitespace(t):
r'\s+'
pass
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
lexer = lex.lex()
#Building the parser
def p_expression_start(p):
'expression : header body'
def p_header(p):
'header : HASH INCLUDE HEADER_FILE'
def p_body(p):
'body : main rest'
def p_main(p):
'main : TYPE MAIN SMALL_OPEN SMALL_CLOSE'
def p_rest(p):
'rest : FLOW_OPEN st FLOW_CLOSE'
def p_st(p):
''''
st : OTHERS st
| end
'''
def p_end(p): #Empty production
'end : SEMI_COLON'
def p_error(p):
print("Syntax error in input!")
parser = yacc.yacc(method='LALR',debug=True)
with open(r'forparsing.txt','r') as file:
while True:
try:
line = next(file)
print('Parsing')
parser.parse(line)
except:
print('Finished')
break
我给出的输入是:
# include <stdio.h>
void main()
{
abc;
}
但是在运行程序时,我在每一行都得到一个语法错误。这里可能有什么问题。据我了解,解析器无法从给定的输入中推导出开始符号,但我不知道如何解决这个问题。一般来说,如何调试 PLY 的语法错误问题?
解决方案
您的任何输入行本身在语法上都不是有效的。它们仅在整体解析时才形成语法上有效的程序。因此,您需要parse
使用包含整个程序的字符串调用一次,而不是每行一次。
您可以通过调用file.read()
文件处理代码而不是使用while
循环来做到这一点。
修复此问题后遇到的语法错误是由于在 PLY 中处理重叠词法规则的方式。在理智的词法分析器生成器中,产生最长匹配的规则获胜,如果两者产生相同的匹配,则代码中首先出现的规则获胜。然而,在 PLY 中,正则表达式最长的那个获胜。由于这种行为,您不能使用单独的规则来使用 PLY 匹配标识符和关键字。在这种情况下,t_OTHERS
即使t_INCLUDE
也匹配,也会使用该规则。
相反,PLY 文档建议使用以下匹配标识符和关键字的方式:
要处理保留字,您应该编写一条规则来匹配标识符并在函数中进行特殊名称查找,如下所示:
reserved = { 'if' : 'IF', 'then' : 'THEN', 'else' : 'ELSE', 'while' : 'WHILE', ... } tokens = ['LPAREN','RPAREN',...,'ID'] + list(reserved.values()) def t_ID(t): r'[a-zA-Z_][a-zA-Z_0-9]*' t.type = reserved.get(t.value,'ID') # Check for reserved words return t
这种方法大大减少了正则表达式规则的数量,并且可能会使事情变得更快。
注意:您应该避免为保留字编写单独的规则。例如,如果您编写这样的规则,
t_FOR = r'for' t_PRINT = r'print'
对于包含这些词作为前缀的标识符,例如“忘记”或“打印”,将触发这些规则。这可能不是你想要的。
再次需要指出的是,使用最大咀嚼规则的词法分析器生成器中不存在上述两个问题。
一般来说,如何调试 PLY 的语法错误问题?
第一步是更改p_error
以打印出一些有用的信息(例如哪一行上的哪种类型的标记导致语法错误),如下所示:
def p_error(p):
if p == None:
token = "end of file"
else:
token = f"{p.type}({p.value}) on line {p.lineno}"
print(f"Syntax error: Unexpected {token}")
推荐阅读
- angular - 我想以角度在两个单独的循环中添加序列号
- python - python pandas数组合并
- excel - Excel VLOOKUP/INDEX 根据值多次
- apache-spark - 作业的 TaskCommitDenied(驱动程序拒绝任务提交):
分割: ,尝试次数: - python - 排序链接不会在 django-tables2 中保留页面锚点
- php - laravel find() 返回空刀片文件时返回错误
- vba - excel 访问选择性行传输而不是整个电子表格
- javascript - 在 Vue-cli 中手动重复 animateCss 失败
- php - PayPal IPN 突然停止工作
- git - Git仅合并两个分支之间的差异