【问题】
之前折腾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’