介绍
在文档来看,ANTLR 2配合使用,有一些所谓predicated lexing,结合实例像这样的(由帕斯卡启发):句法断言规则
RANGE_OR_INT
: (INT "..") => INT { $setType(INT); }
| (INT '.') => REAL { $setType(REAL); }
| INT { $setType(INT); }
;
我看到的样子它在本规则开始时基本上是一个积极的预见性断言:如果前瞻性匹配INT ".."
那么第一个规则将应用(并匹配该输入的INT
部分),依此类推。
我还没有在ANTLR 4中找到过这样的东西。该2 to 3 migration guide似乎并没有提到这一点,而3 to 4 changes document状态:
ANTLR 3和4之间的最大区别在于,ANTLR 4需要你给它,除非语法有间接左递归语法的任何。这意味着我们不需要语法谓词或回溯,因此ANTLR 4不支持该语法;你会得到一个使用它的警告。
这是与错误信息,我得到行,如果我离开这个基本的是:
(...)=> syntactic predicates are not supported in ANTLR 4
虽然我能理解一个更智能解析器实施将如何解决这些模糊之处,我失败看看这将如何工作词法分析器。
再现例如
可以肯定,我们尝试了这一点:
grammar Demo;
prog: atom (',' atom)* ;
atom: INT { System.out.println("INT: " + $INT.getText()); }
| REAL { System.out.println("REAL: " + $REAL.getText()); }
| a=INT RANGE b=INT { System.out.println("RANGE: " +
$a.getText() + " .. " + $b.getText()); }
;
WS : (' ' | '\t' | '\n' | '\r')+ -> skip ;
INT : ('0'..'9')+ ;
REAL: INT '.' INT? | '.' INT ;
RANGE: '..' ;
保存这Demo.g
,然后编译并运行:
$ wget -nc http://www.antlr.org/download/antlr-4.5.2-complete.jar
$ java -jar antlr-4.5.2-complete.jar Demo.g
$ javac -cp antlr-4.5.2-complete.jar Demo*.java
$ java -cp .:antlr-4.5.2-complete.jar org.antlr.v4.gui.TestRig \
Demo prog <<< '1,2.,3.4,5 ..6,7..8'
INT: 1
REAL: 2.
REAL: 3.4
RANGE: 5 .. 6
REAL: 7.
line 1:17 extraneous input '.8' expecting {<EOF>, ','}
这样看来我是正确的:虽然删除语法预定可能适用于解析器,但词法分析器不会突然猜出正确的标记类型。
核心问题
那么一个会如何转换这个具体的例子来ANTLR 4?有没有办法表达先行条件?或者也许有一个像INT '..'
这样的单个规则发出两个不同的标记的方法?
参考和可能的解决方案
望着ANTLR 4 Pascal grammar,我注意到,它不允许实数在.
没有结束之后的数字,所以学习的解决方案从那里不会出现是一个选择。我看过Semantic predicates in ANTLR4?和syntactic predicates - Upgrading from Antlr 3 to Antlr 4。在解析器规则中都讨论句法谓词。后者也有词法规则的例子,但前瞻与后面的规则是一致的,这意味着规则可以被移除而没有不利影响。在我上面的例子中,情况并非如此。
答案check previous/left token in lexer提词法分析器的emit
方法,带有注释的ANTLR 3维基引用How can I emit more than a single token per lexer rule? FAQ页面,所以我想这是一种方法。如果没有人打我的话,我会把它变成一个答案,如果我能在我的例子中得到它的工作。
对ANTLR4 negative lookahead in lexer的回答利用_input.LA(int)
方法来检查前瞻。 ANTLR 4 lexical analysis faq提到_input.LA
没有进入细节。这也适用于上面的例子,但对于不止一个字符的前瞻性考虑的场景来说很难。