Sto scrivendo un programma in cui ho bisogno di analizzare un file sorgente JavaScript, estrarre alcuni fatti e inserire/sostituire porzioni del codice. Una descrizione semplificata dei tipi di cose che avevo bisogno di fare è, dato questo codice:Utilizzo di ANTLR per analizzare e modificare il codice sorgente; sto sbagliando?
foo(['a', 'b', 'c']);
estratto 'a'
, 'b'
e 'c'
e riscrivere il codice come:
foo('bar', [0, 1, 2]);
sto usando ANTLR per le mie esigenze di analisi, producendo codice C# 3. Qualcun altro aveva già contribuito con una grammatica JavaScript. L'analisi del codice sorgente sta funzionando.
Il problema che sto riscontrando è capire come analizzare e modificare correttamente il file sorgente. Ogni approccio che cerco di prendere in realtà risolvendo il problema mi porta in un vicolo cieco. Non posso fare a meno di pensare che non sto usando lo strumento come è inteso o sono solo troppo novizio quando si tratta di trattare con gli AST.
Il mio primo approccio è stato quello di analizzare utilizzando un TokenRewriteStream
e attuare le EnterRule_*
metodi parziali per le regole che mi interessa. Anche se questo sembra rendere la modifica del flusso di token abbastanza facile, non c'è abbastanza informazione contestuale per la mia analisi. Sembra che tutto ciò a cui ho accesso sia un flusso piatto di token, che non mi dice abbastanza sull'intera struttura del codice. Ad esempio, per rilevare se la funzione foo
è chiamata, semplicemente guardando il primo token non avrebbe funzionato perché sarebbe partita anche il falso:
a.b.foo();
per permettermi di fare di più sofisticate analisi del codice, il mio secondo approccio era quello di modificare la grammatica con regole di riscrittura per produrre più di un albero. Ora, il primo blocco di codice di esempio produce questo:
Program CallExpression Identifier('foo') ArgumentList ArrayLiteral StringLiteral('a') StringLiteral('b') StringLiteral('c')
Questo funziona perfettamente per l'analisi del codice. Tuttavia, ora non riesco a riscrivere facilmente il codice. Certo, potrei modificare la struttura ad albero per rappresentare il codice che voglio, ma non posso usarlo per emettere il codice sorgente. Speravo che il token associato a ciascun nodo mi fornisse almeno informazioni sufficienti per sapere dove avrei dovuto apportare le modifiche nel testo originale, ma tutto ciò che ottengo sono indici di token o numeri di riga/colonna. Per usare i numeri di riga e di colonna, dovrei fare una seconda passata scomoda attraverso il codice sorgente.
Sospetto che mi manchi qualcosa nel capire come utilizzare correttamente ANTLR per fare ciò di cui ho bisogno. C'è un modo più corretto per me per risolvere questo problema?
* "C'è un modo più corretto per risolvere questo problema?" *: No, non AFAIK. Analizzi i tuoi input, manipoli e poi li emetti tu stesso. StringTemplate può, come dice Dave, aiutarti in questo. –