Estudio los temas de compiladores e intérpretes intensivamente. Quiero verificar si mi comprensión básica es correcta, así que supongamos lo siguiente:
Tengo un idioma llamado "Foobish" y sus palabras clave son
<OUTPUT> 'TEXT', <Number_of_Repeats>;
Entonces, si quiero imprimir en la consola 10 veces, escribiría
OUTPUT 'Hello World', 10;
Hola World.foobish-file.
Ahora escribo un intérprete en el idioma de mi elección: C # en este caso:
using System;
namespace FoobishInterpreter
{
internal class Program
{
private static void Main(string[] args)
{
analyseAndTokenize(Hello World.foobish-file)//Pseudocode
int repeats = Token[1];
string outputString = Token[0];
for (var i = 0; i < repeats; i++)
{
Console.WriteLine(outputString);
}
}
}
}
En un nivel de intérprete muy fácil, el intérprete analizaría el archivo de script, etc. y ejecutaría el lenguaje foobish en la forma de la implementación del intérprete.
¿Un compilador crearía un lenguaje de máquina que se ejecute directamente en el hardware físico?
Entonces, un intérprete no produce lenguaje de máquina, pero ¿lo hace un compilador para su entrada?
¿Tengo algún malentendido en la forma básica de cómo funcionan los compiladores y los intérpretes?
fuente
Respuestas:
Los términos "intérprete" y "compilador" son mucho más difusos de lo que solían ser. Hace muchos años, era más común que los compiladores produjeran código de máquina para ejecutarlo más tarde, mientras que los intérpretes más o menos "ejecutaban" el código fuente directamente. Entonces esos dos términos se entendieron bien en ese entonces.
Pero hoy hay muchas variaciones en el uso de "compilador" e "intérprete". Por ejemplo, VB6 "compila" en código de bytes (una forma de lenguaje intermedio ), que luego es "interpretado" por el tiempo de ejecución de VB. Un proceso similar tiene lugar en C #, que produce CIL que luego es ejecutado por un compilador Just-In-Time (JIT) que, en los viejos tiempos, habría sido considerado como un intérprete. Puede "liofilizar" la salida del JIT en un ejecutable binario real utilizando NGen.exe , cuyo producto habría sido el resultado de un compilador en los viejos tiempos.
Por lo tanto, la respuesta a su pregunta no es tan sencilla como lo era antes.
Lecturas adicionales
Compiladores vs. Intérpretes en Wikipedia
fuente
El resumen que doy a continuación se basa en "Compiladores, principios, técnicas y herramientas", Aho, Lam, Sethi, Ullman, (Pearson International Edition, 2007), páginas 1, 2, con la adición de algunas ideas propias.
Los dos mecanismos básicos para procesar un programa son la compilación y la interpretación .
La compilación toma como entrada un programa fuente en un idioma dado y genera un programa objetivo en un idioma objetivo.
Si el idioma de destino es el código de máquina, se puede ejecutar directamente en algún procesador:
La compilación implica escanear y traducir todo el programa de entrada (o módulo) y no implica ejecutarlo.
La interpretación toma como entrada el programa fuente y su entrada, y produce la salida del programa fuente.
La interpretación generalmente implica procesar (analizar y ejecutar) el programa una declaración a la vez.
En la práctica, muchos procesadores de lenguaje usan una combinación de los dos enfoques. Por ejemplo, los programas Java se traducen primero (compilan) en un programa intermedio (código de bytes):
La salida de este paso es ejecutada (interpretada) por una máquina virtual:
Para complicar aún más las cosas, la JVM puede realizar una compilación justo a tiempo en tiempo de ejecución para convertir el código de bytes a otro formato, que luego se ejecuta.
Además, incluso cuando compila en lenguaje máquina, hay un intérprete que ejecuta su archivo binario que implementa el procesador subyacente. Por lo tanto, incluso en este caso está utilizando un híbrido de compilación + interpretación.
Por lo tanto, los sistemas reales usan una combinación de ambos, por lo que es difícil decir si un procesador de lenguaje dado es un compilador o un intérprete, porque probablemente usará ambos mecanismos en diferentes etapas de su procesamiento. En este caso, probablemente sería más apropiado usar otro término más neutral.
Sin embargo, la compilación y la interpretación son dos tipos distintos de procesamiento, como se describe en los diagramas anteriores,
Para responder las preguntas iniciales.
No necesariamente, un compilador traduce un programa escrito para una máquina M1 a un programa equivalente escrito para una máquina M2. La máquina de destino puede implementarse en hardware o ser una máquina virtual. Conceptualmente no hay diferencia. El punto importante es que un compilador mira un fragmento de código y lo traduce a otro idioma sin ejecutarlo.
Si al producir se está refiriendo a la salida, un compilador produce un programa de destino que puede estar en lenguaje de máquina, un intérprete no.
fuente
defined A && !defined B
.No. Un compilador es simplemente un programa que toma como entrada un programa escrito en un lenguaje A y produce como salida un programa semánticamente equivalente en el lenguaje B . El lenguaje B puede ser cualquier cosa, no tiene que ser lenguaje de máquina.
Un compilador puede compilar desde un lenguaje de alto nivel a otro lenguaje de alto nivel (por ejemplo, GWT, que compila Java a ECMAScript), desde un lenguaje de alto nivel a un lenguaje de bajo nivel (por ejemplo, Gambit, que compila Scheme a C), de un lenguaje de alto nivel a código de máquina (por ejemplo, GCJ, que compila Java a código nativo), de un lenguaje de bajo nivel a un lenguaje de alto nivel (por ejemplo, Clue, que compila C a Java, Lua, Perl, ECMAScript y Common Lisp), de un lenguaje de bajo nivel a otro lenguaje de bajo nivel (por ejemplo, el SDK de Android, que compila el código de bytes JVML al código de bytes Dalvik), de un lenguaje de bajo nivel a código de máquina (por ejemplo, el compilador C1X que es parte de HotSpot, que compila el código de bytes JVML al código de máquina), el código de máquina a un lenguaje de alto nivel (cualquier llamado "descompilador", también Emscripten, que compila el código de máquina LLVM a ECMAScript),código de máquina a lenguaje de bajo nivel (por ejemplo, el compilador JIT en JPC, que compila código nativo x86 a código de bytes JVML) y código nativo a código nativo (por ejemplo, el compilador JIT en PearPC, que compila código nativo PowerPC a código nativo x86).
Tenga en cuenta también que "código de máquina" es un término muy difuso por varias razones. Por ejemplo, hay CPU que ejecutan de forma nativa el código de bytes JVM, y hay intérpretes de software para el código de máquina x86. Entonces, ¿qué hace que un "código máquina nativo" pero no el otro? Además, cada idioma es código para una máquina abstracta para ese idioma.
Hay muchos nombres especializados para compiladores que realizan funciones especiales. A pesar del hecho de que estos son nombres especializados, todos estos todavía son compiladores, solo tipos especiales de compiladores:
No necesariamente. Se puede ejecutar en un intérprete o en una máquina virtual. Podría compilarse en un idioma diferente.
Un intérprete no produce nada. Simplemente ejecuta el programa.
Un compilador produce algo, pero no necesariamente tiene que ser lenguaje de máquina, puede ser cualquier lenguaje. ¡Incluso puede ser el mismo idioma que el idioma de entrada! Por ejemplo, Supercompilers, LLC tiene un compilador que toma Java como entrada y produce Java optimizado como salida. Hay muchos compiladores de ECMAScript que toman ECMAScript como sus entradas y producen ECMAScript optimizado, minimizado y ofuscado como su salida.
Usted también podría estar interesado en:
fuente
Creo que deberías descartar por completo la noción de "compilador versus intérprete", porque es una falsa dicotomía.
La palabra colectiva para hacer que un lenguaje de programación abstracto sea útil en el mundo real es implementación .
En el pasado, la implementación de un lenguaje de programación a menudo consistía solo en un compilador (y la CPU para la que generó el código) o simplemente un intérprete, por lo que puede parecer que estos dos tipos de herramientas son mutuamente excluyentes. Hoy, puedes ver claramente que este no es el caso (y nunca fue para empezar). Adoptar una implementación sofisticada de lenguaje de programación e intentar introducir el nombre de "compilador" o "intérprete", a menudo lo llevará a resultados inconclusos o inconsistentes.
Una implementación de lenguaje de programación único puede involucrar cualquier número de compiladores e intérpretes , a menudo en múltiples formas (independientes, sobre la marcha), cualquier cantidad de otras herramientas, como analizadores y optimizadores estáticos , y cualquier cantidad de pasos. Incluso puede incluir implementaciones completas de cualquier cantidad de idiomas intermedios (que pueden no estar relacionados con el que se está implementando).
Los ejemplos de esquemas de implementación incluyen:
...y así.
fuente
Si bien las líneas entre los compiladores y los intérpretes se han vuelto borrosas con el tiempo, aún se puede trazar una línea entre ellas al observar la semántica de lo que debe hacer el programa y lo que hace el compilador / intérprete.
Un compilador generará otro programa (generalmente en un lenguaje de nivel inferior como el código de máquina) que, si ese programa se ejecuta, hará lo que su programa debería hacer.
Un intérprete hará lo que su programa debería hacer.
Con estas definiciones, los lugares donde se vuelve borroso son los casos en que se puede pensar que su compilador / intérprete hace cosas diferentes dependiendo de cómo lo mire. Por ejemplo, Python toma su código de Python y lo compila en un bytecode de Python compilado. Si este código de bytes de Python se ejecuta a través de un intérprete de código de bytes de Python , hace lo que su programa debía hacer. Sin embargo, en la mayoría de las situaciones, los desarrolladores de Python piensan que ambos pasos se realizan en un gran paso, por lo que optan por pensar que el intérprete de CPython interpreta su código fuente, y el hecho de que se compiló en el camino se considera un detalle de implementación . De esta manera, todo es cuestión de perspectiva.
fuente
Aquí hay una simple desambiguación conceptual entre compiladores e intérpretes.
Considere 3 idiomas: lenguaje de programación , P (en qué está escrito el programa); lenguaje de dominio , D (para lo que sucede con el programa en ejecución); y idioma de destino , T (algún tercer idioma).
Conceptualmente
un compilador traduce P a T para que pueda evaluar T (D); mientras
Un intérprete evalúa P (D) directamente.
fuente