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在进行缩减之前始终读取前瞻性令牌。显然,没有办法告诉它永远不要读取超前标记,因为有时需要决定解析器动作。

如果lookahead令牌可用于解析器操作(例如在bison生成的解析器中),则可以。不幸的是,在Ply中,先行标记被保留为解析器中的局部变量,这样效率更高,但访问较少。

您可以修改Ply的源代码,以使当前的超前标记成为解析器对象的成员,而不是局部变量。 (如果您想采用该想法,则将其称为lookahead [注1]。)这将在解析器中引入非常小的减速,但我怀疑它在实践中是否可见。但是,这将使共享代码更加复杂。您必须将整个已修改的Ply包(可能已重命名)作为应用程序的一部分进行分发。

超前令牌的最常见用法是编写更好的错误消息,或者辅助错误恢复。使用它来更改归约动作的行为使我感到不理想,因为大多数此类情况可以通过使用更好的语法来实现。但是想必您已经探索了替代方法,所以我将保留它。


注释

  1. 在修改yacc.py时要小心:基于不同的可能优化,存在多种版本的Parser对象。标准安装脚本从框架自动生成此文件,以使各种优化的实现彼此保持同步。要进行此修改,您将不得不使用Ply的构建机制,或者仔细地在所有不同版本中进行更改(并且有注释建议您不要这样做。)