ANTLR:Lexer 规则捕捉应该由解析器规则处理的内容

ANTLR: Lexer rule catching what is supposed to be handled by parser rule

在我的语法中有这些词法分析器规则:

DECIMAL_NUMBER: DIGITS? DOT_SYMBOL DIGITS;

// Identifiers might start with a digit, even though it is discouraged.
IDENTIFIER: LETTER_WHEN_UNQUOTED+;

fragment LETTER_WHEN_UNQUOTED:
    '0'..'9'
    | 'A'..'Z' // Only upper case, as we use a case insensitive parser (insensitive only for ASCII).
    | '$'
    | '_'
    | '\u0080'..'\uffff'
;

WHITESPACE: ( ' ' | '\t' | '\f' | '\r'| '\n') { $channel = HIDDEN; };

和这个解析器规则:

qualified_identifier: IDENTIFIER '.' IDENTIFIER;

除一种特殊情况外,这很好用,例如:

... a.0b

这里的问题是 .0 被 DECIMAL_NUMBER 规则捕获,但如果任何数字后面直接有非数字字符,我需要忽略它。如何做到这一点?

我正在考虑一个验证谓词,但如果 DECIMAL_NUMBER 规则不匹配,那将完全破坏解析。我的另一个想法是添加一个动作来检查到目前为止匹配的字符之后的任何字符,然后手动生成标记,这看起来非常难看。

当我的操作代码确定这不是十进制数时,是否可以在输入流中标记点后的位置并return到它?

如果没记错的话,词法分析器是贪婪的(即寻找将在输入流中的任何给定点匹配的最长标记。在平局中,顺序很重要。我很确定你唯一的解决方案是虚线标识符是一个杠杆规则,然后分解令牌 post-parse(在我的语法中,这就是我处理 ID 的方式)

看看您指定的内容,因为 IDENTIFIER 可以以数字开头(并且只需要是一个或多个字符),那么我相信您的词法分析器有歧义(1.2 是点分标识符还是DECIMAL_NUMBER)。您可能需要中断使 IDENTIFIER 令牌指定两个替代方案(一个以一个或多个数字开头,但至少需要一个非数字字符,另一个允许一个或多个非数字字符。 (也许你已经在真正的语法中处理过这个问题,这只是针对问题进行了简化)。

必须扩展 DECIMAL_NUMBER 规则以仅在我们有纯十进制数时匹配:

DECIMAL_NUMBER:
    DIGITS DOT_SYMBOL DIGITS
    | DOT_SYMBOL {if (!isAllDigits(ctx)) {FAILEDFLAG = ANTLR3_TRUE; return; }} DIGITS
;

我必须使用相同的代码,因为如果反向跟踪处于活动状态,语义谓词将隐式使用它。然而,仅仅有一个谓词并不能完成这项工作,因为在这种情况下没有设置所需的反向跟踪标志。

检查输入的函数是这样的:

  ANTLR3_BOOLEAN isAllDigits(pMySQLLexer ctx)
  {
    int i = 1;
    while (1)
    {
      int input = LA(i++);
      if (input == EOF || input == ' ' || input == '\t' || input == '\n' || input == '\r' || input == '\f')
        return ANTLR3_TRUE;

      // Need to check if any of the valid identifier chars comes here (which would make the entire string to an identifier).
      // For the used values look up the IDENTIFIER lexer rule.
      if ((input >= 'A' && input <= 'Z') || input == '$' || input == '_' || (input >= 0x80 && input <= 0xffff))
        return ANTLR3_FALSE;

      // Everything else but digits is considered valid input for a new token.
      if (input < '0' && input > '9')
        return ANTLR3_TRUE;
    }
  }