乐者为王

Do one thing, and do it well.

ANTLR 4权威参考读书笔记(7)

ANTLR 4权威参考读书笔记(6)中的这些动作仅仅是提取和打印被语法分析器匹配的值,它们并没有改变语法分析器本身。

实际上,动作还可以影响语法分析器如何识别输入短语。这类特殊的动作被称为语义谓词。下面我们会用一个简单的例子来展示语义谓词的强大能力:动态地打开和关闭语法的某个部分。

使用语义谓词改变语法分析

有一个读入整数序列的语法,它的玄机是由输入的部分指定有多少个整数组合在一起,所以我们必须等到运行时才能知道有多少个整数被匹配。这里是示例输入文件idata.txt的内容:

1
2 9 10 3 1 2 3

第一个数字表示匹配后续两个数字9和10;紧跟着10的数字3表示匹配接下来的三个数字。我们的目的是设计一个语法IData.g,把9和10组合在一起,把1、2和3组合在一起。在语法上执行下面的命令后显示的语法分析树能够清楚地标识出整数的分组,就像下图显示的那样:

1
2
3
antlr -no-listener IData.g
compile *.java
grun IData file -gui idata.txt

idata-parse-tree

要达成这个目标,以下语法中的关键是一个被称为语义谓词的布尔值操作:{$i <= $n}?。当谓词计算结果为true时,语法分析器匹配整数直到超过规则参数n要求的数量;当计算结果为false时,谓词让相关的选项从生成的语法分析器中“消失”。 在这个案例中,值为false的谓词让(...)*循环从规则里终止并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
grammar IData;

file : group+ ;

group: INT sequence[$INT.int] ;

sequence[int n]
locals [int i=1]
     : ( {$i <= $n}? INT {$i++;} )*    // match n integers
     ;

INT  : [0-9]+ ;  // match integers
WS   : [ \t\n\r]+ -> skip ;    // toss out all whitespace

被语法分析器使用的规则sequence的内部语法表示看起来就像下图这样:

idata-rule-sequence

虚线表明谓词可以剪断那条路径,只给语法分析器留下一个选择:退出的路径。

虽然大部分时间我们不需要这样的微管理,但它至少让我们知道我们有这样的武器可以处理病理分析问题。

Comments