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.
Scarica il ANTLR source da GitHub. Il JAR "completo" precompilato dal sito ANTLR contiene un bug noto. Il repository GitHub ha la soluzione.
Estrarre il tarball ANTLR.
% tar xzf antlr-antlr3-release-3.4-150-g8312471.tar.gz
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 -
Scarica un Java grammar. Ce ne sono altri, ma so che questo funziona.
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
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
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);
}
}
Compila.
% javac -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main.java
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
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.
fonte
2012-05-16 11:55:45
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? –
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. –
Il conteggio di variabili e metodi sarebbe molto più semplice osservando il bytecode compilato, ad esempio utilizzando il framework bytecode ASM. –