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

【已解决】antlr出错no viable alternative at input ‘__LBL__show’

ANTLR crifan 13467浏览 0评论

【问题】

之前折腾antlr,已经遇到很多次的:

no viable alternative at input

了。

这次,又遇到类似的问题了。

用的.g语法代码是:

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
131
132
133
134
135
136
137
138
139
140
grammar HartEddl;
 
options {
    output = AST;
    ASTLabelType = CommonTree; // type of $stat.tree ref etc...
}
 
fragment
LETTER  :   'a'..'z' | 'A'..'Z';
 
fragment
DIGIT   :   '0'..'9';
 
COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;
 
WS  :   ( ' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};
 
 
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
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;
 
STR_LAN :   '"|' LETTER LETTER '|"';
 
//fragment
STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;
 
//fragment
//ID  : ('a'..'z' | 'A'..'Z' |'_') (options {greedy=true;} :'a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
ID  :   ('a'..'z' | 'A'..'Z' |'_') ('a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
 
//fragment
DEFINE_IMPOTED_VALUE
        :   IMPORTED_VALUE | ID;
 
fragment
IMPORTED_VALUE  :   ('[' ID ']'); /* normal ID with [] */
 
 
fragment
HEX_DIGIT   : ('a'..'f'|'A'..'F' | DIGIT) ;
//fragment
HEX_VALUE   :   '0x' HEX_DIGIT+;
 
//fragment
DECIMAL_VALUE   :   DIGIT+;
 
 
//LEFT  : '(' | '[' | '{' ;
LEFT  : '(' | '[' ;
//RIGHT : ')' | ']' | '}' ;
RIGHT : ')' | ']';
COMMA : ',' ;
 
COMPOSITE_OPERATOR
    :   '<<=' | '>>=' |
        '==' | '!=' |
        '<=' | '>=' |
        '&&' | '||' |
        '++' | '--' |
        '<<' | '>>' |
        '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';
 
OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;
 
//fragment
direct_value    :   (DECIMAL_VALUE | HEX_VALUE);
 
string_value    :   (DEFINE_IMPOTED_VALUE | STRING | multi_lan_str); // support multi language string
//string_value  :   (ID | STRING | multi_lan_str); // support multi language string
 
//multiple language string
//eg: "Current loop"       "|sv|""St?mslinga"
//multi_lan_str :   STRING '"|' LETTER LETTER '|"' STRING;
//multi_lan_str :   STRING WS+ STRING STRING;
multi_lan_str   :   STRING WS* STR_LAN STRING;
 
 
expression_or_direct_value
        :   direct_value; //todo: add expression support
expression_or_string
        :   STRING;//todo:add string expression support
 
 
/*******************************************************************************
Main Entry Rule
*******************************************************************************/
startParse  :   (singleInclude | idInfos | variable | command | collection | menu | array | unit | method)+;
 
/*******************************************************************************
Common definitions
*******************************************************************************/
common_label    :   'LABEL' string_value ';';
......
 
/*******************************************************************************
7.18 MENU
10.1 Menus
*******************************************************************************/
menu    :   'MENU' menu_identifier '{' menu_body '}' ;
menu_identifier
    :   ID;
menu_body
    :   menu_attribute+;
menu_attribute
    :   menu_label | menu_items; //TODO: add help,...
menu_label
    :   common_label;
menu_items
    :   'ITEMS' '{' menu_items_body '}';
menu_items_body
    :   menu_item (',' menu_item)*;
menu_item
    :   ID menu_item_attributes?;
menu_item_attributes
    :   '(' menu_item_attribute (',' menu_item_attribute)* ')';
menu_item_attribute
    :   'DISPLAY_VALUE' | 'HIDDEN' | 'READ_ONLY' | 'NO_LABEL' | 'NO_UNIT' | 'REVIEW';
 
......

处理内容为:

MENU    show

{

    LABEL   __LBL__show;

    ITEMS

    { 
        set_value           (DISPLAY_VALUE, READ_ONLY),          
        position_value  (DISPLAY_VALUE, READ_ONLY),          
        show_method,                                                      //METHOD

        more    //menu

    }

}

然后无法识别

__LBL__show

出错:

xxxdemo.ddl line 30:12 no viable alternative at input ‘__LBL__show’

 

【解决过程】

1.折腾了很多次。

2.包括,以为是分号引起的,所以相关代码改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SEMICOLON
    :   ';';
 
COMPOSITE_OPERATOR
    :   '<<=' | '>>=' |
        '==' | '!=' |
        '<=' | '>=' |
        '&&' | '||' |
        '++' | '--' |
        '<<' | '>>' |
        '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';
 
//OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;
OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;
 
//common_label  :   'LABEL' string_value ';';
common_label    :   'LABEL' string_value SEMICOLON;

结果问题依旧。

3.最后发现,原来是DEFINE_IMPOTED_VALUE的问题,无法捕获到,原以为可以捕获的ID,即__LBL__show,而导致出错的。

详细解释就是:

对于:

1
2
3
4
5
6
7
8
9
10
//fragment
//ID  : ('a'..'z' | 'A'..'Z' |'_') (options {greedy=true;} :'a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
ID  :   ('a'..'z' | 'A'..'Z' |'_') ('a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
 
//fragment
DEFINE_IMPOTED_VALUE
        :   IMPORTED_VALUE | ID;
 
fragment
IMPORTED_VALUE  :   ('[' ID ']'); /* normal ID with [] */

的语法,我们的本意是:

对于普通的字符串,的确是可以通过ID,去捕获识别的。包括普通的set_value,show等等,也包括这里的__LBL__show。

然后对于其他,一些宏定义的字符串,即此处的LABEL后面的__LBL__show,希望是被

1
string_value    :   (DEFINE_IMPOTED_VALUE | STRING | multi_lan_str);

中的DEFINE_IMPOTED_VALUE所识别到,希望DEFINE_IMPOTED_VALUE可以匹配:

xxx

[xxx]

的两种内容。

但是实际上,此处的DEFINE_IMPOTED_VALUE,只匹配到了[xxx]的内容,而没有匹配xxx的内容。

因为xxx的内容,被DEFINE_IMPOTED_VALUE之前的ID所匹配到了,后面的DEFINE_IMPOTED_VALUE就无法再拿到对应的xxx的字符串了。

所以,此处,antlr执行到LABEL后面的__LBL__show,由于,__LBL__show已经被之前的ID所匹配到了,此处的DEFINE_IMPOTED_VALUE没有得到__LBL__show这个ID,所以报错了。

解决方法有几种:

1.把DEFINE_IMPOTED_VALUE,从此处的lexer的token改为parser的rule,即改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//fragment
//ID  : ('a'..'z' | 'A'..'Z' |'_') (options {greedy=true;} :'a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
ID  :   ('a'..'z' | 'A'..'Z' |'_') ('a'..'z' | 'A'..'Z'| '0'..'9' |'_')*;
 
//fragment
define_imported_value
        :   IMPORTED_VALUE | ID;
 
fragment
IMPORTED_VALUE  :   ('[' ID ']'); /* normal ID with [] */
 
......
 
string_value    :   (define_imported_value | STRING | multi_lan_str); // support multi language string
//string_value  :   (ID | STRING | multi_lan_str); // support multi language string
 
......
 
 
common_label    :   'LABEL' string_value ';';

即,可以,通过rule:define_imported_value 去匹配到,要么是ID的xxx,要么是IMPORTED_VALUE的[xxx]

同时,此处的IMPORTED_VALUE其实也是可以去掉fragment了。

 

2.去掉DEFINE_IMPOTED_VALUE,在别处调用到DEFINE_IMPOTED_VALUE的地方,直接用

ID | IMPORTED_VALUE

此种方式,也是可以的。

但是此处由于多处都用到DEFINE_IMPOTED_VALUE,所以如此修改的话,改动太大。

并且,也没有了原先的define 或者imported value的本意了。

如果要改,应该改为这种:

1
2
3
4
5
6
7
8
// //fragment
// DEFINE_IMPORTED_VALUE
        // :    IMPORTED_VALUE | ID;
 
//fragment
direct_value    :   (DECIMAL_VALUE | HEX_VALUE);
 
string_value    :   (IMPORTED_VALUE | ID | STRING | multi_lan_str); // support multi language string

 

本来用第一个方式的,后来由于考虑到尽量减少后续的ast解析代码,所以改为用第一种了。

 

【总结】

还是要真正熟悉antlr中的lexer的token,parser的rule的逻辑,才能写出完善的.g语法代码的。

转载请注明:在路上 » 【已解决】antlr出错no viable alternative at input ‘__LBL__show’

发表我的评论
取消评论

表情

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

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

网友最新评论 (3)

  1. 把lexer rule 写成parser rule就可以了~感谢。
    keroro52011年前 (2014-04-09)回复
  2. Hi,你好!对你关于ANTLR的博客表示很感兴趣! 我发现解析器规则(parser rule)中使用的token好像会和词法分析器(lexer)中定义的token冲突!不知道你是否知道如何解决呢? 有个简单的例子: grammar Test; r1: A; r2: 'a' 'c'; A: 'a' | 'b'; grun Test r1 -tree时,输入‘a'会出现和你此处一样的错误: line 1:0 mismatched input 'a' expecting A
    董理12年前 (2013-07-05)回复
87 queries in 0.571 seconds, using 22.24MB memory