【问题标题】:ANTLR lexer rule consumes characters even if not matched?即使不匹配,ANTLR 词法分析器规则也会消耗字符?
【发布时间】:2012-04-25 13:14:20
【问题描述】:

我有一个 antlr 词法分析器规则的奇怪副作用,我创建了一个(几乎)最小的工作示例来演示它。 在这个例子中,我想匹配字符串 [0..1] 例如。但是当我调试语法时,到达解析器的令牌流只包含[..1]。第一个整数,无论​​它包含多少个数字,总是被消耗掉,我不知道这是怎么发生的。如果我删除 FLOAT 规则,一切都很好,所以我猜错误出在该规则的某个地方。但由于它根本不应该匹配 [0..1] 中的任何内容,我很困惑。

如果我有任何可能出错的地方,我会很高兴。这是我的例子:

grammar min;
options{
language = Java;
output = AST;
ASTLabelType=CommonTree;
backtrack = true;
}
tokens {
  DECLARATION;
}

declaration : LBRACEVAR a=INTEGER DDOTS b=INTEGER RBRACEVAR -> ^(DECLARATION $a $b);

EXP : 'e' | 'E';
LBRACEVAR: '[';
RBRACEVAR: ']';
DOT: '.';
DDOTS: '..';

FLOAT
    : INTEGER DOT POS_INTEGER
    | INTEGER DOT POS_INTEGER EXP INTEGER
    | INTEGER EXP INTEGER
    ;

INTEGER : POS_INTEGER | NEG_INTEGER;
fragment NEG_INTEGER : ('-') POS_INTEGER;
fragment POS_INTEGER : NUMBER+;
fragment NUMBER: ('0'..'9');

【问题讨论】:

    标签: antlr antlr3 antlrworks


    【解决方案1】:

    '0' 被词法分析器丢弃,并产生以下错误:

    line 1:3 no viable alternative at character '.'
    line 1:2 extraneous input '..' expecting INTEGER
    

    这是因为当词法分析器遇到'0.' 时,它会尝试创建一个FLOAT 标记,但不能。并且由于没有其他规则可用于匹配'0.',它会产生错误,丢弃'0' 并创建DOT 令牌。

    这就是 ANTLR 词法分析器的工作原理:它不会回溯以匹配 INTEGER 后跟 DDOTS(请注意,backtrack=true 仅适用于解析器规则!)。

    FLOAT 规则内,您必须确保当前面出现双 '.' 时,您会生成一个 INTEGER 令牌。您可以通过添加句法谓词(('..')=> 部分)来做到这一点,并且仅当单个 '.' 后跟一个数字(('.' DIGIT)=> 部分)时才生成 FLOAT 标记。请看以下演示:

    declaration
     : LBRACEVAR INTEGER DDOTS INTEGER RBRACEVAR
     ;
    
    LBRACEVAR : '[';
    RBRACEVAR : ']';
    DOT       : '.';
    DDOTS     : '..';
    
    INTEGER
     : DIGIT+
     ;
    
    FLOAT
     : DIGIT+ ( ('.' DIGIT)=> '.' DIGIT+ EXP? 
              | ('..')=>      {$type=INTEGER;} // change the token here
              |               EXP
              )
     ;
    
    fragment EXP   : ('e' | 'E') DIGIT+;
    fragment DIGIT : ('0'..'9');
    

    【讨论】:

    • 现在这是一个(至少对我而言)意想不到的行为。感谢您提供全面的示例,我现在已经全部启动并运行了:-)
    • @Lichtblitz,不客气,是的,标记 ..(与 INT 和 FLOAT 令牌结合使用)很棘手! :)
    猜你喜欢
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    相关资源
    最近更新 更多