PLY yacc解析时全局error变量不更新 始终保留首次错误值
问题原因
p_error是PLY框架在检测到语法错误时才会触发的回调函数,如果当前传入的代码段没有任何语法错误,这个函数根本不会执行。你把error = ""的重置逻辑写在p_error内部,就意味着无错解析时全局变量error永远不会被清空,自然会一直保留第一次出错时写入的旧值。
另外你在main.py循环末尾写的r_error = ""只是修改当前函数作用域的局部变量,完全不会影响sintactico模块内的全局error变量,这行代码没有任何实际作用。
顺便提一句,你原来的EOF错误分支漏写了self.list_syn.addItem(item_syn),会导致EOF类型的错误不会显示在列表里。
修复步骤
1. 每次解析前主动重置错误状态
把错误重置的逻辑从p_error里移出来,在每次调用parse方法解析新代码段之前,手动清空sintactico模块的error变量,确保每次解析的初始状态都是无错的。
修改main.py的循环逻辑如下:
import sintactico # codigo是字符串列表,每一项是待解析的代码段 for code in codigo: # 解析前主动清空上一轮残留的错误 sintactico.error = "" # 执行语法解析 parser = sintactico.syntax.parse(code) r_error = sintactico.error print("main.py -> ", r_error) item_syn = QListWidgetItem(code) if r_error == "EOF": texto = code +"\nError en linea "+str(linea)+"\nPosible error: EOF inesperado" item_syn = QListWidgetItem(texto) item_syn.setForeground(QColor(255,0,0)) # 补全原来遗漏的列表添加逻辑 self.list_syn.addItem(item_syn) elif r_error != "": token_p = sintactico.error texto = code +"\nError en linea "+str(token_p.lineno)+"\nPosible error: "+str(token_p.value) item_syn = QListWidgetItem(texto) item_syn.setForeground(QColor(255,0,0)) self.list_syn.addItem(item_syn) print(parser) linea += 1 self.inp_codigo.clear()
2. 精简sintactico.py的错误回调逻辑
去掉p_error函数开头冗余的error = ""重置语句即可,因为重置操作已经在解析前统一处理了,p_error只需要在真的检测到错误时给error赋值:
# sintactico.py error = "" def p_error(p): global error if p: error = p print("sintactico.py IF -> Error en token ", p) else: error = "EOF" print("sintactico.py IF -> Error: se encontró EOF") print("sintactico.py -> ", error) syntax = yacc.yacc()
优化建议
- 如果不需要PLY默认的错误恢复机制(即遇到第一个错误就停止解析,不尝试继续分析后续代码),可以在p_error中直接抛出异常,或者调用
yacc.errok()控制错误处理流程,避免同一段代码多次触发p_error导致错误值被覆盖。 - 长期维护的话不建议用跨模块全局变量存储解析状态,可以把语法解析逻辑封装成类,把错误信息存在实例属性中,能彻底避免全局变量状态残留的问题,代码可维护性更高。
内容的提问来源于stack exchange,提问作者noinsanc23
相关产品推荐
相关产品推荐

