python - Python PLY 在解析期间获取下一个令牌
问题描述
我正在尝试获取下一个令牌并根据它进行一些操作。我知道这很奇怪,但仍然有可能做到这样的事情吗?:
def p_func(p):
'''expr : MY_TOKEN'''
if next_token is None:
#do something here
p[0] = p[1]
我尝试执行以下操作:
def p_func(p):
'''expr : MY_TOKEN'''
if parser.token() is None:
#do something here
p[0] = p[1]
它可以获取令牌,但是在此函数之后,下一个令牌跳过了,因为我拿了它。是否可以将其退回或仅获取下一个令牌的副本?
解决方案
我不相信在 Ply 中有可靠的方法来做到这一点。
Ply 通常在执行归约之前读取下一个标记(“前瞻标记”),因此调用parser.token()
通常会返回第二个下一个标记。但是 Ply 不保证在归约之前读取下一个标记:在某些情况下,它可以在没有前瞻的情况下推断出动作,它会立即执行归约。因此,由 产生的令牌parser.token()
可能是下一个令牌,因为它显然在您尝试它的特定规则中。
如果您需要一致性,您可以指示 Ply 在进行归约之前始终读取前瞻标记。显然,没有办法告诉它永远不要读取前瞻标记,因为有时需要决定解析器的操作。
如果前瞻标记可用于解析器操作,这将很好,因为它在由野牛生成的解析器中(例如)。不幸的是,在 Ply 中,前瞻标记作为局部变量保存在解析器中,这样更有效但更难访问。
您可以修改 Ply 的源代码,使当前的前瞻标记成为解析器对象的成员,而不是局部变量。(lookahead
如果你想追求这个想法[注 1],就会调用它。)这会在解析器中引入一个非常小的减速,但我怀疑它在实践中是否可见。但是,这会使共享代码变得更加复杂;您必须将整个修改后的 Ply 包(可能已重命名)作为应用程序的一部分分发。
前瞻令牌最常见的用途是制作更好的错误消息,或以其他方式协助错误恢复。使用它来改变归约动作的行为让我觉得不是最理想的,因为大多数这样的情况都可以通过使用更好的语法来实现。但大概你已经探索了替代方案,所以我将把它留在那里。
笔记
- 修改时要小心
yacc.py
:Parser 对象有多个版本,基于不同的可能优化。标准安装脚本从骨架自动生成此文件,以保持各种优化的实现彼此同步。要进行此修改,您要么必须使用 Ply 的构建机制,要么在所有不同版本中仔细进行更改(并且有评论建议您不要这样做。)