Un interprete è generalmente inteso per eseguire un programma senza compilare il programma in una fase separata. Tuttavia, la maggior parte degli interpreti moderni non interpreta direttamente il codice sorgente - questo non è comunque possibile per qualcosa di più complesso di BASIC. Invece, prima analizzano il codice, quindi producono una rappresentazione intermedia e infine eseguono questa rappresentazione.
Le rappresentazioni intermedie comuni sono:
-
bytecode , che è un cugino di alto livello del codice macchina. Vengono eseguiti su una macchina virtuale che utilizza questo bytecode. Il bytecode non è generalmente leggibile dall'uomo, sebbene possa esistere una serializzazione leggibile dall'uomo (ad es. Assemblatore Jasmin per bytecode JVM).
Un'implementazione del linguaggio può scegliere un bytecode perché è essenzialmente simile alla maggior parte delle architetture esistenti, anche se più limitate, e quindi più sicuro. È anche molto semplice memorizzare bytecode in un file o scambiarlo altrimenti. La maggior parte delle macchine virtuali esegue bytecode (iniziando dal codice P originale, da CPython alla JVM).
-
altri codici operativi , ad es. strutture dati in memoria come AST. Questi a volte non hanno serializzazione permanente.
Un'implementazione linguistica può scegliere di rappresentare il codice come una struttura dati perché è molto più flessibile (proprio come Lisp è più flessibile di C), e perché rimuove la necessità di decodificare bytecode all'interno della VM - rendendolo più semplice implementare. Questo percorso è molto utile per progetti semplici, ma è anche usato in alcuni interpreti seri come perl
.
In pratica, il confine tra compilatori e interpreti è stato sfocato al di là del riconoscimento, e la maggior parte degli interpreti potrebbe anche essere considerata compilatore perché compilano una rappresentazione intermedia (anche se non è memorizzata da nessuna parte). Le due utili caratteristiche distintive sono:
-
quando la fonte è compilata - prima del tempo, o prima di ogni esecuzione
- qual è il obiettivo di compilazione - codice macchina, una rappresentazione intermedia eseguita da una VM
Alcune implementazioni come le implementazioni Java primarie sfidano categorizzazioni troppo semplici: qui il codice viene compilato in anticipo su un bytecode che viene interpretato su una VM che può anche eseguire la compilazione JIT su codice macchina.