如评论中
@AustinHastings所说,Ply通过将词法分析器类中提供的正则表达式组合来构建词法扫描器,这些正则表达式可以是类成员的值,也可以是类成员函数的文档字符串。一旦扫描器被构建,它就不会被修改,因此在生成扫描器之后,您确实无法动态调整正则表达式。
然而,对于您考虑的特定应用程序,创建自定义正则表达式并不是必需的。您可以使用
Ply手册中演示的简单得多的过程,该过程显示了如何识别保留字而无需为每个单词创建自定义正则表达式。
这个想法真的很简单。保留字(在您的情况下是函数名)通常是已经在词法分析器中使用的某些更一般模式的具体示例。这几乎肯定是这种情况,因为词法分析器必须以某种方式识别每个标记,因此在将动态生成的单词添加到扫描器之前,它必须被识别为其他东西。与其尝试覆盖特定实例的其他模式,我们只需让标记被识别,然后在返回标记之前更正其类型(以及可能的值)。
这是从Ply手册中稍作修改的示例版本:
def t_ID(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
token = t.value.lower()
if token in self.funcs:
t.type = 'FUNC'
return t
您可能希望调整上面的内容,以便对与funcs
字典中键相关联的值执行某些操作,尽管这可以在语义分析期间稍后完成。
由于funcs
字典在词法分析器(或解析器)的生成过程中并不以任何方式参与,因此不需要特别聪明才能将其传递到Lexer对象中。实际上,它甚至不需要在词法分析器对象中;您可以在构造词法分析器对象时将解析器对象添加到词法分析器对象中,从而使您可以将字典放入解析器对象中,使其更易于被解析器动作访问。
这比尝试构建自定义正则表达式的一个原因是,它不会识别作为非保留字前缀的保留字。例如,如果cos
是其中之一函数,并且您已经成功生成了相应的内容
t_ID = r'[a-zA-Z_][a-zA-Z_0-9]*'
def t_FUNC(t):
r'(?i)sin|cos|tan'
然后您会发现:
cost = 3
被扫描为FUNC(cos), ID(t), '=', NUMBER(3)
,几乎肯定不是您想要的。将逻辑放在t_ID
函数内部完全避免了这个问题,因为只有完整的标记才会被考虑。
t_FUNC_
返回它的第二个参数。它不返回正则表达式。 - DYZ