运行时期间ANTLR v3.5解析器错误

时间:2013-12-18 19:06:37

标签: java parsing antlr3

所以我的语法有些问题,我似乎无法弄明白。我不确定问题究竟是什么或它在哪里,但我会尽力解释发生了什么。

就像一点背景,这样语法可能会更有意义,这里的目标是采用伪abc-notation编写的输入程序,并使用java库jMusic播放它。

另外,值得注意的是我使用的是自定义AST代码,而不是ANTLR内置的AST构建器。

在解析'header'中的'fields'时,问题似乎首先发生,但我也尝试完全从语法中删除标题,试图缩小可能出现问题的地方,但是我遇到了类似的问题当试图解析“笔记”时,我觉得这里有一个更普遍的问题。

这是我的语法:

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 个答案:

没有答案