我的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匹配为float,即使后跟下划线和字母。
很清楚它的来源:LETTER_WHEN_UNQUOTED包括数字,因此'1'既可以是整数,也可以是标识符。但规则顺序应该注意将其解析为整数,如同意图(并且通常是)。
但是,我很困惑t1.1_d
输入导致浮动规则启动,并会欣赏一些指针来解决这个问题。只要我在点后添加一个空格一切都很好,但这显然不是一个真正的解决方案。
当我将IDENTIFIER规则移到其他规则之前时,我遇到了新的麻烦,因为其他几个规则再也无法匹配了。在IDENTIFIER规则之后移动FLOAT规则也不能解决问题(但至少不会产生新问题)。在这种情况下,我们会看到实际问题:如果直接后跟数字,则点总是与FLOAT规则匹配。在我的情况下,我该怎么做才能使它不匹配?
答案 0 :(得分:0)
问题是词法分析器独立于解析器运行。当面对输入字符串t1.1_d
时,词法分析器将首先消耗IDENTIFIER
,离开.1_d
。您现在希望它与DOT_SYMBOL
匹配,然后是IDENTIFIER
。但是,词法分析器将始终匹配最长的令牌,从而导致FLOAT匹配.1
。
在IDENTIFIER
之前移动FLOAT
无效,因为'。'不是有效的IDENTIFIER
符号,因此当它以.
开头时,根本无法与输入匹配。
注意Java和co。不允许标识符以数字开头,可能是为了避免这些问题。
一种可能的解决方案是将FLOAT
规则更改为要求点前的数字:FLOAT: DIGITS '.' DIGITS ...