PLY Python 中的词法分析器错误处理

3 投票
3 回答
3727 浏览
提问于 2025-04-17 07:09

t_error()这个函数是用来处理在分析代码时遇到的错误,比如发现了不合法的字符。我想问的是:我怎么才能用这个函数获取更详细的错误信息呢?比如错误的类型,或者错误出现在哪个规则或部分等等。

3 个回答

1

在PLY中确实有管理错误的方法,可以看看这个非常有趣的演示文稿:

http://www.slideshare.net/dabeaz/writing-parsers-and-compilers-with-ply

还有第6.8.1章的内容:

http://www.dabeaz.com/ply/ply.html#ply_nn3

1

Ply里面有一个示例的ANSI-C风格的词法分析器,文件名叫做cpp.py。这个示例展示了如何从t_error()函数中提取一些信息:

def t_error(t):
    t.type = t.value[0]
    t.value = t.value[0]
    t.lexer.skip(1)
    return t

在这个函数里,你还可以访问词法分析器的一些公共属性:

  • lineno - 当前的行号
  • lexpos - 当前在输入字符串中的位置

还有一些其他的属性虽然没有列为公共的,但可能会提供一些有用的诊断信息:

  • lexstate - 当前的词法分析器状态
  • lexstatestack - 词法分析器状态的堆栈
  • lexstateinfo - 状态信息
  • lexerrorf - 错误规则(如果有的话)
3

一般来说,t_error() 函数能获取的信息非常有限。它接收一个令牌对象,里面的值是剩下的输入文本。分析这些文本的工作完全靠你自己来做。你可以使用 t.lexer.skip(n) 函数让词法分析器跳过一定数量的字符,就这些了。

除了有一个输入字符不符合任何已知令牌的规则外,并没有所谓的“错误类型”。因为词法分析器和语法分析器是分开的,所以没有直接的方法来获取解析引擎的状态,也无法知道正在解析哪个语法规则。即使你能获取到状态(这实际上只是 LALR 状态机的底层状态编号),理解它也会非常困难,因为解析器可能正在匹配许多可能的语法规则,寻找简化操作。

我的建议是:如果你在 t_error() 函数中需要更多信息,应该设置一个在词法分析器和语法分析器之间共享的对象。你应该明确让编译器的不同部分在需要时更新这个对象(例如,可以在特定的语法规则中进行更新)。

顺便说一下,对于一个错误的令牌,通常可采取的措施很少。基本上,你得到的输入文本并不属于语言字母表的任何已知部分(例如,没有已知符号)。因此,你甚至无法给解析器提供任何令牌值。通常,唯一的做法就是报告这个错误的输入,丢弃它,然后继续。

作为对 Raymond 回答的补充,我也不建议在 t_error() 中修改词法分析器对象的任何属性。

撰写回答