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

时间:2015-11-13 10:36:22

标签: parsing antlr antlr3

在我的语法中,我有这些词法规则:

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规则与它不匹配,则会彻底破坏解析。我的另一个想法是添加一个动作检查,跟踪到目前为止匹配的任何字符,然后手动生成令牌,这看起来非常难看。

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

2 个答案:

答案 0 :(得分:1)

如果我们有一个纯十进制数字,则必须将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;
    }
  }

答案 1 :(得分:0)

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

看看你指定的是什么,因为IDENTIFIER可以从一个数字开始(并且只需要一个或多个字符),那么我相信你有一个词法分析模糊(1.2是一个点缀的IDENTIFIER或者十进制数)。您可能需要打破使IDENTIFIER令牌指定两个备选(一个以一个或多个数字开头,但要求至少包含非数字字符,另一个允许一个或多个非数字)字符。 (也许你已经在真正的语法中处理了这个问题,这只是针对这个问题进行了简化)。