perlcompile - Introduzione al Traduttore-Compilatore Perl
Perl ha da sempre un compilatore: il vostro codice viene compilato in un
formato interno (un albero sintattico [parse tree, NdT]) che è poi ottimizzato prima di essere
eseguito. Fin dalla versione 5.005, Perl è stato distribuito con un modulo
capace di ispezionare l'albero sintattico ottimizzato (B ), e questo è
stato utilizzato per scrivere molte utilità, incluso un modulo che vi permette di
convertire il vostro codice Perl in codice C in modo che possa essere compilato
in un eseguibile nativo.
Il modulo B fornisce accesso all'albero sintattico, e altri moduli
(detti ``back end'' [che si occupano della parte terminale del procedimento, NdR])
lavorano sull'albero. Alcuni di questi lo esportano come
bytecode, codice C, o un testo semi-leggibile per l'uomo. Un altro
attraversa l'albero sintattico per costruire una guida di riferimento [cross reference, NdT] di quali
funzioni, formati, e variabili vengono usate, e dove. Un altro controlla
il vostro codice alla ricerca di costrutti di dubbia natura. Un altro
back end, ancora, salva l'albero sintattico come codice Perl, agendo come un
miglioratore [beautifier, NdT] o deoffuscatore di codice.
Poiché il suo scopo originario era quello di produrre codice C
corrispondente ad un programma Perl e di trasformarlo in un eseguibile nativo, il
modulo B e i suoi back end associati sono noti come ``il compilatore'',
anche se essi in realtà non compilano niente.
Parti diverse del compilatore sono più propriamente un ``traduttore'',
o un ``ispettore'', ma la gente vuole che Perl abbia una ``opzione compilatore''
non un ``ispettore gadget''. Cosa potete farci?
Questo documento ricopre l'uso del compilatore Perl: quali moduli comprende,
come usare i moduli back end più importanti, che problemi ci sono e come
li si aggira.
I back end sono nella gerarchia di B:: e il front-end (il modulo con
cui voi, utenti del compilatore, avrete qualche volta a che fare [dunque ciò che ha a che fare
con la parte iniziale del procedimento, NdR]) è il modulo O. Alcuni back end (per esempio B::C )
hanno programmi (come perlcc) che nascondono la complessità dei moduli.
Ecco i back end importanti da conoscere, con il loro status espresso
come un numero da 0 (linea guida per implementazione futura) a
10 (se ci fosse un bug, ne saremmo molto sorpresi):
- B::Bytecode
-
Salva l'albero sintattico in un formato indipendente dall'architettura, che può
essere ricaricato in seguito attraverso il modulo ByteLoader. Status: 5 (qualcosa
funziona, qualcosa no, qualcosa deve ancora essere testato).
- B::C
-
Crea un file sorgente C contenente il codice per ricostruire l'albero sintattico
e richiama l'interprete. Status: 6 (molte cose funzionano adeguatamente,
inclusi programmi che usano Tk).
- B::CC
-
Crea un codice sorgente C corrispondente al run time code path [``percorso del codice a tempo di esecuzione'', NdR]
nell'albero sintattico. Questo è quello che più si avvicina ad un
traduttore Perl-C, ma il codice generato è quasi incomprensibile
perché traduce l'albero sintattico in una enorme struttura a switch [commutatori, NdR]
che manipola strutture Perl.
Un possibile miglioramento sarebbe ridurre (date sufficienti informazioni
all'interno del programma Perl) alcune delle manipolazioni di strutture dati
Perl in manipolazioni di interi, float, ecc. a livello C. Status: 5 (alcune cose
funzionano, inclusi esempi non complicati in Tk).
- B::Lint
-
Protesta se trova costrutti di dubbia natura nel vostro codice sorgente.
Status: 6 (funziona adeguatamente, ma ha un numero molto limitato di aree
che è in grado di controllare).
- B::Deparse
-
Ricrea il codice sorgente Perl, tentando di formattarlo coerentemente.
Status: 8 (funziona abbastanza bene, ma mancano alcune cose di natura oscura).
- B::Xref
-
Effettua un riepilogo della dichiarazione e uso di funzioni e variabili.
Status: 8 (funziona abbastanza bene, ma ha ancora diversi vecchi bug da risolvere).
Questa sezione spiega come usare i vari back end del compilatore.
Essi sono presentati approssimativamente in ordine di maturità
in modo tale che i back end più stabili e testati siano descritti
per primi, e quelli più sperimentali e incompleti siano descritti
per ultimi.
Il modulo O abilita automaticamente il flag -c in Perl, il che
gli impedisce di eseguire il vostro codice prima che esso venga compilato.
Questo è il motivo per cui tutti i back end stampano:
ilmioprogrammaperl syntax OK
prima di produrre ulteriore output.
Il back end per la costruzione della guida di riferimento (B::Xref) produce
un rapporto riguardante il vostro programma, sviscerando le dichiarazioni e le chiamate
alle funzioni, alle variabili ed ai formati, dividendoli per file e funzione.
Per esempio, ecco una porzione del rapporto costruito sul programma pod2man
incluso nella distribuzione di Perl:
Subroutine clear_noremap
Package (lexical)
$ready_to_print i1069, 1079
Package main
$& 1086
$. 1086
$0 1086
$1 1087
$2 1085, 1085
$3 1085, 1085
$ARGV 1086
%HTML_Escapes 1085, 1085
Ciò mostra le variabili usate nella funzione clear_noremap . La variabile
$ready_to_print è una variabile lessicale di tipo my(), Introdotta (dichiarata
precedentemente con my()) alla linea 1069, e utilizzata alla linea 1079.
La variabile $& proveniente dal package main è usata alla linea 1086, e così via.
Un numero di linea potrebbe essere preceduto da una singola lettera:
- i
-
Variabile lessicale introdotta (dichiarata con
my()) per la prima volta.
- &
-
Funzione o chiamata a un metodo.
- s
-
Funzione definita.
- r
-
Formato definito.
L'opzione più utile del modulo per la guida di riferimento è
quella di poter salvare il rapporto in un file separato. Per esempio, per salvare
il rapporto riguardante ilmioprogrammaperl nel file rapporto è sufficiente
digitare:
$ perl -MO=Xref,-orapporto ilmioprogrammaperl
Per back end per la decompilazione trasforma il codice Perl
in codice Perl. Esso è in grado di riformattare il codice durante il processo,
comportandosi di fatto come un deoffuscatore.
Il modo più semplice di utilizzarlo è:
$ perl -MO=Deparse ilmioprogrammaperl
Noterete immediatamente che Perl non sa come mettere in paragrafi il vostro codice.
Dovrete separare in seguito i pezzi di codice l'uno dall'altro a mano utilizzando
l'andata a capo.
Ciononostsante, guardate come si comporta con i programmi one-liner [su una sola riga, NdR]:
$ perl -MO=Deparse -e '$op=shift||die "uso: $0
codice [...]";chomp(@ARGV=<>)unless@ARGV; for(@ARGV){$era=$_;eval$op;
die$@ if$@; rename$era,$_ unless$era eq $_}'
-e syntax OK
$op = shift @ARGV || die("uso: $0 codice [...]");
chomp(@ARGV = <ARGV>) unless @ARGV;
foreach $_ (@ARGV) {
$era = $_;
eval $op;
die $@ if $@;
rename $era, $_ unless $era eq $_;
}
Il decompilatore ha diverse opzioni riguardanti il codice che genera. Per
esempio, potete impostare la dimensione di ogni rientro da 4 a 2 spazi (come sopra)
in questo modo:
$ perl -MO=Deparse,-si2 ilmioprogrammaperl
L'opzione -p aggiunge parentesi dove esse sono generalmente omesse:
$ perl -MO=Deparse -e 'print "Ciao, mondo\n"'
-e syntax OK
print "Ciao, mondo\n";
$ perl -MO=Deparse,-p -e 'print "Ciao, mondo\n"'
-e syntax OK
print("Ciao, mondo\n");
Si veda the B::Deparse manpage per maggiori informazioni sulle opzioni di formattazione.
Il back end di controllo dello stile (B::Lint) analizza i programmi alla
ricerca di porzioni di codice dallo stile povero.
Lo scarso stile di un programmatore può essere uno strumento molto utile
per un altro programmatore, per questo le opzioni vi lasciano scegliere su cosa bisogna impuntarsi.
Per eseguire il controllo di stile sul vostro codice sorgente usate:
$ perl -MO=Lint ilmioprogrammaperl
Per disabilitare controlli di contesto e funzioni non definite:
$ perl -MO=Lint,-context,-undefined-subs ilmioprogrammaperl
Si veda the B::Lint manpage per maggiori informazioni sulle opzioni.
Questo modulo trasforma lo stato compilato interno del vostro programma Perl
in un file sorgente C, che può poi essere compilato in un eseguibile nativo
per una particolare piattaforma usando un compilatore C.
Il programma risultante si collega alla libreria dell'interprete Perl,
quindi non vi farà risparmiare né spazio sull'hard disk (a meno che voi
non compiliate Perl tramite una libreria condivisa) né dimensione del programma.
Tuttavia potrebbe farvi risparmiare tempo nell'esecuzione.
Lo strumento perlcc genera tale eseguibile di default.
perlcc ilmioprogramma.pl
Questo back end è utile solo se avete già un modo per
caricare ed eseguire il codice bytecode che produce. Il modulo ByteLoader
fornisce proprio questa funzionalità.
Per trasformare un programma Perl in un codice bytecode eseguibile, utilizzate perlcc
con l'opzione -B :
perlcc -B ilmioprogrammaperl.pl
Il bytecode è indipendente dall'architettura, quindi se avete
un modulo o un programma compilato, esso sarà portabile
quanto un codice sorgente Perl (posto che l'utente del modulo
o del programma abbia un interprete Perl abbastanza moderno per
eseguire il codice bytecode)
Si veda B::Bytecode per maggiori informazioni sulle opzioni per controllare
l'ottimizzazione e il tipo di codice generato dal modulo Bytecode.
Il back end per C ottimizzato trasformerà il run time code path del vostro
programma perl in un programma C equivalente (ma ottimizzato) che manipola
direttamente le strutture dati Perl. Il programma continuerà comunque
a collegarsi alla libreria dell'interprete Perl per utilizzare eval(), s///e ,
require , ecc.
Lo strumento perlcc genera questo tipo di eseguibili se viene utilizzata
l'opzione -O. Per compilare un programma Perl (con estensione .pl o .p )
utilizzate il comando:
perlcc -O ilmioprogrammaperl.pl
Per produrre una libreria condivisa a partire da un modulo Perl (con estensione .pm ) usate:
perlcc -O Ilmiomoduloperl.pm
Per maggiori informazioni, si veda perlcc e B:CC.
- B
-
Questo è il modulo introspettivo (``riflessivo'' in termini Java), che permette
ad un programma Perl di ispezionare il proprio stesso codice.
Tutti i moduli back end utilizzano questo modulo per ottenere accesso all'albero sintattico
compilato. Voi, come utenti di un modulo back end, non avrete mai bisogno
di interagire direttamente con B.
- O
-
Questo modulo è il front end al back end del compilatore. Normalmente richiamato
con un comando come questo:
$ perl -MO=Deparse ilmioprogrammaperl
Che è come dire use O 'Deparse' nel vostro programma Perl.
- B::Asmdata
-
Questo modulo è utilizzato dal modulo B::Assembler, che è a sua volta
usato dal modulo B::Bytecode, che salva un albero sintattico come bytecode per un caricamento
successivo. Non è propriamente un back end, ma piuttosto un componente
di un back end.
- B::Assembler
-
Questo modulo trasforma l'albero sintattico in una struttura dati comoda per essere
salvata e in seguito ritradotta in albero sintattico. Non è propriamente un
back end, ma piuttosto il componente di un back end. È utilizzato dal programma
l<assemble> che produce bytecode.
- B::Bblock
-
Questo modulo è utilizzato dal back end B::CC. Esegue ``blocchi base''.
Un blocco base è una serie di operazioni che sono eseguite dall'inizio
alla fine, senza possibilità di effettuare salti o essere fermate.
- B::Bytecode
-
Questo modulo è un back end che genera bytecode dall'albero sintattico
di un programma. Questo bytecode viene scritto su un file, da cui può venire
poi ripristinato ad albero sintattico. Lo scopo è di eseguire subito
la costosa compilazione del programma, salvare lo stato dell'interprete in un file
e poi ripristinare lo stato dal file quando il programma deve essere eseguito.
Si veda Il back end Bytecode per maggiori dettagli sull'utilizzo.
- B::C
-
Questo modulo scrive codice C corrispondente all'albero sintattico e ad altre
strutture interne dell'interprete.
Voi compilate il file C corrispondente, otterrete un file eseguibile che
ripristinerà le strutture interne e l'interprete Perl inizierà
ad eseguire il programma.
Si veda Il back end per C semplice per maggiori dettagli sull'utilizzo.
- B::CC
-
Questo modulo dà in output del codice C corrispondente alle operazioni
del vostro programma. A differenza di B::C, che salva essenzialmente l'interprete
ed il suo stato in un programma C, il modulo B::CC genera un programma C che
non dipende dall'interprete. Una conseguenza è che i programmi
tradotti in C da B::CC vengono eseguiti più velocemente dei normali
programmi interpretati.
Si veda Il back end per C ottimizzato per maggiori dettagli sull'utilizzo.
- B::Concise
-
Questo modulo stampa una sintetica (ma completa) versione dell'albero sintattico
di Perl. Il suo output è più personalizzabile di quello di B::Terse
o di B::Debug (e può emularli). Questo modulo è utile per chi
sta scrivendo i propri personali back end, o per chi deve imparare il funzionamento interno
di Perl. Non è molto utile per il programmatore medio.
- B::Debug
-
Questo modulo esporta l'albero sintattico di Perl con un livello di dettaglio
``verboso'' sullo STDOUT. È utile per chi sta scrivendo i propri back end, o
chi deve imparare il funzionamento interno di Perl. Non è molto utile per il
programmatore medio.
- B::Deparse
-
Questo modulo produce codice sorgente Perl dall'albero sintattico compilato.
È utile per effettuare del debug e per smontare il codice prodotto da altri,
agisce anche come strumento di stampa per il proprio codice.
Si veda </``Il back end per la decompilazione''> per maggiore dettagli sull'utilizzo.
- B::Disassembler
-
Questo modulo ritraduce il bytecode in un albero sintattico. Non è
propriamente un back end ma piuttosto un componente di un back end. È
utilizzato dal programma l<disassemble> associato al bytecode.
- B::Lint
-
Questo modulo ispeziona il codice compilato a partire dal vostro codice sorgente
alla ricerca di costrutti che non siano abbastanza gravi da giustificare
un warning. Per esempio l'utilizzo di un array in un contesto scalare
senza dire
scalar(@array) è una di quelle cose che Lint è in
grado di identificare.
Si veda Il back end Lint per maggiori dettagli sull'utilizzo.
- B::Showlex
-
Questo modulo stampa la lista delle variabili
my() utilizzate in una
funzione o in un file. Per ottenere la lista di tutte le variabili my()
utilizzate in una funzione definita in un programma, usate:
$ perl -MO=Showlex,lamiafunzione ilmioprogrammaperl
Mentre per ottenere una lista delle variabili my() utilizzate in un programma, usate:
$ perl -MO=Showlex ilmioprogrammaperl
[BROKEN]
- B::Stackobj
-
Questo modulo è usato dal modulo B::CC. Non è propriamente
un back end ma piuttosto un componente di un back end.
- B::Stash
-
Questo modulo è utilizzato dal programma perlcc, che compila
un modulo in un eseguibile. B::Stash stampa la tabella di simboli utilizzata
da un programma, ed è utilizzata per evitare che B::CC produca codice
C per i moduli B::* e O. Non è propriamente un back end ma piuttosto
un componente di un back end.
- B::Terse
-
Questo modulo stampa il contenuto dell'albero sintattico, ma senza tutte le informazioni
che fornisce B::Debug. Per esempio:
print "Hello, world." ha prodotto 96 linee
di output con B::Debug, ma solo 6 con B::Terse.
Questo modulo è utile per chi sta scrivendo i propri back end,
o per chi deve imparare il funzionamento interno di Perl. Non è molto utile
per il programmatore medio.
- B::Xref
-
Questo modulo stampa un rapporto di dove le variabili, le funzioni e i format
sono definiti e utilizzati all'interno di un programma e nei moduli che questi
utilizza.
Si veda Il back end per la guida di riferimento per maggiori dettagli sull'utilizzo.
Il back end per C semplice attualmente salva i typeglobs solo con nomi alfanumerici.
Il back end per C ottimizzato produce codice per più moduli di quelli
che dovrebbe (per esempio DirHandle). C'è anche la possibilità che
gestisca correttamente goto LABEL fuori dalla subroutine in esecuzione
(goto &sub funziona bene).
goto LABEL attualmente non funziona affatto in questo back end.
Genera anche una enorme funzione di inizializzazione che confonde
il compilatore C. Altri problemi includono: la matematica senza segno
non funziona correttamente; alcuni opcode sono gestiti non correttamente dal
meccanismo di gestione degli opcode predefiniti.
I blocchi BEGIN{} sono eseguiti mentre il codice viene compilato. Ogni stato
esterno che è inizializzato in BEGIN{}, come l'apertura di files, l'inizializzazione
di connessioni a database ecc., non si comporta correttamente.
Per far funzionare tutto ciò, Perl ha un blocco INIT{} che corrisponde
al codice che viene essere eseguito prima del vostro programma ma dopo che il vostro
programma è stato compilato. Ordine d'esecuzione: BEGIN{}, (possibile
salvataggio di stato attraverso il back end del compilatore), INIT{}, esecuzione
del programma, END{}.
Questo documento è stato scritto originariamente da Nathan Torkington, ed
è attualmente mantenuto dalla mailing list perl5-porters.
perl5-porters@perl.org.
La versione su cui si basa questa traduzione è ottenibile con:
perl -MPOD2::IT -e print_pod perlcompile
Per maggiori informazioni sul progetto di traduzione in italiano si veda
http://pod2it.sourceforge.net/ .
Traduzione a cura di tunnuz.
Revisione a cura di dree.
Mon Jun 11 22:02:13 2012
|