Ci sono linguaggi di programmazione che i loro programmi non funzionano su una VM o in modo nativo, ma piuttosto su un interprete? [chiuso]

-2

In questa domanda ho presentato un'idea Ho un semplice linguaggio di programmazione. Il modo in cui i programmi scritti in questa lingua verranno eseguiti, è all'interno di un interprete scritto in Java, che interpreterà il codice sorgente direttamente ed eseguirà.

Direi che non c'è dubbio che questa lingua sarebbe considerata un "linguaggio di programmazione". È in grado di produrre programmi che possono essere eseguiti e esiste una piattaforma su cui possono essere eseguiti (interprete).

Tuttavia, la maggior parte delle risposte alla mia domanda diceva che questo interprete non sarà considerato una VM.

Sono abituato a pensare che tutte le languges di programmazione creino programmi che sono più comunemente compilati in codice macchina e eseguiti in modo nativo, o compilati in una sorta di bytecode o IL e interpretati (eseguiti) su una VM. (O come nel raro caso del linguaggio Dart, interpretato ed eseguito da una VM che interpreta direttamente il codice sorgente, nessun IL o bytecode).

Ma nel mio caso - se è vero che il mio interprete non è considerato una VM - i programmi scritti nella mia lingua non vengono eseguiti su una VM e non vengono eseguiti in modo nativo, ma piuttosto eseguiti su un interprete.

La mia domanda:

Esistono linguaggi di programmazione, che i loro programmi sono più comunemente eseguiti in modo simile? Non su una VM, e non in modo nativo, ma piuttosto eseguito su un interprete? (che non è considerata una VM - anche se devo aggiungere non riesco ancora a capire perché un interprete usato come piattaforma per altri programmi su cui girare non sia considerato una VM ) .

    
posta NPElover 09.03.2014 - 12:22
fonte

3 risposte

6

Una VM è un software che offre un'astrazione simile a una macchina. Nel contesto della virtualizzazione, una macchina virtuale potrebbe astrarre risorse hardware. Nella programmazione delle VM del linguaggio, la VM offre un modello di macchina, ad es. con un set di istruzioni specifico, un numero di stack e un modello di memoria.

È vero che possiamo interpretare qualsiasi linguaggio come set di istruzioni, ma in genere le istruzioni VM sono più dettagliate delle direttive di programmazione di alto livello. Ad esempio, il% di alto livello% co_de potrebbe essere stato modificato in queste istruzioni per uno stack machine:

PUSH "baz"
PUSH "bar"
PUSH 2      ; number of arguments
LOAD "foo"  ; load the value of a variable onto the stack, here a function
CALL        ; the "CALL" op pops a function and number of arguments off the stack,
            ; then calls it

Il modo in cui queste istruzioni sono eseguite è irrilevante per questa discussione, potrebbero essere interpretate.

Un interprete che "direttamente" esegue foo("bar", "baz") generalmente non può essere considerato una VM. L'interpretazione diretta è caduta in disgrazia anche per le semplici lingue hobbistiche, ma i primi dialetti BASIC erano interpretati. Oggi, un'interpretazione semplice potrebbe essere ancora utilizzata per i linguaggi di shell semplici.

Il problema con ingenui interpreti di linea è la difficoltà di implementare la programmazione strutturata e procedurale. Supponiamo di voler scrivere foo("bar", "baz") . Questo potrebbe essere fatto con GOTO condizionali:

10 GOTO 40 IF x
20 z
30 GOTO 50
40 y
50 

Questo è molto fragile per un uso serio, ma è molto facile da implementare. Ma Vai a è considerato dannoso e preferiamo piuttosto un if (x) { y } else { z } costruire. Ad esempio, bash usa if/else :

if x
then y
else z
fi

Se la condizione è falsa, l'interprete potrebbe passare al if/then/else/fi corrispondente, ma questo è essenzialmente un problema di parità equilibrato, perché i condizionali possono essere annidati. Un'altra complicazione è che le istruzioni possono anche essere separate tramite else invece di newline, quindi non si tratta semplicemente di guardare la prima parola in ogni riga.

In breve, qualsiasi linguaggio con sintassi anche tollerabile a distanza dovrebbe essere analizzato in una struttura di dati prima dell'esecuzione. L'output di un parser è chiamato Abstract Syntax Tree. Per esempio. ; potrebbe produrre questo AST:

FunctionCall
name: "foo"
    |
   List
 length: 2
 /      \
String  Addition
"bar"    /    \
       Int   Variable
        4    name: "variable"

