javaantlrv3。运行时出现5个语法分析器错误
所以我的语法有一些问题,我就是搞不懂。我不确定到底是什么问题,也不确定问题出在哪里,但我会尽力解释到底发生了什么
作为一点背景知识,为了让语法更有意义,这里的目标是获取一个用伪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"
看起来field3=field();
行返回null,所以让我们看看field()
函数。这是相当长的,但我会张贴它只是为了彻底
// $ANTLR start "field"
// simpleABC.g:31:1: field returns [Field ast] : ( 'X:' x= NUM | 'T:' t= STRING | 'C:' c= STRING | 'M:' (b= NUM '/' l= NUM ) | 'M:' 'C' | 'K:' k= PITCH | 'L:' l= NUM | 'L:' '/' l= NUM | 'tempo:' tempo= NUM );
public final Field field() throws RecognitionException {
Field ast = null;
Token x=null;
Token t=null;
Token c=null;
Token b=null;
Token l=null;
Token k=null;
Token tempo=null;
try {
// simpleABC.g:32:2: ( 'X:' x= NUM | 'T:' t= STRING | 'C:' c= STRING | 'M:' (b= NUM '/' l= NUM ) | 'M:' 'C' | 'K:' k= PITCH | 'L:' l= NUM | 'L:' '/' l= NUM | 'tempo:' tempo= NUM )
int alt2=9;
switch ( input.LA(1) ) {
case 18:
{
alt2=1;
}
break;
case 17:
{
alt2=2;
}
break;
case 13:
{
alt2=3;
}
break;
case 16:
{
int LA2_4 = input.LA(2);
if ( (LA2_4==12) ) {
alt2=5;
}
else if ( (LA2_4==NUM) ) {
alt2=4;
}
else {
if (state.backtracking>0) {state.failed=true; return ast;}
int nvaeMark = input.mark();
try {
input.consume();
NoViableAltException nvae =
new NoViableAltException("", 2, 4, input);
throw nvae;
} finally {
input.rewind(nvaeMark);
}
}
}
break;
case 14:
{
alt2=6;
}
break;
case 15:
{
int LA2_6 = input.LA(2);
if ( (LA2_6==NUM) ) {
alt2=7;
}
else if ( (LA2_6==11) ) {
alt2=8;
}
else {
if (state.backtracking>0) {state.failed=true; return ast;}
int nvaeMark = input.mark();
try {
input.consume();
NoViableAltException nvae =
new NoViableAltException("", 2, 6, input);
throw nvae;
} finally {
input.rewind(nvaeMark);
}
}
}
break;
case 21:
{
alt2=9;
}
break;
default:
if (state.backtracking>0) {state.failed=true; return ast;}
NoViableAltException nvae =
new NoViableAltException("", 2, 0, input);
throw nvae;
}
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;
case 2 :
// simpleABC.g:33:4: 'T:' t= STRING
{
match(input,17,FOLLOW_17_in_field115); if (state.failed) return ast;
t=(Token)match(input,STRING,FOLLOW_STRING_in_field119); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Title((t!=null?t.getText():null))); }
}
break;
case 3 :
// simpleABC.g:34:4: 'C:' c= STRING
{
match(input,13,FOLLOW_13_in_field130); if (state.failed) return ast;
c=(Token)match(input,STRING,FOLLOW_STRING_in_field134); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Composer((c!=null?c.getText():null))); }
}
break;
case 4 :
// simpleABC.g:35:4: 'M:' (b= NUM '/' l= NUM )
{
match(input,16,FOLLOW_16_in_field145); if (state.failed) return ast;
// simpleABC.g:35:9: (b= NUM '/' l= NUM )
// simpleABC.g:35:10: b= NUM '/' l= NUM
{
b=(Token)match(input,NUM,FOLLOW_NUM_in_field150); if (state.failed) return ast;
match(input,11,FOLLOW_11_in_field152); if (state.failed) return ast;
l=(Token)match(input,NUM,FOLLOW_NUM_in_field156); if (state.failed) return ast;
}
if ( state.backtracking==0 ) { ast = (new Meter((b!=null?b.getText():null), (l!=null?l.getText():null))); }
}
break;
case 5 :
// simpleABC.g:36:4: 'M:' 'C'
{
match(input,16,FOLLOW_16_in_field166); if (state.failed) return ast;
match(input,12,FOLLOW_12_in_field168); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Meter("4", "4")); }
}
break;
case 6 :
// simpleABC.g:37:4: 'K:' k= PITCH
{
match(input,14,FOLLOW_14_in_field180); if (state.failed) return ast;
k=(Token)match(input,PITCH,FOLLOW_PITCH_in_field184); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Key((k!=null?k.getText():null))); }
}
break;
case 7 :
// simpleABC.g:38:4: 'L:' l= NUM
{
match(input,15,FOLLOW_15_in_field195); if (state.failed) return ast;
l=(Token)match(input,NUM,FOLLOW_NUM_in_field199); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Length((l!=null?l.getText():null))); }
}
break;
case 8 :
// simpleABC.g:39:4: 'L:' '/' l= NUM
{
match(input,15,FOLLOW_15_in_field211); if (state.failed) return ast;
match(input,11,FOLLOW_11_in_field213); if (state.failed) return ast;
l=(Token)match(input,NUM,FOLLOW_NUM_in_field217); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Length("/" + (l!=null?l.getText():null))); }
}
break;
case 9 :
// simpleABC.g:40:4: 'tempo:' tempo= NUM
{
match(input,21,FOLLOW_21_in_field228); if (state.failed) return ast;
tempo=(Token)match(input,NUM,FOLLOW_NUM_in_field232); if (state.failed) return ast;
if ( state.backtracking==0 ) { ast = (new Tempo((tempo!=null?tempo.getText():null))); }
}
break;
}
}
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}
finally {
// do for sure before leaving
}
return ast;
}
// $ANTLR end "field"
在我看来,第二个switch case语句中的match()
函数返回null,我认为这意味着它没有将输入标记与预期标记匹配。下一个片段在上面的field()
函数中,但为了防止您不想筛选所有这些内容,下面是我要说的片段:
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无法理解的东西,所以欢迎提供任何建议、猜测或解决方案。请让我知道,如果有任何额外的信息,你想让我提供,并感谢你的任何人,甚至通过这篇文章哈哈
共 (0) 个答案