【问题】
之前折腾antlr,已经遇到很多次的:
no viable alternative at input
了。
这次,又遇到类似的问题了。
用的.g语法代码是:
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 { more //menu } |
然后无法识别
__LBL__show
出错:
xxxdemo.ddl line 30:12 no viable alternative at input ‘__LBL__show’ |
【解决过程】
1.折腾了很多次。
2.包括,以为是分号引起的,所以相关代码改为:
SEMICOLON : ';'; COMPOSITE_OPERATOR : '<<=' | '>>=' | '==' | '!=' | '<=' | '>=' | '&&' | '||' | '++' | '--' | '<<' | '>>' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|='; //OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ; OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ; //common_label : 'LABEL' string_value ';'; common_label : 'LABEL' string_value SEMICOLON;
结果问题依旧。
3.最后发现,原来是DEFINE_IMPOTED_VALUE的问题,无法捕获到,原以为可以捕获的ID,即__LBL__show,而导致出错的。
详细解释就是:
对于:
//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,希望是被
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,即改为:
//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的本意了。
如果要改,应该改为这种:
// //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’