最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】antlr调试时,antlr的语法是对的,但是却无法完全识别输入的测试数据,仅识别第一行

ANTLR crifan 3906浏览 0评论

【问题】

对于antlr的如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
grammar DDParserDemo;
 
options {
    output = AST;
    ASTLabelType = CommonTree; // type of $stat.tree ref etc...
}
 
ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;
 
FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;
 
COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;
 
WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {skip();}
    ;
 
STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;
 
CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;
 
fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
 
fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
 
fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;
 
fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;
 
fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;
 
fragment
DIGIT
    :   '0'..'9';
 
NEWLINE :   '\r'? '\n' ;
 
/*
DECIMAL_VALUE
    :   '1'..'9' DIGIT*;
*/
 
DECIMAL_VALUE
    :   DIGIT*;
 
HEX_VALUE
    :   '0x' HEX_DIGIT+;
/* 
startParse  :   (identification)+;
*/
startParse  :   (identification)+;
 
identification  :   definiton WS* ','? WS*   -> definiton
        ;
     
definiton   :   (ID)^ ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE)
        ;

然后去调试如下的输入:

1
2
3
4
MANUFACTURER      0x1E6D11,
DEVICE_TYPE       0x00FF,
DEVICE_REVISION   5,
DD_REVISION       1

结果,始终只能识别第一行,余下的三行,都无法识别:

can only recognize the first line

【解决过程】

1.期间,经历了多次修改代码。

最后无意间,发现了导致此现象的直接的原因:

(1)如果把上述的:

1
NEWLINE :   '\r'? '\n' ;

加上,则就会出现上述的现象,只能识别第一行,无法识别其余的三行;

(2)而如果把该行去掉(或注释掉):

1
//NEWLINE :   '\r'? '\n' ;

结果就可以正常识别输入的内容:

remove that special newline then can recognize all input

 

2. 貌似,还是很诡异,因为,至今看来,此行:

1
NEWLINE :   '\r'? '\n' ;

对于上述的antlr的语法,也只是一个多余的一行,不起效果的一行,但是结果其有或无,却影响到了,整个语法能否正常工作。

其根本原因,暂未搞懂,待以后再去弄清楚。

 

3.对此,猜测,难道是,如果有对于的定义,就会导致无法正常工作?

那么就再去随便加个别的,多余的定义,看看是否会导致同样的错误,同样会导致语法无法识别所有的输入的内容。

加了个:

1
2
FAKE_TOKEN
    :   '1' '2' '3';

看看测试效果。

结果证实,其是不影响的,语法是可以正常工作,可以识别所有的输入的内容的:

add fake token also work

4.难道,此处antlr或antlrworks内置有个变量叫做NEWLINE

然后此处定义的NEWLINE把内置的替换了,导致,此处\r\n变成了

所以,先确定当前antlr文件的回车换行是什么:

all is cr lf for antlr g file

可以看到,antlr的语法文件,其中都是cr lf。

然后对于要测试的数据,对应的也都是cr lf:

for test file also cr lf

对应的,debug时候的设置,设置的line ending也是CRLF:

line ending set to cr lf

 

而对于NEWLINE是否为内置的变量,无意间,在antlr官网找到了示例代码:

1
2
3
4
5
6
7
8
grammar Expr;      
prog:   (expr NEWLINE)* ;
expr:   expr ('*'|'/') expr
      | expr ('+'|'-') expr
|   INT
|   '(' expr ')'
;
        

其是针对antlr v4的语法。

期间可以看到,貌似NEWLINE和INT,都是没有定义,就直接使用的。

所以推测出来,antlr内置本身就是支持INT,NEWLINE等定义的。

但是还是要去找到官网真正的确定的解释才可以。

但是暂时没有找到。

5.但是,可以先去,把此处的NEWLINE改为:

1
2
//NEWLINE :   '\r'? '\n' ;
NEWLINE :   '\r' '\n' ;

看看调试结果如何。

同样是无法识别其余各行,只能识别第一行。

6.猜想,不会是版本的问题吧?

所以,把当前的antlrworks-1.5rc2.jar,换成别的版本的。

先换成antlrworks-1.2.2.jar试试,折腾过程参见:

【已解决】用antlrworks-1.2.2.jar编译代码出错:error: cannot find symbol,g.NEWLINE();,symbol: method NEWLINE()

 

7.上述折腾期间,发现需要给NEWLINE加fragment,就是避免在1.2.2中出错,所以猜测,在最新的1.5rc2中,如果也是加了fragment的NEWLINE,估计就可以正常调试,识别所有输入了。

所以去试试。

最终,是可以,在保留NEWLINE的情况下,可以识别所有的输入了:

recognize all line with retain NEWLINE

 

注:其中,如果在多个antlrworks之间切换,比如

antlrworks-1.2.2.jar

antlrworks-1.5rc2.jar

那么,在切换的时候,最好手动删除,当然项目下面所生成的output目录(其下包含了所生成的各种代码和测试文件)

以避免影响到调试。(否则调试的时候,可能会出现一些异常的情况,可能是由于不同版本所生成的文件,有所不同,被混淆了而导致的错误)

 

【总结】

1.随便加个,多余的定义,是不会影响到语法是否正常工作的;

2.单独添加:

1
NEWLINE :   '\r'? '\n' ;

会影响到此处的语法的正常工作,会导致,只能识别第一行,无法识别其余各行。

解决办法是,将此(无法再被细分的)定义,加上对应的fragment,变成:

1
fragment NEWLINE :   '\r'? '\n' ;

就可以正常编译和调试整个语法了,而不会出现上述的NEWLINE影响到整个语法的执行了。

注:其中关于fragment,详见:

【整理】antlr语法中的fragment

转载请注明:在路上 » 【已解决】antlr调试时,antlr的语法是对的,但是却无法完全识别输入的测试数据,仅识别第一行

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.200 seconds, using 22.19MB memory