ANTLR词法分析中还可以加入greedy设置项,当greedy=true时当前规则会尽可能的匹配可以匹配的输入。ANTLR中默认情况greedy为true,所以COMMENT: '/*' . * '*/' {$channel=HIDDEN;} ;规则中符号“.”可以匹配“*/”字符,也就是说当遇到“*/”字符时它是匹配“.”还是匹配’*/’出现了二义的情况,前面的例子中已经显示出在这种情况下分析器是可以正确分析的,但加入greedy=false后可以消除这种二义性,就是说greedy=false时分析器遇到“*/”字符时会很确定的做为注释结束符号来匹配,这样的话就消除了二义性。
COMMENT : '/*' (options {greedy=false;} : . ) * '*/' {$channel=HIDDEN;} ;
options{greedy=false;} : 是一种局部设置的写法,其格式为:( options {«option-assignmen ts»} :«subrule-alternatives» )。关键字options后面用“{}”将设置项括起来,使用“:”符号表示对后面部分进行设置,这种设置的方法必须在子规则中设置它只能在子规则中有效。如:'/*' options {greedy=false;}: . * '*/' 这样的定义是不无法的。
下面给出一个更加明显的例子。
grammar TestGreedy;
options {
language=CSharp;
output=AST;
}
c : A B;
A : 'a' 'b' ?;
B : 'b';
此例子中c规则有A和B两个词法符号,其中A匹配的是“a”或“ab”字符,B匹配的是“b”字符。这时会出现一个问题就是当输入为“ab”时这个“b”是规则A的b还是规则B的b,这属于二义性问题。此示例在实际运行时如果输入为“abb”时可以正确生成有两个子节点的语法树。
如果输入为“ab”会出现MismatchedTokenException异常,因为现在分析器的greedy属性为true。这时分析器会尽可能的匹配输入的字符“ab”被规则A匹配,这时规则B就没有了可匹配的字符,所以出现了MismatchedTokenException异常。
如果我们将规则A中可选的’b’定义为greedy=false;代码如下。
c : A B;
A : 'a' (options {greedy=false;} : 'b')?;
B : 'b';
当输入“ab”和“abb”时生成的语法树同样为:
规则A中的’b’由于是可选项并且其后规则B中也需要匹配’b’字符所以在Greedy属性为false时规则A不去匹配字符’b’。这样输入的字符串中第一个’b’字符与规则B匹配,第二个’b’字符无处匹配。