需要 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 ...
我的 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 ...