1

我正在编写一个 ANTLR 语法来解析日志文件,但遇到了一个问题。我简化了语法以重现问题,如下所示:

stmt1:
  '[ ' elapse ': ' stmt2
  ;

stmt2:
  '[xxx'
  ;

stmt3:
  ': [yyy'
  ;

elapse :
  FLOAT;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* 
    ;

当我使用以下字符串测试语法时:

[ 98.9: [xxx

我得到了错误:

E:\work\antlr\output\__Test___input.txt line 1:9 mismatched character 'x' expecting 'y'
E:\work\antlr\output\__Test___input.txt line 1:10 no viable alternative at character 'x'
E:\work\antlr\output\__Test___input.txt line 1:11 no viable alternative at character 'x'
E:\work\antlr\output\__Test___input.txt line 1:12 mismatched input '<EOF>' expecting ': '

但是如果我删除 ruel 'stmt3',同样的字符串会被接受。

我不确定发生了什么...

感谢您的任何建议!

莱昂


感谢巴特的帮助。我试图纠正语法。我认为,基线,我必须消除所有标记的歧义。我添加了 WS 令牌以简化规则。

stmt1:
  '[' elapse ':' stmt2
  ;

stmt2:
  '[' 'xxx'
  ;

stmt3:
  ':' '[' 'yyy'
  ;

elapse :
  FLOAT;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* 
    ;

WS : (' ' |'\t' |'\n' |'\r' )+ {skip();} ;   
4

1 回答 1

4

ANTLR 严格区分词法分析器规则(令牌)和解析器规则。尽管您在解析器规则中定义了一些文字,但它们仍然是标记。这意味着以下语法(在实践中)与您的示例语法等效:

stmt1  : T1 elapse T2 stmt2 ;
stmt2  : T3 ;
stmt3  : T4 ;
elapse : FLOAT;

T1     : '[ ' ;
T2     : ': ' ;
T3     : '[xxx' ;
T4     : ': [yyy' ;
FLOAT  : ('0'..'9')+ '.' ('0'..'9')* ;

现在,当词法分析器尝试从输入构造标记时"[ 98.9: [xxx",它成功地创建标记T1FLOAT,但是当它看到 ": ["时,它尝试构造T4标记。但是当流中的下一个字符是 a"x"而不是 a"y"时,词法分析器会尝试构造另一个以 开头的标记": ["。但是由于没有这样的标记,词法分析器会发出错误:

[...] 不匹配的字符 'x' 期望 'y'

不,词法分析器不会回溯以“放弃”字符"["from": ["以匹配 token T2,也不会在 char-stream 中向前看以查看是否T4真的可以构造 token。ANTLR 的 LL(*) 仅适用于解析器规则,不适用于词法分析器规则!

于 2012-10-29T18:45:14.917 回答