2015-07-16 26 views
8

Sto provando a convertire il formico ANTLR3 grammar in un ANTLR4 grammar, per poterlo utilizzare con il runtime antlr4-python2. Questa grammatica è un parser fuzzy C/C++.Parser lento ANTLR4 generato in Python, ma veloce in Java

Dopo la conversione esso (in pratica la rimozione di operatori di albero e predicati semantici/sintattica), ho generato i file python2 utilizzando:

java -jar antlr4.5-complete.jar -Dlanguage=Python2 CPPGrammar.g4

E il codice viene generato senza alcun errore, in modo da importare nel mio progetto Python (sto usando PyCharm) per fare alcuni test:

import sys, time 
from antlr4 import * 
from parser.CPPGrammarLexer import CPPGrammarLexer 
from parser.CPPGrammarParser import CPPGrammarParser 

currenttimemillis = lambda: int(round(time.time() * 1000)) 

def is_string(object): 
    return isinstance(object,str) 

def parsecommandstringline(argv): 
    if(2!=len(argv)): 
     raise IndexError("Invalid args size.") 
    if(is_string(argv[1])): 
     return True 
    else: 
     raise TypeError("Argument must be str type.") 

def doparsing(argv): 
    if parsecommandstringline(argv): 
     print("Arguments: OK - {0}".format(argv[1])) 
     input = FileStream(argv[1]) 
     lexer = CPPGrammarLexer(input) 
     stream = CommonTokenStream(lexer) 
     parser = CPPGrammarParser(stream) 
     print("*** Parser: START ***") 
     start = currenttimemillis() 
     tree = parser.code() 
     print("*** Parser: END *** - {0} ms.".format(currenttimemillis()-start)) 
     pass 

def main(argv): 
    tree = doparsing(argv) 
    pass 

if __name__ == '__main__': 
    main(sys.argv) 

Il problema è che l'analisi è molto lenta. Con un file contenente ~ 200 linee ci vogliono più di 5 minuti per completare, mentre l'analisi dello stesso file in antlrworks richiede solo 1-2 secondi. Analizzando l'albero antlrworks, ho notato che la regola expr e tutti i suoi discendenti sono chiamati molto spesso e penso che ho bisogno di semplificare/modificare queste regole per rendere il parser operare più velocemente: expr_tree

È la mia ipotesi corretta o ho fatto qualche errore durante la conversione della grammatica? Cosa si può fare per rendere l'analisi veloce come su antlrworks?

UPDATE: Ho esportato la stessa grammatica in Java e sono stati necessari solo 795 ms per completare l'analisi. Il problema sembra più correlato all'implementazione di Python rispetto alla grammatica stessa. C'è qualcosa che può essere fatto per accelerare l'analisi di Python?
Ho letto here che python può essere 20-30 volte più lento di java, ma nel mio caso python è ~ 400 volte più lento!

+0

Devono rispettare i tempi di esecuzione delle regole per avere una certezza. Potrebbe essere l'uso pesante di set negati, letterali nel parser o qualcos'altro che sembra completamente benigno. – GRosenberg

+0

@GRosenberg grazie per il commento. Non sono un esperto di ANTLR, ma non mi sembra che la mia grammatica e quella originale abbiano un sacco di set o letterali negati nel parser. Penso che sia un errore relativo a 'antlr4-python2-runtime' perché ci vuole solo 1 secondo per analizzare lo stesso file su java.Python può essere più lento, ma 400 volte più lento è troppo per pensare che sia un problema dalla mia parte. – Vektor88

+0

Tuttavia, il modo migliore per identificare l'aspetto del tempo di esecuzione che non è performante consiste nel profilare le singole regole e identificare particolari aspetti delle regole che sono lenti da elaborare. Il problema è dalla tua parte solo nel senso che la tua grammatica sta facendo qualcosa per innescare il rallentamento. Quasi sicuramente sarà necessaria una modifica al runtime. La parte difficile è capire cosa aggiustare. La chiave, per fortuna, è da qualche parte nella tua grammatica. Fai ciò che puoi per isolare la causa e crea un problema sul repository di Github di Antlr. Questo è il modo più veloce per farlo riparare. – GRosenberg

risposta

6

Confermo che i runtime di Python 2 e Python 3 hanno problemi di prestazioni. Con alcune patch, ho ottenuto un 10x di accelerazione sul runtime python3 (~ 5 secondi fino a ~ 400 ms). https://github.com/antlr/antlr4/pull/1010

+2

La richiesta pull è stata accettata: utilizzare l'ultimo runtime python antlr4 o attendere le versioni 4.5.3 su pypi ... – Pinaraf

3

Ho affrontato un problema simile quindi ho deciso di confrontare questo vecchio post con una possibile soluzione. La mia grammatica funzionava all'istante con TestRig ma era incredibilmente lenta su Python 3.

Nel mio caso l'errore era il token non-goloso che stavo usando per produrre commenti di una riga (doppia barra in C/C++, '%' nel mio caso):

TKCOMM : '%' ~[\r\n]* -> skip ; 

questo è in qualche modo sostenuta da questo post da sharwell in questa discussione qui: https://github.com/antlr/antlr4/issues/658

Quando la performance è un problema, evitare di usare gli operatori non avidi, soprattutto nelle regole del parser .

Per testare questo scenario, è possibile rimuovere regole/token non grezzi dalla grammatica.

+0

E cosa hai usato per avere una regola dei commenti migliore? – DainDwarf

+0

@DainDwarf Al momento sono pre-elaborazione e rimozione dei commenti in una routine separata senza ANTLR. Sto usando questo come soluzione alternativa fino a quando la patch delle prestazioni citata su questo thread arriva a pip. – Caian