ANTLR4 C#运行时解析速度极慢



我正在将我的自定义DSL从GoldParser迁移到ANTLR4,但我被困在解析步骤,因为它需要太多时间才能完成。与我在GoldParser中的毫秒范围相比,1000行的源代码在34秒内被解析。

这是我用于解析的C#代码:

var input = new AntlrInputStream(prg);
var lexer = new PCLexer(input);
var tokens = new CommonTokenStream(lexer);
var parser = new PCParser(tokens);       
var tree = parser.programma(); // root rule is "programma"      

我怀疑问题出在语法上,语法有很多歧义,事实上,这就是我决定将其从GoldParser迁移的原因(由于无法进一步改进,我意识到在Antlr4中重写它要容易得多,而且不在乎歧义)。

我的问题是:我能做些什么来进行毫秒级的解析吗?或者ANTLR4天生就很慢是正常的?我是Antlr的新手,我不知道该期待什么。

恢复语法,这是一种伪C:

    grammar PC;                                    
    fragment Number : [0-9] ;
    fragment DoubleStringCharacter  : ~["rn] ;
    fragment SingleStringCharacter  : ~['rn] ;
    fragment DoubleStringCharacterM : ~["] ;  
    fragment SingleStringCharacterM : ~['] ;
    BlockComment : '/*' .*? '*/' -> skip ;
    LineComment  : '//' ~[rn]* -> skip ;
    WhiteSpaces  : [tu000Bu000Cu0020u00A0]+ -> skip ; 
    Identifier   : [a-zA-Z_][a-zA-Z0-9_]* ; 
    Quote        : '''  ;
    DoubleQuote  : '"'   ;
    NullLiteral  : 'null' ;
    BoolLiteral  : 'true' | 'false' ;
    IntLiteral   : (Number)+ ;
    FloatLiteral : (Number)* '.' (Number)+ ;
    StringLiteral    :     DoubleQuote DoubleStringCharacter*   DoubleQuote ;
    StringLiteralJs  :     Quote       SingleStringCharacter*   Quote       ;
    StringLiteralM   : '@' DoubleQuote DoubleStringCharacter*   DoubleQuote ;
    StringLiteralJsM : '@' Quote       SingleStringCharacter*   Quote       ;
    Or_op        : 'or' | '||'  ;
    And_op       : 'and' | '&&' ;
    Not_op       : 'not' | '!'  ;
    Not_eq       : '!=' | '<>'  ;
    programma : interfaccia? dichiarazione* ;
    interfaccia : 'interfaccia' '{' oggettoInterfaccia* '}' ;
    oggettoInterfaccia : Identifier Identifier '{' definizioneProprieta* '}' ;
    definizioneProprieta : Identifier '=' valoreProprieta ';' 
                         | oggettoInterfaccia; 
    valoreProprieta : BoolLiteral | IntLiteral  | FloatLiteral | StringLiteral | StringLiteralM | Identifier ;
    dichiarazione : dichiarazioneReference 
                  | dichiarazioneUsing 
                  | dichiarazioneClass
                  | dichiarazioneFunzione 
                  | dichiarazioneVariabile 
                  ;             
    dichiarazioneReference : 'reference' StringLiteral ';' ;
    dichiarazioneUsing     : 'using' Identifier '=' StringLiteral ';' ;
    dichiarazioneClass     : 'class' Identifier ';' ;
    dichiarazioneFunzione : Identifier Identifier '(' parametri ')' '{' stmList '}' ;
    parametri : parametro (',' parametro)* ;
    parametro : Identifier 
              | Identifier Identifier
              ;       
    dichiarazioneVariabile : Identifier listaVariabili ';' ;                            
    listaVariabili : variabile (',' variabile)* ;
    variabile : Identifier 
              | Identifier '=' exprOrArray
              ;
    stmList : stm* ;
    stm  : blocco
         | dichiarazioneVariabile
         | etichetta
         | istruzioneIf
         | istruzioneWhile
         | istruzioneFor
         | istruzioneDo                              
         | istruzioneGoto
         | istruzioneBreak
         | istruzioneContinue
         | istruzioneReturn
         | expr ';'              
         | assegnamento ';'               
         | ';'          
         | 'ConnectEvent' '(' Identifier ',' Identifier ',' Identifier ')' ';'
         | istruzioneTry
         ;
    blocco : '{' stmList '}' ;
    istruzioneIf : 'if' '(' expr ')' stm ( 'else' stm )? ;
    istruzioneFor : 'for' '(' stm condizioneFor ';' incrementoFor? ')' stm ;
    condizioneFor : expr? ; 
    incrementoFor : expr 
                  | assegnamento 
                  ;
    istruzioneWhile : 'while' '(' expr ')' stm ; 
    istruzioneDo : 'do' stm 'while' '(' expr ')' ;    // TODO si deve aggiungere ';' ?          
    etichetta          : Identifier ':' ;    
    istruzioneGoto     : 'goto' Identifier ';' ;
    istruzioneBreak    : 'break' ';' ;
    istruzioneContinue : 'continue' ';' ;
    istruzioneReturn   : 'return' exprOrArray ';' | 'return' ';' ;
    istruzioneTry      : 'try' blocco 'catch' '(' Identifier ')' blocco ;
    assegnamento : Identifier '=' exprOrArray
                 | Identifier '[' expr ']' '=' exprOrArray
                 | Identifier '.' Identifier '=' exprOrArray
                 ;
    exprOrArray : expr 
                | '{' exprList '}'
                ;
    exprList : exprOrArray ',' exprList
             | exprOrArray
             ;
    expr : expr '+=' expr
         | expr '-=' expr
         | expr '?' expr ':' expr
         | expr Or_op  expr
         | expr And_op expr         
         | expr '==' expr
         | expr Not_eq expr
         | expr '<' expr
         | expr '>' expr
         | expr '<=' expr
         | expr '>=' expr
         | expr 'as' Identifier
         | expr '+' expr
         | expr '-' expr
         | expr '*' expr
         | expr '/' expr
         | expr '%' expr
         | expr Not_op expr
         | '-' expr
         | '+' expr
         | '--' expr
         | '++' expr
         | expr '--'
         | expr '++'
         | expr '[' expr ']' 
         | callFun
         | Identifier '.' Identifier '(' methodParams ')'      
         | Identifier '.' Identifier          
         | Identifier
         | literal
         | '(' expr ')'
         ;
    methodParams : methodParam (',' methodParam)* ;
    methodParam  : exprOrArray ;
    callFun : Identifier '(' methodParams ')'               
            | 'new' Identifier '(' methodParams ')'
            ;        
    literal : NullLiteral
            | BoolLiteral
            | IntLiteral  
            | FloatLiteral 
            | StringLiteral
            | StringLiteralJs
            | StringLiteralM
            | StringLiteralJsM        
            ;

如果您的语法有歧义,Gold Parser(我的理解是:LALR(1))将无法正确解析源文本。[我认为你忽略了它应该产生的关于shift reduce和reduce reduce冲突的抱怨?]它会选择其中一个解析。而且,作为LALR(1),它将在线性时间内这样做,所以它很快并不奇怪;这是LALR(1)解析器的一个关键实用程序。

语法中的歧义通常(并不总是)意味着你应该消除一些语法解析,但没有。如果Gold在解析中挑选,有些是错误的,那么没有理由相信你得到了正确的解析。

所以,事实上,如果你可以在几毫秒内用Gold得到错误的答案,为什么ANTLR得到错误答案的速度较慢呢?

我建议你消除歧义。(作为一个起点,你的表情subgammer在我看来非常模糊)。我认为ANTLR会"加速"。

相关内容

  • 没有找到相关文章

最新更新