【已解决】antlr调试时,antlr的语法是对的,但是却无法完全识别输入的测试数据,仅识别第一行

【问题】

对于antlr的如下代码:

grammar DDParserDemo;

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

ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

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

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

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

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

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

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

fragment
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';

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

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

DECIMAL_VALUE
	:	DIGIT*;

HEX_VALUE
	:	'0x' HEX_DIGIT+;
/*	
startParse	:	(identification)+;
*/
startParse	:	(identification)+;

identification	:	definiton WS* ','? WS*   -> definiton
		;
	
definiton	:	(ID)^ ('\t'!|' '!)+ (DECIMAL_VALUE | HEX_VALUE)
		;

然后去调试如下的输入:

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

结果,始终只能识别第一行,余下的三行,都无法识别:

can only recognize the first line

【解决过程】

1.期间,经历了多次修改代码。

最后无意间,发现了导致此现象的直接的原因:

(1)如果把上述的:

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

加上,则就会出现上述的现象,只能识别第一行,无法识别其余的三行;

(2)而如果把该行去掉(或注释掉):

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

结果就可以正常识别输入的内容:

remove that special newline then can recognize all input

 

2. 貌似,还是很诡异,因为,至今看来,此行:

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

对于上述的antlr的语法,也只是一个多余的一行,不起效果的一行,但是结果其有或无,却影响到了,整个语法能否正常工作。

其根本原因,暂未搞懂,待以后再去弄清楚。

 

3.对此,猜测,难道是,如果有对于的定义,就会导致无法正常工作?

那么就再去随便加个别的,多余的定义,看看是否会导致同样的错误,同样会导致语法无法识别所有的输入的内容。

加了个:

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

看看测试效果。

结果证实,其是不影响的,语法是可以正常工作,可以识别所有的输入的内容的:

add fake token also work

4.难道,此处antlr或antlrworks内置有个变量叫做NEWLINE

然后此处定义的NEWLINE把内置的替换了,导致,此处\r\n变成了

所以,先确定当前antlr文件的回车换行是什么:

all is cr lf for antlr g file

可以看到,antlr的语法文件,其中都是cr lf。

然后对于要测试的数据,对应的也都是cr lf:

for test file also cr lf

对应的,debug时候的设置,设置的line ending也是CRLF:

line ending set to cr lf

 

而对于NEWLINE是否为内置的变量,无意间,在antlr官网找到了示例代码:

grammar Expr;		
prog:	(expr NEWLINE)* ;
expr:	expr ('*'|'/') expr
      |	expr ('+'|'-') expr
|	INT
|	'(' expr ')'
;
		

其是针对antlr v4的语法。

期间可以看到,貌似NEWLINE和INT,都是没有定义,就直接使用的。

所以推测出来,antlr内置本身就是支持INT,NEWLINE等定义的。

但是还是要去找到官网真正的确定的解释才可以。

但是暂时没有找到。

5.但是,可以先去,把此处的NEWLINE改为:

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

看看调试结果如何。

同样是无法识别其余各行,只能识别第一行。

6.猜想,不会是版本的问题吧?

所以,把当前的antlrworks-1.5rc2.jar,换成别的版本的。

先换成antlrworks-1.2.2.jar试试,折腾过程参见:

【已解决】用antlrworks-1.2.2.jar编译代码出错:error: cannot find symbol,g.NEWLINE();,symbol: method NEWLINE()

 

7.上述折腾期间,发现需要给NEWLINE加fragment,就是避免在1.2.2中出错,所以猜测,在最新的1.5rc2中,如果也是加了fragment的NEWLINE,估计就可以正常调试,识别所有输入了。

所以去试试。

最终,是可以,在保留NEWLINE的情况下,可以识别所有的输入了:

recognize all line with retain NEWLINE

 

注:其中,如果在多个antlrworks之间切换,比如

antlrworks-1.2.2.jar

antlrworks-1.5rc2.jar

那么,在切换的时候,最好手动删除,当然项目下面所生成的output目录(其下包含了所生成的各种代码和测试文件)

以避免影响到调试。(否则调试的时候,可能会出现一些异常的情况,可能是由于不同版本所生成的文件,有所不同,被混淆了而导致的错误)

 

【总结】

1.随便加个,多余的定义,是不会影响到语法是否正常工作的;

2.单独添加:

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

会影响到此处的语法的正常工作,会导致,只能识别第一行,无法识别其余各行。

解决办法是,将此(无法再被细分的)定义,加上对应的fragment,变成:

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

就可以正常编译和调试整个语法了,而不会出现上述的NEWLINE影响到整个语法的执行了。

注:其中关于fragment,详见:

【整理】antlr语法中的fragment



发表评论

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

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