【已解决】Antlr语法编译出错:Cannot generate the grammar because, duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set

【问题】

之前已经写好的一个antlr的.g语法文件,当时在antlrworks中编译都正常的。

现在重新去编译,结果倒出错了:

cannot generate the grammar because duplicate token type when collapsing subrule into set

对应的log:

[13:08:51] error(204): xxx.g:427:29: duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set
[13:08:54] error(204): xxx.g:427:29: duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set
[13:08:54] warning(200): xxx.g:427:47:
Decision can match input such as "COMMA..’unsigned’" using multiple alternatives: 1, 2

As a result, alternative(s) 2 were disabled for that input
[13:11:02] error(204): HartEddl.g:427:29: duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set

 

【解决过程】

1.看起来,是新添加的token,即那个

COMPOSITE_OPERATOR

惹的祸。

然后去看看代码是:

OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;

COMPOSITE_OPERATOR
	:	'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '&=' | '^=' | '|=';

//fragment
direct_value 	:	(DECIMAL_VALUE | HEX_VALUE);

对应的,看起来COMPOSITE_OPERATOR的语法图,也的确有问题:

this token syntax diagram seem is not ok

其中,<<=和>>=被分解成单个字符了。

而不是我们所想要的,成为一个整体。

2.所以,去改为:

COMMA : ',' ;

COMPOSITE_OPERATOR
	:	'<<=' | '>>=' |
		'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';

OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;


//fragment
direct_value 	:	(DECIMAL_VALUE | HEX_VALUE);

然后结果是:

第一次编译:

Generate->Generate Code

是正常的:

fist compile is ok

但是再次去编译:

Generate->Generate Code

结果就出错了:

then recompile is not ok

所以,感觉还是很诡异。

3.还是很奇怪的是:

当手动重新:

删除掉output文件夹;

重新打开Antlrworks

重新编译

结果就是可以的。

如果再次编译,或者是只是删除output文件夹,但不关闭antlrworks,结果重新编译,还是会存在同样的错误。

貌似antlrworks本身对于配置方面,或者编译方面的东西,是有全局的系统的缓存或配置的。

4.然后在代码中,去除掉COMPOSITE_OPERATOR,然后就是正常的了:

无论怎么重复编译,也都不会出错的。

5.后来的后来,是把原先的:

......


COMMA : ',' ;


COMPOSITE_OPERATOR
	:	'<<=' | '>>=' |
		'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';


OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;

......

any_char:	((~('{' | '}')) | COMPOSITE_OPERATOR)+;

......

改为:

......


COMMA : ',' ;


COMPOSITE_OPERATOR
	:	'<<=' | '>>=' |
		'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';


OPERATOR : '!' | '#' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ;

......

//any_char:	((~('{' | '}')) | COMPOSITE_OPERATOR)+;
any_char:	(~('{' | '}') | COMPOSITE_OPERATOR)+;

......

就可以了。

 

6.所以,看来还是自己的语法写的不对。

但是,至于为何:

any_char: ((~('{' | '}')) | COMPOSITE_OPERATOR)+; 

会导致:

duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set

的错误,而:

any_char:	(~('{' | '}') | COMPOSITE_OPERATOR)+;

不会导致错误。

至今,还是没有完全搞懂。

7.后来,经过多次再次测试,发现不是上述原因,而是:

还是会,无故的,导致:

duplicate token type COMPOSITE_OPERATOR when collapsing subrule into set

的错误。

8.现在基本判断出,antlrworks有个全局的缓存。

因为此处,现在是,即使改动antlrworks的文件,然后去重新Generate Code,结果antlrworks都不会重新去编译代码,而是直接报错。

9.后来找到了,antlrworks2缓存(数据)

found antlrworks2 data

先不管和此处的antlrworks是否有关,先删除试试。

结果错误依旧。

10.参考:

duplicate token type…

[antlr-interest] Bug? duplicate token type … when collapsing subrule into set

貌似说这个antlr本身的bug。

11。参考:

Parsing a log file with ANTLR

提到了,意思是,本身你前面的语法,所表示的内容,已经包含了后面的了,

所以,去看了看自己的语法:

any_char:	((~('{' | '}')) | COMPOSITE_OPERATOR)+;

好像也是这个问题:

本身

~('{' | '}')

其实就已经包含了:

COMPOSITE_OPERATOR

了。

所以去改为:

//any_char:	(~('{' | '}'))+;
//any_char:	((~('{' | '}')) | COMPOSITE_OPERATOR)+;
//any_char:	(~('{' | '}') | COMPOSITE_OPERATOR)+;
any_char:	(COMPOSITE_OPERATOR | (~('{' | '}')) )+;

然后就可以了。

即:

无论如何编译:

是直接编译,还是多次再次编译

还是debug后再去编译

还是编译后再去debug

等等,都是可以正常执行了。不会报错了。

所以,至此,终于解决了这个问题了。

 

【总结】

当antlr编译出现:

duplicate token type xxx when collapsing subrule into set

的错误时,则去找到出错的位置。

去查看对应的语法代码,是不是出现了,类似于:

some_rule: TOKEN_A | TOKEN_B;

的语法,并且是TOKEN_A本身耳朵含义,本身所包含的内容,就已经把TOKEN_B中的内容包含在内了。

 

两个例子:

1.Parsing a log file with ANTLR

错误的写法:

fragment
SPECIAL : ( ~'\n' | '\'' | '.' | '(' | ')' | '-');

错误原因:

~'\n'

本身就已经包含了

'\'' | '.' | '(' | ')' | '-'

正确的写法:

fragment
SPECIAL : ~('\n' | '\'' | '.' | '(' | ')' | '-');

2.我这里的:

错误的写法:

COMPOSITE_OPERATOR
	:	'<<=' | '>>=' |
		'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';

any_char:	((~('{' | '}')) | COMPOSITE_OPERATOR)+;

错误原因:

~(‘{‘ | ‘}’)

本身就已经包含了:

COMPOSITE_OPERATOR

的内容了。

正确的写法:

COMPOSITE_OPERATOR
	:	'<<=' | '>>=' |
		'==' | '!=' |
		'<=' | '>=' |
		'&&' | '||' |
		'++' | '--' |
		'<<' | '>>' |
		'+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=';

any_char:	(COMPOSITE_OPERATOR | (~('{' | '}')) )+;

至此,大功告成。



发表评论

电子邮件地址不会被公开。 必填项已用*标注

无觅相关文章插件,快速提升流量