如何用PLY处理一个token的多条规则
我正在处理一个jison文件,并使用Python的PLY库中的lex模块将其转换为解析器生成器。
我注意到,在这个jison文件中,某些标记(tokens)有多个规则。例如,对于标记CONTENT
,文件中指定了以下三个规则:
[^\x00]*?/("{{") {
if(yytext.slice(-2) === "\\\\") {
strip(0,1);
this.begin("mu");
} else if(yytext.slice(-1) === "\\") {
strip(0,1);
this.begin("emu");
} else {
this.begin("mu");
}
if(yytext) return 'CONTENT';
}
[^\x00]+ return 'CONTENT';
// marks CONTENT up to the next mustache or escaped mustache
<emu>[^\x00]{2,}?/("{{"|"\\{{"|"\\\\{{"|<<EOF>>) {
this.popState();
return 'CONTENT';
}
在另一个情况下,COMMENT
标记也有多个规则:
<com>[\s\S]*?"--}}" strip(0,4); this.popState(); return 'COMMENT';
<mu>"{{!--" this.popState(); this.begin('com');
<mu>"{{!"[\s\S]*?"}}" strip(3,5); this.popState(); return 'COMMENT';
当这些规则适用于不同的状态时,区分起来似乎很简单,但如果它们适用于相同的状态呢?
我该如何使用ply.lex将这个jison转换为Python规则呢?
编辑
如果有帮助的话,这个jison文件是handlbars.js源代码的一部分。可以查看:https://github.com/wycats/handlebars.js/blob/master/src/handlebars.l
1 个回答
这个问题比较复杂,实际上它包含了两个问题。
Jison(这是手柄解析器使用的语言,不是bison)有一些其他词法分析器没有的特性,特别是PLY就没有。这使得将你展示的Jison词法代码转换为PLY变得困难。不过,这并不是你关注的问题。我们可以回答你的基本问题,如何在PLY中让多个正则表达式返回一个单一的标记,但这并不能解决你选择的示例代码的问题!
首先,我们来解决你问的问题。在PLY中,使用@TOKEN
装饰器可以实现多个正则表达式返回一个标记,具体可以参考PLY手册(第4.11节)。
例如,我们可以这样做:
comment1 = r'[^\x00]*?/("{{")'
comment2 = r'[^\x00]+'
comment = r'(' + comment1 + r'|' + comment2 + r')'
@TOKEN(comment)
def t_COMMENT(t)
....
然而,这对于你从Jison得到的规则并不适用,因为它们使用了Jison的新特性,叫做起始条件(可以查看Jison手册)。在这里,this.begin
这个短语用来引入一个状态名称,然后可以在其他模式中使用。这就是<mu>
、<emu>
和<com>
的来源。PLY中没有这样的特性。
为了匹配这些词素,实际上需要回到手柄/胡子语言的语法,创建新的正则表达式。我觉得在这里完全为你重新实现整个手柄语言可能有点过于复杂。
不过,我已经为你找到了一个解决方案的步骤,适合任何走这条路的人。