2012-05-09 10 views
9

Qualcuno ha un'implementazione completa (possibilmente github o googlecode) per l'utilizzo di un file di grammatica ANTLR e del codice sorgente Java per analizzare l'origine Java. Ad esempio, voglio semplicemente essere in grado di contare il numero di variabili, metodo, ecc.Utilizzo di ANTLR per l'analisi statica del file di origine Java

Anche utilizzando una versione recente di ANTLR.

+4

Suppongo che sia possibile scaricare un parser Java/builder AST direttamente dal sito Web ANTLR (che pertanto soddisfa "una versione recente di ANTLR"). Scrivere un crawler per contare i metodi e i campi è piuttosto semplice. Il "ecc." parte significa che nessuno può indovinare cos'altro vuoi; perché non funziona uno strumento di metrica standard? –

+0

Se si sta considerando di eseguire analisi statiche per errori o sicurezza di quanto non si avrà probabilmente bisogno di più dell'AST e delle regole di riscrittura dell'albero fornite da ANTLR. Potresti voler usare ANTLR in combinazione con [Stratego/XT] (http://en.wikipedia.org/wiki/Stratego/XT). Non so se qualcuno ha una versione pubblica gratuita di quello che cerchi. Buona domanda. Se vuoi strumenti di qualità professionale controlla il profilo di Ira. –

+1

Il conteggio di variabili e metodi sarebbe molto più semplice osservando il bytecode compilato, ad esempio utilizzando il framework bytecode ASM. –

risposta

12

Ho pensato di fare una pausa durante la pausa pranzo. Questo potrebbe non risolvere completamente il tuo problema, ma potrebbe darti un punto di partenza. L'esempio presuppone che tu stia facendo tutto nella stessa directory.

  1. Scarica il ANTLR source da GitHub. Il JAR "completo" precompilato dal sito ANTLR contiene un bug noto. Il repository GitHub ha la soluzione.

  2. Estrarre il tarball ANTLR.

    % tar xzf antlr-antlr3-release-3.4-150-g8312471.tar.gz
  3. Costruire il JAR "completo" ANTLR.

    % cd antlr-antlr3-8312471 
    % mvn -N install 
    % mvn -Dmaven.test.skip=true 
    % mvn -Dmaven.test.skip=true package assembly:assembly 
    % cd -
  4. Scarica un Java grammar. Ce ne sono altri, ma so che questo funziona.

  5. Compilare la grammatica sull'origine Java.

    % mkdir com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated 
    % mv *.g com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated 
    % java -classpath antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar org.antlr.Tool -o com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated Java.g
  6. Compila la sorgente Java.

    % javac -classpath antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/*.java
  7. Aggiungere il seguente file di origine, Main.java.

    import java.io.IOException; 
    import java.util.List;
    import org.antlr.runtime.*; import org.antlr.runtime.tree.*;
    import com.habelitz.jsobjectizer.unmarshaller.antlrbridge.generated.*;
    public class Main { public static void main(String... args) throws NoSuchFieldException, IllegalAccessException, IOException, RecognitionException { JavaLexer lexer = new JavaLexer(new ANTLRFileStream(args[1], "UTF-8")); JavaParser parser = new JavaParser(new CommonTokenStream(lexer)); CommonTree tree = (CommonTree)(parser.javaSource().getTree()); int type = ((Integer)(JavaParser.class.getDeclaredField(args[0]).get(null))).intValue(); System.out.println(count(tree, type)); } private static int count(CommonTree tree, int type) { int count = 0; List children = tree.getChildren(); if (children != null) { for (Object child : children) { count += count((CommonTree)(child), type); } } return ((tree.getType() != type) ? count : count + 1); } }
  8. Compila.

    % javac -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main.java
  9. Selezionare un tipo di sorgente Java che si desidera contare; ad esempio, VAR_DECLARATOR, FUNCTION_METHOD_DECL o VOID_METHOD_DECL.

    % cat com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/Java.tokens
  10. Run su qualsiasi file, tra cui il Main.java recentemente creata.

    % java -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main VAR_DECLARATOR Main.java 
    6

Questa è imperfetta, naturalmente. Se osservi da vicino, potresti aver notato che la variabile locale dell'istruzione for avanzata non è stata conteggiata. Per questo, è necessario utilizzare il tipo FOR_EACH anziché VAR_DECLARATOR.

Avrete bisogno di una buona comprensione degli elementi del codice sorgente Java e di essere in grado di fare ipotesi ragionevoli su come questi corrispondano alle definizioni di questa particolare grammatica. Inoltre, non sarai in grado di fare i conteggi dei riferimenti. Le dichiarazioni sono semplici, ma il conteggio degli usi di un campo, ad esempio, richiede una risoluzione di riferimento.p.C.f fa riferimento a un campo statico f di una classe p all'interno di un pacchetto oppure fa riferimento a un campo di istanza f dell'oggetto archiviato da un campo statico di una classe p? I parser di base non risolvono i riferimenti per le lingue complesse come Java, perché il caso generale può essere molto difficile. Se vuoi questo livello di controllo, dovrai usare un compilatore (o qualcosa di simile). Il compilatore Eclipse è una scelta popolare.

Vorrei anche ricordare che avete altre opzioni oltre a ANTLR. JavaCC è un altro generatore di parser. Lo strumento di analisi statica PMD, che utilizza JavaCC come generatore di parser, consente di scrivere regole personalizzate che potrebbero essere utilizzate per i tipi di conteggi indicati.

+0

Dal punto di vista del semplice conteggio delle istanze di sintassi (ad es. # Dichiarazioni di variabili) questa è una risposta soddisfacente. OP è opaco su cos'altro vuole fare; l'analisi statica di solito va ben oltre il semplice conteggio e in genere richiede una tabella dei simboli e spesso richiede un'analisi del flusso. Se ha bisogno solo di contare, la tua soluzione è pesche (quindi +1); se ha bisogno di più, questo non lo taglierà, la risoluzione dei nomi e tanto meno l'analisi del flusso per Java è difficile. –

+0

@IraBaxter: ho convenuto che la mia soluzione sia possibilmente parziale. Ho il sospetto che i suoi bisogni siano relativamente semplici, in più è stato divertente tornare a pasticciare con ANTLR. –

+0

È una domanda vaga perché non ho mai ottenuto una grammatica Java per lavorare con la versione recente di antlr. La sintassi è cambiata molto dalla versione 2.0 e 3.0. Molti dei documenti online erano orientati verso la versione precedente. Mi stava buttando fuori. Mi interessava soprattutto la sintassi e l'approccio con antlr. Il mio vero compito era piuttosto semplice. –

Problemi correlati