【问题】
对于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
结果,始终只能识别第一行,余下的三行,都无法识别:
【解决过程】
1.期间,经历了多次修改代码。
最后无意间,发现了导致此现象的直接的原因:
(1)如果把上述的:
NEWLINE : '\r'? '\n' ;
加上,则就会出现上述的现象,只能识别第一行,无法识别其余的三行;
(2)而如果把该行去掉(或注释掉):
//NEWLINE : '\r'? '\n' ;
结果就可以正常识别输入的内容:
2. 貌似,还是很诡异,因为,至今看来,此行:
NEWLINE : '\r'? '\n' ;
对于上述的antlr的语法,也只是一个多余的一行,不起效果的一行,但是结果其有或无,却影响到了,整个语法能否正常工作。
其根本原因,暂未搞懂,待以后再去弄清楚。
3.对此,猜测,难道是,如果有对于的定义,就会导致无法正常工作?
那么就再去随便加个别的,多余的定义,看看是否会导致同样的错误,同样会导致语法无法识别所有的输入的内容。
加了个:
FAKE_TOKEN : '1' '2' '3';
看看测试效果。
结果证实,其是不影响的,语法是可以正常工作,可以识别所有的输入的内容的:
4.难道,此处antlr或antlrworks内置有个变量叫做NEWLINE
然后此处定义的NEWLINE把内置的替换了,导致,此处\r\n变成了
所以,先确定当前antlr文件的回车换行是什么:
可以看到,antlr的语法文件,其中都是cr lf。
然后对于要测试的数据,对应的也都是cr lf:
对应的,debug时候的设置,设置的line ending也是CRLF:
而对于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的情况下,可以识别所有的输入了:
注:其中,如果在多个antlrworks之间切换,比如
antlrworks-1.2.2.jar
antlrworks-1.5rc2.jar
那么,在切换的时候,最好手动删除,当然项目下面所生成的output目录(其下包含了所生成的各种代码和测试文件)
以避免影响到调试。(否则调试的时候,可能会出现一些异常的情况,可能是由于不同版本所生成的文件,有所不同,被混淆了而导致的错误)
【总结】
1.随便加个,多余的定义,是不会影响到语法是否正常工作的;
2.单独添加:
NEWLINE : '\r'? '\n' ;
会影响到此处的语法的正常工作,会导致,只能识别第一行,无法识别其余各行。
解决办法是,将此(无法再被细分的)定义,加上对应的fragment,变成:
fragment NEWLINE : '\r'? '\n' ;
就可以正常编译和调试整个语法了,而不会出现上述的NEWLINE影响到整个语法的执行了。
注:其中关于fragment,详见:
转载请注明:在路上 » 【已解决】antlr调试时,antlr的语法是对的,但是却无法完全识别输入的测试数据,仅识别第一行