Un AST può essere valutato dal basso verso l'alto. Innanzitutto, sostituiamo la variabile con il suo valore (ad esempio foo("bar", 4 + variable) ). Successivamente, la sottostruttura

Addition
 /   \
4    38

sarebbe stato valutato, che sostituisce questa sottostruttura con 38 . Infine, viene eseguita la funzione get che sostituisce quella parte dell'albero.

Descrivendo la semantica operazionale di un linguaggio di programmazione usando questi grafici è bello, ma non è un buon modello per l'esecuzione effettiva: questo distrugge l'albero originale, quindi devi fare una copia per cose come corpi in loop o procedure. E se abbiamo variabili, il nostro interprete ha bisogno di un concetto di un ambiente che ci avvicini molto ad essere una VM.

Attraversiamo quel confine per essere una VM se notiamo che i nodi nel nostro AST sono essenzialmente Opcode. Se ordiniamo le operazioni dell'albero (qui: dal basso verso l'alto, da destra a sinistra: attraversamento post-vendita ), e non aggiorna la struttura attuale ma colloca i valori intermedi nello stack, l'esempio sopra potrebbe anche essere stato scritto come un assemblatore più simile

Variable "variable"
Int 4
Addition
String "bar"
List 2
FunctionCall "foo"
    
risposta data 09.03.2014 - 13:38
fonte
3

La maggior parte delle prime implementazioni dei linguaggi di programmazione sono transistor in un altro linguaggio di programmazione o interpreti, perché sono molto più semplici da scrivere rispetto ai compilatori o alle macchine virtuali.

Quando la lingua diventa popolare e le prime persone iniziano a lamentarsi della sua mancanza di prestazioni, le persone iniziano a cercare modi per rendere più veloci le implementazioni della lingua. Rendendolo un linguaggio compilato cambierebbe il modo in cui viene utilizzato e distribuito. Quindi la scelta abituale è quella di trasformare l'interprete in una macchina virtuale che converte l'origine in codice bytecode prima di eseguirla.

Un buon esempio è Javascript. Quando Netscape ha inventato Javascript nel 1995, è stato puramente interpretato. Ma quando le persone hanno iniziato a utilizzare JS per applicazioni sempre più complesse, la velocità ha iniziato a essere importante. C'era anche la guerra del browser in corso, in cui tutti i venditori di browser cercavano di sovraperformarsi a vicenda. Quindi i produttori di browser hanno iniziato a cercare modi per rendere JS più veloce. SpiderMonkey, il motore Javascript di Mozilla, compila Javascript in Bytecode e lo esegue in una VM. Il motore V8 di Google sta addirittura compilando il codice Javascript sul codice macchina nativo prima di eseguirlo.

    
risposta data 09.03.2014 - 13:36
fonte
3

Ho riflettuto su questa domanda molte volte. La mia risposta è che questi termini sono solo marginalmente utili, che potrebbe esserci qualcosa di uno spettro di linguaggi e di implementazioni tra di loro, ma in definitiva:

Una VM esegue un codice intermedio; un interprete esegue il codice sorgente.

Per una VM, il codice sorgente è semplicemente "zucchero sintattico" sul codice intermedio. Il codice sorgente non è richiesto dopo la compilazione. Più lingue potrebbero essere indirizzate alla stessa VM. (JVM, CLR)

Per un interprete, il codice sorgente è tutto ciò che esiste, e viene analizzato, analizzato ed eseguito immediatamente. Potrebbe essere tokenizzato, ma in tal caso si può garantire che una versione del codice sorgente originale possa essere ricostruita dal modulo tokenizzato.

Quindi, dove è un tale linguaggio? Non ce ne sono quasi nessuno esistente. La maggior parte delle lingue viene compilata prima o poi per il miglioramento delle prestazioni. Quelli che non possono essere sono quelli in cui i valori di runtime sono o potrebbero essere interpolati direttamente nelle istruzioni, o dove nessuno potrebbe essere disturbato a scrivere un compilatore.

La maggior parte dei linguaggi di script di shell sono interpretati: sh, bash, csh, MSDOS / file BAT di Windows, ecc. Calcolatori da tavolo (dc). Un pacchetto grafico come Gnuplot. Script di editor (sed, ed, vi). Il file di configurazione per un software importante come Apache. Questi sono tutti interpretati, ma alcuni di essi sono solo marginalmente qualificati come lingue.

Questo è tutto ciò che riesco a pensare.

    
risposta data 09.03.2014 - 14:45
fonte

Leggi altre domande sui tag