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