Sviluppare un linguaggio dinamico


11

Ho creato diversi compilatori scritti a mano per linguaggi molto semplici, ma ora voglio provare a sviluppare un linguaggio dinamico, simile a un Python o Ruby semplificato. Tuttavia, è stato facile per me capire come funzionano i compilatori. I compilatori primitivi traducono e basta. Ma non posso farlo se la lingua è dinamica. Devo scrivere un interprete o una macchina virtuale che tenga traccia delle informazioni in fase di esecuzione e mi dedichi molto più lavoro.

In breve, ci sono delle risorse che dovrei controllare considerando che so come funzionano i compilatori ma voglio migrare alla creazione di un interprete? Esistono alcune macchine virtuali disponibili per linguaggi dinamici, ma non ho problemi a implementare le mie. Questo è tutto solo per la mia esperienza personale.

Sto cercando informazioni su come passare da un compilatore a un interprete. Se ho già creato un compilatore per il linguaggio X ma ora cosa devo scrivere un interprete, cosa bisogna fare e ci sono risorse che vanno oltre il processo?

Non voglio risorse ampie o astratte che spieghino come funzionano i compilatori o le macchine virtuali. Ho molti libri di testo sull'argomento. Tutte le risorse che ho trovato online presumono che tu abbia 0 esperienze e quindi ti inizi con l'analisi lessicale o sintattica o sono estremamente astratte. Ho un compilatore funzionante, ma ora voglio trasformarlo in un interprete e aggiungere funzionalità dinamiche al linguaggio.

Non sono riuscito a trovare risorse su questo processo, potrebbe essere di portata troppo limitata o risorse sul "back-end" di un interprete senza essere troppo teorico, motivo per cui ho pubblicato qui.


1
Ci sono tonnellate di risorse come questa. Si noti che la linea tra compilatore e interprete è più sfocata di quanto si pensi; il compilatore C # 4.0 supporta la programmazione dinamica, così come una serie di altri compilatori.
Robert Harvey,

@RobertHarvey Sì, ciò che sto chiedendo è che le risorse creino il mio tempo di esecuzione / interprete / macchina virtuale. L'interprete .Net è troppo complicato per me basare il mio su!
Austin Henley,


1
E dai un'occhiata a questa domanda SO , ci sono un paio di commenti con riferimenti ad altre domande che sono abbastanza interessanti ...
yannis,

Risposte:


4

Per prima cosa scopri l'implementazione degli interpreti. Raccomando PLAI (Linguaggi di programmazione: applicazione e interpretazione) . Arriva rapidamente alla carne dell'interpretazione senza soffermarsi troppo sulla sintassi.

Per la tua lingua, sarai in grado di riutilizzare la libreria front-end del compilatore (parser, principalmente) e di runtime (GC, strutture dati, operazioni primitive, ecc.).

Ovviamente, puoi anche implementare un linguaggio dinamico con un compilatore che produce codice che manipola (alcune delle) stesse strutture dati che useresti in un interprete. Ad esempio, in un interprete è possibile implementare variabili globali come una tabella hash indicizzata da stringa. In un compilatore, si compilerebbero riferimenti a variabili globali nel codice che esegue la ricerca utilizzando la stessa tabella. Al contrario, è possibile compilare variabili lessicali in una rappresentazione più efficiente (argomenti "nativi" e riferimenti alla struttura di chiusura).


5

Se vuoi imparare le basi dell'implementazione di un interprete per un linguaggio dinamico, non posso immaginare un punto di partenza migliore delle origini del primissimo linguaggio di programmazione interpretato dinamico: Lisp.

Nel suo documento originale del 1960 , John McCarthy ha definito 5 funzioni primitive necessarie per un Lisp. Naturalmente, McCarthy intendeva il suo lavoro su Lisp solo come esercizio accademico; era uno studente laureato che implorò evalin assemblea e creò il primo interprete Lisp. Paul Graham identifica sette primitivi : citazione, atomo, eq, contro, auto, cdr e cond.

Il fatto è che puoi davvero implementare Lisp in qualsiasi lingua; una volta implementato eval, è facile impostare un REPL e si dispone di un interprete interattivo . Le persone sono state abbastanza annoiate o curiose di implementare Lisps in C, Java, Ruby, Python e molte altre lingue. E non sempre di proposito; è importante ricordare la Decima Regola di Greenspun :

Qualsiasi programma C o Fortran sufficientemente complicato contiene un'implementazione lenta ad hoc, specificata in modo informale, inficiata da bug, di metà di Common Lisp.

Non sto dicendo che il tuo obiettivo finale dovrebbe essere un'implementazione Lisp; ma l'omoiconicità ha i suoi benefici quando si impara ad implementare un linguaggio dinamico; perché affrontare i problemi di sintassi quando puoi imparare su una lingua in cui la sintassi idiomatica è identica all'AST di una lingua che usa un lexer / parser?

Comunque ... solo un suggerimento. Ma è per una buona ragione che la maggior parte dei grandi linguaggi di programmazione da quando C ha almeno un po 'di natura Lisp.


1
Vorrei poter accettare due risposte. Grazie, penso che implementerò davvero un interprete Lisp. È facile da analizzare, ha un sacco di documentazione e codice esistente e dovrebbe darmi una base su cui lavorare. Purtroppo ho seguito un corso di laurea che utilizzava Scheme e mi ha fatto strappare i capelli;)
Austin Henley,

1
Ora sono tentato di compilare la mia lingua nel mio dialetto di Lisp!
Austin Henley,


0

Ho messo questo (~ 600 righe di C #) nel dominio pubblico, che supporta quote / list / apply / eval / test / etc e permette di personalizzare facilmente una sintassi simile a Lisp e / o i builtin semantici:

https://repl.it/CdjV/3

Per esempio:

        var factorial = (Lambda)language.
            Evaluate
            (@"
                ( => ( n ) (
                        ? ( != n 0 )
                        ( * n ( this ( - n 1 ) ) )
                        1
                    )
                )
            ");

        var sw = new System.Diagnostics.Stopwatch();
        var n = 12;
        var r = 0;
        int k;
        sw.Start();
        for (k = 0; k < 10000; k++)
        {
            r = (int)factorial.Invoke(null, n);
        }
        sw.Stop();
        Console.WriteLine("{0}! = {1}", n, r);
        Console.WriteLine();
        Console.WriteLine("in {0} ms (for {1} times)", sw.ElapsedMilliseconds, k.ToString("0,0"));

'HTH,


0

Supponendo che tu conosca un po 'di Schema (ad esempio hai letto SICP ) o Lisp, ti consiglio il libro Lisp In Small Pieces di Queinnec . Spiega diverse varianti di interpreti e compilatori simili a Lisp (incluso il bytecode o il C).

Inoltre, leggi Scott's Programming Language Pragmatics , l'ultimo Dragon Book , il manuale GC , i tipi di Pierce e i linguaggi di programmazione .

Sto cercando informazioni su come passare da un compilatore a un interprete.

Quindi, la valutazione parziale (e le proiezioni di Futamura) e lo stile di continuazione potrebbero essere rilevanti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.