Java 运行时出现ANTLR v3.5解析器错误
所以我的语法有一些问题,我就是想不出来。我不确定到底是什么问题,也不知道问题在哪里,但我会尽力解释到底发生了什么 作为一点背景知识,为了让语法更有意义,这里的目标是获取一个用伪abc表示法编写的输入程序,并使用java库jMusic进行回放 另外,值得注意的是,我使用的是自定义AST代码,而不是ANTLR的内置AST生成器 当解析“header”中的“fields”时,问题似乎首先出现,但我也尝试从语法中完全删除header,以尝试缩小问题可能出现的范围,但在尝试解析“notes”时,我遇到了类似的问题,因此我感觉这里有一个更普遍的问题 这是我的语法:Java 运行时出现ANTLR v3.5解析器错误,java,parsing,antlr3,Java,Parsing,Antlr3,所以我的语法有一些问题,我就是想不出来。我不确定到底是什么问题,也不知道问题在哪里,但我会尽力解释到底发生了什么 作为一点背景知识,为了让语法更有意义,这里的目标是获取一个用伪abc表示法编写的输入程序,并使用java库jMusic进行回放 另外,值得注意的是,我使用的是自定义AST代码,而不是ANTLR的内置AST生成器 当解析“header”中的“fields”时,问题似乎首先出现,但我也尝试从语法中完全删除header,以尝试缩小问题可能出现的范围,但在尝试解析“notes”时,我遇到了类
grammar simpleABC;
// grammar rules
options{
backtrack = true;
}
@members{
// override the default error reporting functions
public void reportError(RecognitionException e) {
// call the Parser member function to report the error
displayRecognitionError(this.getTokenNames(), e);
// exit with error
System.exit(1);
}
}
program returns [AST ast]
: { $ast = new Program(); }
(header {$ast.addAST($header.ast);})
(score {$ast.addAST($score.ast);})
;
header returns [Header ast]
: 'header' '{'
(field {$ast.addAST($field.ast);})+
'}'
;
field returns [Field ast]
: 'X:' x=NUM { $ast = (new ReferenceNumber($x.text)); }
| 'T:' t=STRING { $ast = (new Title($t.text)); }
| 'C:' c=STRING { $ast = (new Composer($c.text)); }
| 'M:' (b=NUM '/' l=NUM) { $ast = (new Meter($b.text, $l.text)); }
| 'M:' 'C' { $ast = (new Meter("4", "4")); }
| 'K:' k=PITCH { $ast = (new Key($k.text)); }
| 'L:' l=NUM { $ast = (new Length($l.text)); }
| 'L:' '/' l=NUM { $ast = (new Length("/" + $l.text)); }
| 'tempo:' tempo=NUM { $ast = (new Tempo($tempo.text)); }
;
score returns [Score ast]
: 'score' '{'
(part {$ast.addAST($part.ast);})+
'}'
;
part returns [Part ast]
: instrument=STRING id=VAR '{' {$ast = new Part($instrument.text, $id.text);}
(phrase {$ast.addAST($phrase.ast);})+
'}'
;
phrase returns [Phrase ast]
: '|' (b1=bar {$ast.addAST($b1.ast);} '|')+ // typical bar
/* | '|:' (b2=bar {$ast.addAST($b2.ast);} '|')+ (b3=bar {$ast.addAST($b3.ast);} ':|') // single repeat
| '|:' (b4=bar {$ast.addAST($b4.ast);} '|')+ // multi-ending repeat
'1' (b5=bar {$ast.addAST($b5.ast);} )+ ':|' // 1st ending
'2' (b6=bar {$ast.addAST($b6.ast);} )+ // 2nd ending
TODO: fix repeats
*/
;
bar returns [Bar ast]
: (note {$ast.addAST($note.ast);})+
;
note returns [Note ast]
: pitch=PITCH length=NUM { $ast = new Note($pitch.text, $length.text); }
| pitch=PITCH { $ast = new Note($pitch.text); }
;
// lexical analysis stuff
NUM : ('0'..'9')+
;
VAR : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
;
PITCH : (('A'..'G') | ('a'..'g')) (',' | '\'')?
;
COMMENT : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
;
WS : ( ' ' | '\t' | '\r' | '\n' ) {$channel=HIDDEN;}
;
STRING : '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
;
fragment
ESC_SEQ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
;
下面是我一直在使用的一个简单输入程序:
header {
X:1
T:"Notes"
M:C
K:C
L:1/4
}
score {
PIANO pianoPart {
|C, D, E, F,|G, A, B, C|D E F G|A B c d| e f g a|b c' d' e'|f' g' a' b'|
}
}
运行此代码时,出现以下错误:
Exception in thread "main" java.lang.NullPointerException
at simpleABCParser.header(simpleABCParser.java:151)
at simpleABCParser.program(simpleABCParser.java:87)
at simpleABCParser.main(simpleABC.java:32)
好的,它告诉我解析器中有一个空指针异常。下面看一下这个空指针发生的位置
// $ANTLR start "header"
// simpleABC.g:25:1: header returns [Header ast] : 'header' '{' ( field )+ '}' ;
public final Header header() throws RecognitionException {
Header ast = null;
Field field3 =null;
try {
// simpleABC.g:26:2: ( 'header' '{' ( field )+ '}' )
// simpleABC.g:26:4: 'header' '{' ( field )+ '}'
{
match(input,19,FOLLOW_19_in_header67); if (state.failed) return ast;
match(input,22,FOLLOW_22_in_header69); if (state.failed) return ast;
// simpleABC.g:27:4: ( field )+
int cnt1=0;
loop1:
while (true) {
int alt1=2;
int LA1_0 = input.LA(1);
if ( ((LA1_0 >= 13 && LA1_0 <= 18)||LA1_0==21) ) {
alt1=1;
}
switch (alt1) {
case 1 :
// simpleABC.g:27:5: field
{
pushFollow(FOLLOW_field_in_header75);
field3=field();
state._fsp--;
if (state.failed) return ast;
if ( state.backtracking==0 ) {ast.addAST(field3);}
}
break;
default :
if ( cnt1 >= 1 ) break loop1;
if (state.backtracking>0) {state.failed=true; return ast;}
EarlyExitException eee = new EarlyExitException(1, input);
throw eee;
}
cnt1++;
}
match(input,24,FOLLOW_24_in_header83); if (state.failed) return ast;
}
}
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}
finally {
// do for sure before leaving
}
return ast;
}
// $ANTLR end "header"
在我看来,第二个switch case语句中的match()
函数返回null,我认为这意味着它没有将输入标记与预期标记进行匹配。下一个代码段位于上面的字段()
函数中,但为了防止您不想筛选所有这些内容,下面是我要讨论的代码段:
switch (alt2) {
case 1 :
// simpleABC.g:32:4: 'X:' x= NUM
{
match(input,18,FOLLOW_18_in_field99); if (state.failed) return ast;
x=(Token)match(input,NUM,FOLLOW_NUM_in_field103); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new ReferenceNumber((x!=null?x.getText():null))); }
}
break;
所以我想我已经尽可能地追溯到了这一点,而没有深入到ANTLR。对我来说,证据表明语法有问题。我已经检查了很多次,并试图隔离这个问题,但我没有任何运气
这一定是一些我刚刚错过的非常愚蠢的东西,或者是一些我目前对ANTLR无法理解的东西,所以欢迎提供任何建议、猜测或解决方案。如果您希望我提供任何其他信息,请告诉我,并感谢您通过此帖子发布的任何人。哈哈。因此,我成功地解决了我遇到的问题,不再得到我指出的错误。问题是,我向AST对象添加了一些东西,这些东西是我在解析器规则中返回的,而没有首先初始化它们。例如,“header”应该以以下行开头:{$ast=newheader();},然后再尝试向header添加任何“fields”。这个问题解决了,但现在我有了一个新的问题,关于“音高”词法规则。它告诉我与字符“C”不匹配,这需要一个音高。有什么想法吗?
switch (alt2) {
case 1 :
// simpleABC.g:32:4: 'X:' x= NUM
{
match(input,18,FOLLOW_18_in_field99); if (state.failed) return ast;
x=(Token)match(input,NUM,FOLLOW_NUM_in_field103); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new ReferenceNumber((x!=null?x.getText():null))); }
}
break;