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

【基本解决】antlr v3中包含{skip();}的语法,调试解析时出错:org.antlr.runtime.EarlyExitException

ANTLR crifan 3538浏览 0评论

【问题】

antlr v3,在antlrworks中,用如下语法:

grammar DDParserDemo;

options {
	output = AST;
	ASTLabelType = CommonTree; // type of $stat.tree ref etc...
}

//NEWLINE :   '\r'? '\n' ;
//NEWLINE :   '\r' '\n' ;
fragment 
NEWLINE :   '\r'? '\n' ;


fragment
ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;
    
fragment
FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

fragment
WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {skip();}
    ;


STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;


ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

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
DIGIT
	:	'0'..'9';

//FAKE_TOKEN 	:	'1' '2' '3';

/*
DECIMAL_VALUE
	:	'1'..'9' DIGIT*;
*/

DECIMAL_VALUE
	:	DIGIT*;

HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;


HEX_VALUE
	:	'0x' HEX_DIGIT+;


/*
BLANKSPACE_TAB
//	:	(' ' | '\t'){skip();};
	:	(' ' | '\t')
	{$channel=HIDDEN;};
*/	
//fragment BLANK	:	(' '|'\t')+ {skip();};
//BLANK	:	(' '|'\t') {skip();};
BLANK	:	(' '|'\t') {skip();};

fragment
HEADER_FILENAME
	:	('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'_')*;

/*
//singleInclude	:	'#include' ' '+ '"' ID '.h"' ;
//singleInclude	:	'#include' ' '+ '"' ID+ '.h"' ;
//singleInclude	:	'#include' ' '+ '"' HEADER_FILENAME '.h"';
//singleInclude	:	'#include' ' ' '"' HEADER_FILENAME '.h"';
//singleInclude	:	'#include "' HEADER_FILENAME '.h"';
//fragment singleInclude	:	'#include' (' ')+ '"' ID '.h"';
//singleInclude	:	'#include' (' '|'\t')+ '""' ID '.h"';
//singleInclude	:	'#include' (' '|'\t')+ '"std_defs.h"';
singleInclude	:	'#include' (' '|'\t')+  ID '.h';

include		:	singleInclude WS*   -> singleInclude;
*/

//startParse	:	include* identification+;
//startParse	:	include+ identification+;
//startParse	:	identification+;
startParse	:	manufacture deviceType deviceRevison ddRevision;
manufacture	:	'MANUFACTURER'^ 	BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
deviceType	:	'DEVICE_TYPE'^ 		BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
deviceRevison	:	'DEVICE_REVISION'^ 	BLANK+ (DECIMAL_VALUE | HEX_VALUE)(','?)! WS*;
ddRevision	:	'DD_REVISION'^ 		BLANK+ (DECIMAL_VALUE | HEX_VALUE)(','?)! WS*;
	
//identification	:	definiton WS* (','?)! WS*   -> definiton;
	
//definiton	:	(ID)^ ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE)
//definiton	:	(ID)^ BLANKSPACE_TAB+ (DECIMAL_VALUE | HEX_VALUE)
//definiton	:	ID ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE);

去调试解析:

MANUFACTURER      0x1E6D11,
DEVICE_TYPE       0x00FF,
DEVICE_REVISION   5,
DD_REVISION       1

结果出错:

use antlr grammar parse error org.antlr.runtime.EearlyExitException

【解决过程】

1.参考:

How to resolve this parsing ambiguitiy in Antlr3

看了其解释,只是明白了一点,那就是,

在语法中,的确存在,解析器,希望匹配的东西,但是实际上所匹配的内容中,缺少了后面的部分,所以导致解析器报错,说是EarlyExitException,即过早退出,(希望还有更多后续匹配的内容)

2.所以,就去自己的语法中,看看是否有,类似于上面这样的歧义的东西。

试试去,把skip去掉,即变为:

//BLANK	:	(' '|'\t') {skip();};
BLANK	:	(' '|'\t');

看看效果。结果果然可以正常解析对应的值了:

after remove skip then can recognize the value

接下来,还是需要,好好搞懂,为何加上那个skip,而出现EarlyExitException。

3.改为加上感叹号,表示不捕获:

//manufacture	:	'MANUFACTURER'^ 	BLANK+ (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;
manufacture	:	'MANUFACTURER'^ 	(BLANK+)! (DECIMAL_VALUE | HEX_VALUE) (','?)! WS*;

结果还是和上面一样,还是可以捕获对应的那6个空格。

4.参考:

http://www.antlr3.org/api/Java/index-all.html

中的:

DEFAULT_CHANNEL – Static variable in interface org.antlr.runtime.Token

All tokens go to the parser (unless skip() is called in that rule) on a particular "channel".

以及,进一步的,参考:

SKIP_TOKEN

得知,加上skip()后,对应的,antlr就不为此内容,创建对应的token了。

所以,倒是可以去试试,把对应的内容,去改为hidden,而不是skip:

//BLANK	:	(' '|'\t') {skip();};
//BLANK	:	(' '|'\t');
BLANK	:	(' '|'\t') {$channel=HIDDEN;};

结果却又是变成EarlyExitException了:

set to channel hidden result is also earlyexitexception

觉得还是不能理解。

5.期间,又出现别的问题,详见:

【基本解决】antlr v3,用包含{$channel=HIDDEN;}语法,结果解析出错:MissingTokenException

 

【总结】

虽然,对于org.antlr.runtime.EarlyExitException和之后的MissingTokenException,都可以避免了。

但是还是无法实现所要的,可以skip或hidden空格的效果。

更多总结详见上面的:

【基本解决】antlr v3,用包含{$channel=HIDDEN;}语法,结果解析出错:MissingTokenException

转载请注明:在路上 » 【基本解决】antlr v3中包含{skip();}的语法,调试解析时出错:org.antlr.runtime.EarlyExitException

发表我的评论
取消评论

表情

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

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

  1. 根本就不需要在规则中出现BLANK+这样的东西吧
    过客9年前 (2015-10-25)回复
85 queries in 0.173 seconds, using 22.17MB memory