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