乐者为王

Do one thing, and do it well.

使用ANTLR构建PowerScript语法分析器(2)

使用ANTLR构建PowerScript语法分析器(1)中写的词法规则存在几个小问题:

  1. 换行符和回车符同时存在于WS和EndOfLine两个词法规则中,属于重复定义;
  2. 输出单行注释时紧随其后会额外多输出一个空行;
  3. 单行注释是文件的最后一行时不能被词法分析器识别;
  4. /* comments /* nested comments */ */这种嵌套注释会被输出成:
1
2
bc>/* comments /* nested comments */
bc>/* comments /* nested comments */ */

下面我们将逐个修复它们。

解决第1个问题前先要问问自己,单行注释的词法规则中真的需要包含EndOfLine这个词法规则吗?真的需要吗?如果没有的话,当词法分析器识别到换行符或回车符时,就会去匹配词法规则WS。这样看来,EndOfLine这个词法规则在这里其实是不必要的,完全可以删除掉。

第2个问题因为词法规则EndOfLine已经被删除,所以也就不存在了。这儿仅仅分析下问题的原因。词法分析器分析单行注释时,EndOfLine会被当作单行注释的一部分予以识别。翻看生成的词法识别器代码,可以看到打印代码块出现在词法规则EndOfLine调用的后面。打印代码块中的getText()方法是从CharStream中获取文本的,如果在词法规则EndOfLine被调用后才执行,因为词法规则EndOfLine被调用时会将CharStream的当前索引向尾部移动,这时获得的文本就会包含EndOfLine,导致打印时额外输出一个空行。

第3个问题同样也由于第1个问题的修复而不存在了。它出现的原因是因为文件最后一行的结尾字符是EOF,无法匹配词法规则EndOfLine。

第4个问题则可以通过计数器来处理。先初始化一个计数器变量depthOfComments来标记块注释的深度,当遇到“/*”时就加1,遇到“*/”时则减1。输出时只要判断depthOfComments是否等于0就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@lexer::members {
    int depthOfComments = 0;
}

BLOCK_COMMENT
    : '/*' {depthOfComments++;}
      ( options {greedy=false;}
      : ('/' '*')=> BLOCK_COMMENT
      | '/' ~('*')
      | ~('/')
      )*
      '*/' {depthOfComments--;}
      {
          if (depthOfComments == 0) {
              System.out.println("bc>" + getText());
          }
      }
    ;

Comments