在ANTLR3中,我需要区分“注释”和“指令”(看起来像评论)

时间:2014-02-10 21:37:00

标签: antlr antlr3 lexer

我对ANTLR很新,我遇到了一个问题。

我有一个语法,我正在尝试编写一种语言,其中包括以相同注释标识符开头的单行注释和语言指令。例如:

--This is a comment.  What follows is a directive with a parameter
--directive:param

指令将始终采用该格式 - 两个短划线字符后跟命令,冒号和单个参数。

我想让词法分析器忽略实际的注释(将其发送到隐藏的通道),但是将指令标记化。我有以下词法规则:

DCOMMAND    : DATABASE;
fragment DATABASE   : D A T A B A S E;
fragment COMMENTSTART   : '--';
LINE_COMMENT    : COMMENTSTART ~(DCOMMAND|('\n'|'\r')*) {$channel=HIDDEN;};
fragment A  : ('a'|'A');
fragment B  : ('b'|'B');
fragment C  : ('c'|'C');
fragment D  : ('d'|'D');
....

现在只有一个指令:'数据库'。 DCOMMAND令牌最终可能代表几个关键字。问题是我的词法分析器总是将以“ - ”开头的任何东西推入隐藏的通道。如何使LINE_COMMENT标记与指令不匹配?或者我是否必须将评论处理移到解析器中?

1 个答案:

答案 0 :(得分:3)

AFAIK,没有一些手动代码就没有办法在你的词法分析器语法中处理这个问题(恕我直言,比向解析器推广评论更好!)。

你能做的是:

  • 匹配'--'
  • 在自定义方法中,手动向前看直到行尾(EOL)。当true是指令的一部分时,让此方法返回'--'
    • 如果匹配的内容直到EOL看起来是一个指令,请不要匹配字符并返回true
    • 如果您在EOL之前匹配的内容不是指令,请匹配字符并返回false
  • 如果您的自定义方法返回false,则必须是注释,您可以skip()

快速演示:

grammar T;

@lexer::members {

  private boolean directiveAhead() throws MismatchedTokenException {

    StringBuilder b = new StringBuilder();

    for(int ahead = 1; ; ahead++) {

      // Grab the next character from the input.
      int next = input.LA(ahead);

      // Check if we're at the EOL.
      if(next == -1 || next == '\r' || next == '\n') {
        break;
      }

      b.append((char)next);
    }

    if(b.toString().trim().matches("\\w+:\\w+")) {
      // Do NOT let the lexer consume all the characters, just return true!
      return true;
    }
    else {
      // Let the lexer consume all the characters!
      this.match(b.toString());
      return false;
    }
  }
}

parse
 : directive EOF
 ;

directive
 : DIRECTIVE_START IDENTIFIER COL IDENTIFIER 
 ;

IDENTIFIER
 : ('a'..'z' | 'A'..'Z')+
 ;

DIRECTIVE_START
 : '--' { if(!directiveAhead()) skip(); }
 ;

COL
 : ':'
 ;

SPACES
 : (' ' | '\t' | '\r' | '\n')+ {skip();}
 ;