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

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

ANTLR crifan 13198浏览 0评论

【问题】

之前折腾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

    { 
        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.包括,以为是分号引起的,所以相关代码改为:

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’

发表我的评论
取消评论

表情

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.192 seconds, using 22.17MB memory