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

【基本解决】antlr v3中包含{skip();}的语法,调试解析时出错:org.antlr.runtime.EarlyExitException

ANTLR crifan 3708浏览 0评论

【问题】

antlr v3,在antlrworks中,用如下语法:

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
grammar DDParserDemo;
 
options {
    output = AST;
    ASTLabelType = CommonTree; // type of $stat.tree ref etc...
}
 
//NEWLINE :   '\r'? '\n' ;
//NEWLINE :   '\r' '\n' ;
fragment
NEWLINE :   '\r'? '\n' ;
 
 
fragment
ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;
     
fragment
FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;
 
COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;
 
fragment
WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {skip();}
    ;
 
 
STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;
 
CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;
 
fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
 
 
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';
 
//FAKE_TOKEN    :   '1' '2' '3';
 
/*
DECIMAL_VALUE
    :   '1'..'9' DIGIT*;
*/
 
DECIMAL_VALUE
    :   DIGIT*;
 
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
 
 
HEX_VALUE
    :   '0x' HEX_DIGIT+;
 
 
/*
BLANKSPACE_TAB
//  :   (' ' | '\t'){skip();};
    :   (' ' | '\t')
    {$channel=HIDDEN;};
*/ 
//fragment BLANK    :   (' '|'\t')+ {skip();};
//BLANK :   (' '|'\t') {skip();};
BLANK   :   (' '|'\t') {skip();};
 
fragment
HEADER_FILENAME
    :   ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'_')*;
 
/*
//singleInclude :   '#include' ' '+ '"' ID '.h"' ;
//singleInclude :   '#include' ' '+ '"' ID+ '.h"' ;
//singleInclude :   '#include' ' '+ '"' HEADER_FILENAME '.h"';
//singleInclude :   '#include' ' ' '"' HEADER_FILENAME '.h"';
//singleInclude :   '#include "' HEADER_FILENAME '.h"';
//fragment singleInclude    :   '#include' (' ')+ '"' ID '.h"';
//singleInclude :   '#include' (' '|'\t')+ '""' ID '.h"';
//singleInclude :   '#include' (' '|'\t')+ '"std_defs.h"';
singleInclude   :   '#include' (' '|'\t')+  ID '.h';
 
include     :   singleInclude WS*   -> singleInclude;
*/
 
//startParse    :   include* identification+;
//startParse    :   include+ identification+;
//startParse    :   identification+;
startParse  :   manufacture deviceType deviceRevison ddRevision;
manufacture :   'MANUFACTURER'^     BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
deviceType  :   'DEVICE_TYPE'^      BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
deviceRevison   :   'DEVICE_REVISION'^  BLANK+ (DECIMAL_VALUE | HEX_VALUE)(','?)! WS*;
ddRevision  :   'DD_REVISION'^      BLANK+ (DECIMAL_VALUE | HEX_VALUE)(','?)! WS*;
     
//identification    :   definiton WS* (','?)! WS*   -> definiton;
     
//definiton :   (ID)^ ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE)
//definiton :   (ID)^ BLANKSPACE_TAB+ (DECIMAL_VALUE | HEX_VALUE)
//definiton :   ID ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE);

去调试解析:

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

结果出错:

use antlr grammar parse error org.antlr.runtime.EearlyExitException

【解决过程】

1.参考:

How to resolve this parsing ambiguitiy in Antlr3

看了其解释,只是明白了一点,那就是,

在语法中,的确存在,解析器,希望匹配的东西,但是实际上所匹配的内容中,缺少了后面的部分,所以导致解析器报错,说是EarlyExitException,即过早退出,(希望还有更多后续匹配的内容)

2.所以,就去自己的语法中,看看是否有,类似于上面这样的歧义的东西。

试试去,把skip去掉,即变为:

1
2
//BLANK :   (' '|'\t') {skip();};
BLANK   :   (' '|'\t');

看看效果。结果果然可以正常解析对应的值了:

after remove skip then can recognize the value

接下来,还是需要,好好搞懂,为何加上那个skip,而出现EarlyExitException。

3.改为加上感叹号,表示不捕获:

1
2
//manufacture   :   'MANUFACTURER'^     BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
manufacture :   'MANUFACTURER'^     (BLANK+)! (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;

结果还是和上面一样,还是可以捕获对应的那6个空格。

4.参考:

http://www.antlr3.org/api/Java/index-all.html

中的:

DEFAULT_CHANNEL – Static variable in interface org.antlr.runtime.Token

All tokens go to the parser (unless skip() is called in that rule) on a particular "channel".

以及,进一步的,参考:

SKIP_TOKEN

得知,加上skip()后,对应的,antlr就不为此内容,创建对应的token了。

所以,倒是可以去试试,把对应的内容,去改为hidden,而不是skip:

1
2
3
//BLANK :   (' '|'\t') {skip();};
//BLANK :   (' '|'\t');
BLANK   :   (' '|'\t') {$channel=HIDDEN;};

结果却又是变成EarlyExitException了:

set to channel hidden result is also earlyexitexception

觉得还是不能理解。

5.期间,又出现别的问题,详见:

【基本解决】antlr v3,用包含{$channel=HIDDEN;}语法,结果解析出错:MissingTokenException

 

【总结】

虽然,对于org.antlr.runtime.EarlyExitException和之后的MissingTokenException,都可以避免了。

但是还是无法实现所要的,可以skip或hidden空格的效果。

更多总结详见上面的:

【基本解决】antlr v3,用包含{$channel=HIDDEN;}语法,结果解析出错:MissingTokenException

转载请注明:在路上 » 【基本解决】antlr v3中包含{skip();}的语法,调试解析时出错:org.antlr.runtime.EarlyExitException

发表我的评论
取消评论

表情

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

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

  1. 根本就不需要在规则中出现BLANK+这样的东西吧
    过客10年前 (2015-10-25)回复
85 queries in 0.216 seconds, using 22.25MB memory