【问题标题】:Lexer rule conflict resolution needed需要 Lexer 规则冲突解决方案
【发布时间】:2015-02-24 15:29:59
【问题描述】:

我的 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 等非常特殊的情况外,这几乎可以正常工作,它应该被解析为两个用点连接的标识符。发生的情况是 .1 匹配为浮点数,即使它后面跟着下划线和字母。

很清楚它的来源:LETTER_WHEN_UNQUOTED 包含数字,因此“1”既可以是整数,也可以是标识符。但规则顺序应注意将其解析为整数,正如预期的那样(通常会这样做)。

但是,我很困惑t1.1_d 输入会导致浮动规则生效,并希望有一些指针可以解决这个问题。只要我在点之后添加一个空格就可以了,但这显然不是一个真正的解决方案。

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

【问题讨论】:

  • 您能否包含完整的语法(即包含示例中引用的所有标记/片段)?此外,greedy 默认为 true,因此不需要指定它。
  • 您可能会考虑重新设计:目前 1234 既是整数又是标识符。我不是说它不起作用,但它让我头疼。

标签: antlr3


【解决方案1】:

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

FLOAT 之前移动IDENTIFIER 没有帮助,因为'.'不是有效的IDENTIFIER 符号,因此当它以. 开头时,根本无法匹配输入。

请注意,Java 和 co.不要让标识符以数字开头,可能是为了避免这类问题。

一种可能的解决方案是将FLOAT 规则更改为在点之前需要数字:FLOAT: DIGITS '.' DIGITS ...

【讨论】:

  • 好的,谢谢。我也是这么想的。我想通过允许 id 以数字开头来定义语言只是一种糟糕的方式。
猜你喜欢
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
相关资源
最近更新 更多