2009-05-27 13 views
32

Esistono compilatori di codice nativo per Lisp? Fino a che punto può essere compilato, con tutta la sua natura dinamica, la garbage collection, le macro e cos'altro?Esistono compilatori di codice nativo Lisp?

+2

E pensare che fino adesso ho pensato che LISP fosse interpretato. –

+1

Stai parlando di Common Lisp, in esclusiva? –

+2

@Amit, sì e no. Voglio trovare un modo per generare (piccoli abbastanza per essere pratico) i file Windows * .exe per scrivere alcuni programmi di utilità usa e getta, come i convertitori di file, che potrei quindi dare a qualcun altro al lavoro da usare senza implorarli installare Lisp sulle loro macchine (soprattutto perché sono ancora arrabbiate con me dopo averle fatte installare Python). A tale scopo preferirei Common Lisp in quanto sembra più "pratico". D'altra parte, mi piacerebbe conoscere anche i compilatori Scheme (o qualsiasi altra cosa), per vedere il quadro generale. – Headcrab

risposta

53

Molti compilatori Lisp compilano codice "nativo". 'Nativo' significa qui 'codice macchina' (x86 in modalità 32 bit o 64 bit, PowerPC, SPARC, ...).

Altre domande:

  • possono compilatori 'di codice non nativo' generare eseguibili di file singoli? -> Sì.

  • i compilatori 'codice nativo' possono generare file eseguibili per file singoli? -> Sì.

  • come "nativo" è "nativo"? -> Il sistema Lisp ha per la maggior parte il proprio layout di struttura dati interno (classi CLOS), la loro gestione degli errori ('condizioni'), la propria gestione della memoria (garbage collection), le proprie librerie, ...

  • Lisp può funzionare senza un GC? -> Di solito no. Ci sono delle eccezioni.

  • E le dimensioni dell'applicazione? -> Di default, semplici modi per generare un'applicazione Lisp spesso portano a file eseguibili di grandi dimensioni.Gli eseguibili includono l'intero Lisp, compresa la sua libreria, i nomi di tutti i simboli, le informazioni sugli elenchi di argomenti per le funzioni, il compilatore, il debugger, informazioni sulla posizione del codice sorgente e altro. Alcuni compilatori generano anche codice di grandi dimensioni (SBCL è un esempio).

  • ci sono modi per ridurre le dimensioni delle applicazioni? -> Dipende dal sistema Lisp. Sistemi Lisp commerciali come LispWorks e Allegro CL possono. Per la consegna delle applicazioni, possono rimuovere il codice inutilizzato, rimuovere le informazioni di debug, rimuovere parti del Lisp (librerie, compilatore, ...) e altro.

  • i sistemi Lisp comuni generano piccoli eseguibili. Intendo davvero piccolo. -> Non proprio. Gli eseguibili sono grandi (CCL) o molto grandi (SBCL). Alcuni sistemi Lisp comuni possono generare file eseguibili di medie dimensioni. Ma nessuno può davvero generare piccoli eseguibili.

  • non c'è davvero modo di generare file eseguibili veramente piccoli? -> Anni fa sono stati scritti compilatori che generano codice C relativamente compatto senza librerie di grandi dimensioni. Ma questi compilatori non sono mantenuti.

  • esistono altri modi per ridurre i file eseguibili? -> Se si desidera eseguire più di un'applicazione Lisp, è opportuno riutilizzare runtime, compilatore, librerie in una o più librerie condivise. In questo modo il codice da consegnare sarà più piccolo, quando un runtime è già installato come libreria condivisa (o simile).

  • come faccio a sapere che cosa supporta il Lisp che sto utilizzando come consegna delle applicazioni? -> leggi il manuale e chiedi ad altri utenti.

  • ok, quindi la maggior parte dei sistemi Lisp comuni non è in grado di generare applicazioni minuscole. Ci sono altri dialetti Lisp in grado di generare file eseguibili più piccoli. -> Sì, alcuni compilatori Scheme possono.

  • in che modo Common Lisp gestisce gli errori di runtime? -> dipende dal modo in cui generi l'applicazione. Per impostazione predefinita si ottiene un debugger Lisp (a meno che non lo si sia rimosso). Ma è possibile utilizzare le proprie routine di gestione degli errori nell'applicazione e impedire che venga visualizzato il debugger.

  • quali sono i punti di forza del Common Lisp, quando generare file eseguibili veramente piccoli non lo è? -> è possibile includere un REPL per interagire con l'applicazione, è possibile utilizzare un compilatore incluso per compilare nuovo (o codice modificato) in fase di esecuzione, è possibile utilizzare il caricatore FASL (codice Lisp compilato) per CARICARE codice nativo aggiuntivo in fase di esecuzione (si pensi plug-in, patch, estensioni, ...), la gestione degli errori sofisticata incluso il recupero degli errori è possibile, ...

  • ma Lisp è dinamico? -> Sì, dinamico significa che può cambiare molte cose durante il runtime. Ad esempio, in Common Lisp è possibile modificare una classe CLOS in fase di esecuzione e le istanze della classe 'adotteranno le modifiche. Ma i vari sistemi Lisp hanno diversi modi per rimuovere alcune delle caratteristiche dinamiche. Le strutture sono meno dinamiche delle classi CLOS. È possibile dichiarare tipi e compilare con diverse impostazioni di ottimizzazione (velocità, sicurezza, debug, ...). È possibile integrare funzioni. E altro ancora.

