需要 Lexer 规则冲突解决

Lexer rule conflict resolution needed

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

INTEGER:                DIGITS;
FLOAT:                  DIGITS? DOT_SYMBOL DIGITS ('E' (MINUS_OPERATOR | PLUS_OPERATOR)? DIGITS)?;

HEXNUMBER:              '0X' HEXDIGIT+;
HEXSTRING:              'X' '\'' HEXDIGIT+ '\'';

BITNUMBER:              '0B' ('0' | '1')+;
BITSTRING:              'B' '\'' ('0' | '1')+ '\'';

NCHAR_TEXT:             'N' SINGLE_QUOTED_TEXT;

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'
;

qualified_identifier:
    IDENTIFIER ( options { greedy = true; }: DOT_SYMBOL IDENTIFIER)?
;

除了非常特殊的情况(例如输入 t1.1_d 应该被解析为用点连接的 2 个标识符)之外,这在大多数情况下都可以正常工作。发生的情况是 .1 匹配为浮点数,即使它后跟下划线和字母。

它的来源一目了然:LETTER_WHEN_UNQUOTED 包含数字,因此“1”既可以是整数,也可以是标识符。但是规则顺序应该注意将其解析为整数,如预期的那样(并且通常如此)。

但是,我对 t1.1_d 输入导致浮动规则生效感到困惑,希望能提供一些解决此问题的建议。只要我在点之后添加一个 space 就可以了,但这显然不是一个真正的解决方案。

当我将 IDENTIFIER 规则移到其他规则之前时,我遇到了新的麻烦,因为其他几个规则无法再匹配。在 IDENTIFIER 规则之后移动 FLOAT 规则也不能解决问题(但至少不会产生新问题)。在这种情况下,我们看到了实际问题:如果紧跟数字,则点始终符合 FLOAT 规则。我该怎么做才能让它与我的情况不匹配?

问题在于词法分析器独立于解析器运行。当面对输入字符串 t1.1_d 时,词法分析器将首先消耗一个 IDENTIFIER,留下 .1_d。您现在希望它匹配 DOT_SYMBOL,然后是 IDENTIFIER。但是,词法分析器将始终匹配最长的可能标记,从而导致 FLOAT 匹配 .1.

IDENTIFIER 移到 FLOAT 之前没有帮助,因为 '.'不是有效的 IDENTIFIER 符号,因此当它以 ..

开头时根本无法匹配输入

请注意 Java 和公司。不允许标识符以数字开头,可能是为了避免此类问题。

一个可能的解决方案是更改 FLOAT 规则以要求在点之前有数字:FLOAT: DIGITS '.' DIGITS ...