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

【已解决】antlr调试解析出错:UnwantedTokenException(found=xxx)

ANTLR crifan 2876浏览 0评论

【问题】

在antlrworks 1.5rc2中,用antlr v3的语法,相关代码如下:

//fragment 
BLANKS_TABS	:	(' '|'\t')+;

manufacture	:	'MANUFACTURER'^ 	BLANKS_TABS (direct_value | define_value) (','?)! WS*;

single_import	:	'IMPORT' BLANKS_TABS manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

去解析内容:

IMPORT MANUFACTURER     __FF,

       DEVICE_TYPE      __STD_PARM,

       DEVICE_REVISION  SFT_STD_PARM_dev_rev,

       DD_REVISION      SFT_STD_PARM_dd_rev

结果出错:

UnwantedTokenException(found=xxx)

antlr error UnwantedTokenException found

 

【解决过程】

1.字面上看起来,像是,本来写代码,用BLANKS_TABS去匹配空格的,结果实际匹配到的内容却是MANUFACTURER,

但是,很奇怪的是,本来要测试的内容,在IMPORT和MANUFACTURER,就的确,存在一个空格的:

IMPORT MANUFACTURER     __FF,

所以,没道理啊。

2.后来通过:

single_import	:	'IMPORT' (' ' | '\t')+ manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

就的确是可以匹配到的:

use blank and tab can match

3。但是后来,无意间,把空格匹配的部分去掉,变成:

single_import	:	'IMPORT' manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;
//single_import	:	'IMPORT' (' ' | '\t')+ manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

结果,竟然是可以匹配到的,而且是无错的:

no space unexpectly match ok

所以,看起来,很是诡异啊。

即,本身要解析的内容,IMPORT和MANUFACTURER之前的确存在一个空格,

但是用语法解析时,没有写代码去匹配空格,结果竟然也是可以匹配正常的。

难道,antlr中,自动会忽略掉两个ID之间的空格?

4.去试试,把其他一些,看起来,暂时用不到的token,都注释掉,比如CHAR,NEWLINE,等等,结果效果依旧。

5.后来,觉得,估计是原先的这句:

WS  :   ( ' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};

所导致,自动匹配到白空格之类的,然后就自动hidden了,所以,应该就是上面的效果了。

所以,现在试试,把hidden属性去掉,变成:

//WS  :   ( ' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
WS  :   ( ' ' | '\t' | '\r' | '\n');

试试,结果竟然,从最开始的内容,都无法匹配了:

from start can not parse

还是很奇怪的,为何把WS的hidden去掉,竟然连comment里面的内容,都无法匹配了。

6.结果,只能把在WS的hidden加上,然后反正是可以正常解析了。

7.此处,看起来,像是:

此处,加了对应的空格去匹配本身就存在的空格,却导致了异常,出现UnwantedTokenException的错误,原因在于:

本身,之前已经写了规则:

WS  :   ( ' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};

去自动匹配单个空格,并且自动忽略掉,所以,后来再加上自己写的:

BLANKS_TABS	:	(' '|'\t')+;

single_import	:	'IMPORT' BLANKS_TABS manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

去匹配:

IMPORT MANUFACTURER

中间的那个空格时,才会出错。

 

但是为何,手动写成:

single_import	:	'IMPORT' (' ' | '\t')+ manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

中,却又是可以匹配到其中的空格呢?

所以,还是没有完全搞懂其中的规则,没有搞懂,此处的WS,何时会去自动匹配,何时会被当前的规则重写。

 

8.所以,再去试着手动写成WS,变成:

single_import	:	'IMPORT' WS+ manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

看看效果,结果竟然是出现了org.antlr.runtime.EearlyExitException:

if use WS then will earlyexitexception

9.期间出现

NoViableAltException(0@[null])

折腾过程见:

【已解决】antlr调试解析出错:NoViableAltException(0@[null])

 

【总结】

此处的UnwantedTokenException的错误的原因是,对于之前使用:

WS  :   ( ' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};

会自动识别匹配,单个的白空格,且由于加了hidden,所以会自动忽略掉。

所以,对于要匹配的内容:

IMPORT MANUFACTURER

中的空格,本身就只有一个,所以,已经被之前的WS匹配并忽略掉了。

所以,再次使用:

single_import	:	'IMPORT' WS+ manufacture deviceType deviceRevison ddRevision WS* '{' WS* everything WS* redefinitions WS* '}' ;

去匹配的时候,注意此处用的WS+,已经找不到对应的,其他的空格了,所以会报UnwantedTokenException的错。

解决办法是,直接把WS改为:

WS  :   ( ' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};

则可以自动识别并忽略掉所有的白空格,且对后续的所有内容中白空格都有效。

更多解释参见:

【已解决】antlr调试解析出错:NoViableAltException(0@[null])

转载请注明:在路上 » 【已解决】antlr调试解析出错:UnwantedTokenException(found=xxx)

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.320 seconds, using 22.16MB memory