Un modo semplice per visualizzare il codice compilato per le funzioni consiste nell'utilizzare la funzione Common Lisp DISASSEMBLE. Esempio in Clozure CL su un x86-64 Mac

? (defun foo (x y) (if (= x y) (sin x) (* y (cos x)))) 
FOO 
? (disassemble 'foo) 
L0 
    [0]  (leaq (@ (:^ L0) (% rip)) (% fn)) 
    [7]  (cmpl ($ 16) (% nargs)) 
    [10] (jne L209) 
    [16] (pushq (% rbp)) 
    [17] (movq (% rsp) (% rbp)) 

...

[172] (pushq (@ 77752)) 
    [179] (jmpq (@ 10 (% temp0))) 
L189 
    [189] (leaq (@ (:^ L0) (% rip)) (% fn)) 
    [196] (jmpq (@ .SPNVALRET)) 
L209 
    [209] (uuo-error-wrong-number-of-args) 
NIL 

L'uscita di smontaggio dipende ovviamente l'architettura del processore, il sistema operativo, il compilatore Lisp utilizzato e le impostazioni di ottimizzazione correnti .

+0

E se qualcosa viene modificato durante il runtime, cosa succede? Lisp genera una nuova versione del codice macchina o le modifiche influiscono solo sul "layout della struttura dati interna"? – Headcrab

+0

Dipende dalle modifiche. Alcuni potrebbero non richiedere un compilatore, alcuni potrebbero usare il compilatore interno, alcuni useranno solo il codice appena caricato (per sostituire o estendere il codice esistente), alcuni potrebbero non aver bisogno di un compilatore. Tutte le varianti sono possibili –

4

Ci puoi scommettere. Chez Scheme (un compilatore commerciale) è uno dei migliori. Gambit e Larceny sono compilatori di ricerca che generano anche codice nativo.

+0

http://www.iro.umontreal.ca/~gambit/ Gambit Homepage http://www.ccs.neu.edu/home/will/Larceny/ Larceny Homepage Gambit compila in C, Larceny compila sia in C, codice macchina o CLR. –

3

Sì. Vedi http://en.wikipedia.org/wiki/Common_Lisp. Si menziona che Steel Bank Common Lisp (un'implementazione abbastanza popolare) compila tutto in modo nativo per impostazione predefinita. Il fatto che le raccolte di dati inutili e simili siano usati non costituisce un ostacolo al codice nativo. Ciò significa solo che è necessario un qualche tipo di runtime. Ma allora cosa? Anche C ha un runtime.

9

Ci sono molti compilatori Lisp che compilano il codice nativo. CMUCL, SBCL, ClozureCL sono noti tra i compilatori Lisp open-source.

La raccolta di dati inutili non costituisce un ostacolo alla compilazione in codice nativo. Inoltre, in alcuni casi, Lisp può utilizzare l'allocazione dello stack che non richiede GC e può migliorare notevolmente le prestazioni (utilizzando la dichiarazione di estensione dinamica, almeno SBCL supporta questo).

Macro (e qualsiasi codice eseguito in fase di lettura (lettura macro e read-eval), tempo di compilazione (macro, macro del compilatore, codice in eval-when)) richiedono la compilazione incrementale (la prima macro-funzione ha da compilare e quindi è possibile compilare il codice che utilizza la macro). Ciò complica in qualche modo la compilazione, ma non è un problema. Inoltre, macro e macro del compilatore aiutano anche il processo di compilazione perché consentono al programmatore di scrivere generatori di codice e ottimizzatori di codice, essenzialmente personalizzando il compilatore.

Quindi il compilatore è più complicato di alcuni linguaggi più semplici (come C), ma la complessità è gestibile (vedere Design of CMU Common Lisp).

La natura dinamica di Common Lisp è controllabile e progettata per essere efficacemente compilabile. A differenza di altri linguaggi dinamici (ad es. Python), il dinamismo è limitato (ad esempio, non è possibile prendere l'ambiente lessicale corrente in fase di esecuzione) che offre ai compilatori una certa libertà di ottimizzazione.

+0

Ho provato diversi compilatori qualche tempo fa. Quello che ero in grado di fare con loro era qualcosa come ~ 10 MB per un "Hello, World!" File .exe di Windows, che mostra un prompt Lisp se c'è un errore di runtime. Quindi sembra che l'intero sistema Lisp sia stato trascinato insieme, il che fa pensare che non sia davvero troppo "nativo", forse ... – Headcrab

+10

Hmm, java trascina l'intero runtime di java, .net trascina l'intero clr, C++ trascina il intero C++ rt, lisp trascina l'intero runtime lisp. È solo la stessa cosa: quasi ogni lingua richiede il proprio tempo di esecuzione. Il runtime di Lisp è grande a causa della sua flessibilità (lo stesso è vero per jvm e clr). Tuttavia, il codice è ancora nativo: cioè, le istruzioni non sono per VM, ma per la CPU di destinazione. –

+0

Penso che alcune lisps forniscano un modo per scaricare le immagini con alcune funzioni rimosse (come il compilatore, se non è usato). forse questo potrebbe aiutare a restringerlo un po '? –

4

Non dimenticare Chicken Schema.

+0

Perché i downvotes? L'OP voleva sapere anche lo schema, e il pollo è un compilatore nativo. –