¿Un intérprete produce un código de máquina?

42

Estudio intensivamente los temas de compiladores e intérpretes. Quiero verificar si mi comprensión básica es correcta, por lo que asumamos lo siguiente:

Tengo un lenguaje 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;

Hello 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 el camino de la implementación del intérprete.

¿Un compilador creará 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 un compilador lo hace para su entrada?

¿Tengo algún malentendido en la forma básica en que funcionan los compiladores e intérpretes?

    
pregunta GrayFox 22.10.2015 - 19:35

6 respuestas

79

Los términos "intérprete" y "compilador" son mucho más confusos de lo que solían ser. Hace muchos años era más común que los compiladores produjeran un código de máquina para ejecutarse más tarde, mientras que los intérpretes "ejecutaban" el código fuente directamente. Así que esos dos términos fueron bien entendidos en aquel entonces.

Pero hoy en día hay muchas variaciones en el uso de "compilador" y "intérprete". Por ejemplo, VB6 "compila" en código de byte (una forma de Intermediate Language ), que luego es "interpretado" por el VB Runtime. Un proceso similar tiene lugar en C #, que produce CIL que luego se ejecuta mediante un Just-In-Time Compiler (JIT) que, en los viejos tiempos, se habría pensado como un intérprete. Puede "secar por congelación" la salida del JIT en un ejecutable binario real utilizando NGen.exe , cuyo producto hubiera sido el resultado de un compilador en los viejos tiempos.

Entonces, la respuesta a tu pregunta no es tan sencilla como lo fue una vez.

Lecturas adicionales
Compiladores contra intérpretes en Wikipedia

    
respondido por el Robert Harvey 22.10.2015 - 20:10
35

El resumen que doy a continuación se basa en "Compiladores, Principios, Técnicas y Herramientas", Aho, Lam, Sethi, Ullman, (Edición Internacional Pearson, 2007), páginas 1, 2, con algunas ideas adicionales. de mi propia.

Los dos mecanismos básicos para procesar un programa son compilación e interpretación .

La compilación toma como entrada un programa de origen en un idioma determinado y genera un programa de destino en un idioma de destino.

source program --> | compiler | --> target program

Si el idioma de destino es el código de máquina, puede ejecutarse directamente en algún procesador:

input --> | target program | --> output

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

source program, input --> | interpreter | --> output

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 utilizan una combinación de los dos enfoques. Por ejemplo, los programas de Java se traducen (compilan) por primera vez en un programa intermedio (código de bytes):

source program --> | translator | --> intermediate program

la salida de este paso es ejecutada (interpretada) por una máquina virtual:

intermediate program + input --> | virtual machine | --> output

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 en otro formato, que luego se ejecuta.

Además, incluso cuando compila en lenguaje de máquina, hay un intérprete ejecutando su archivo binario que es implementado por 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 los dos, por lo que es difícil decir si un procesador de lenguaje dado es un compilador o un intérprete, porque probablemente utilizará ambos mecanismos en diferentes etapas de su procesamiento. En este caso, probablemente sería más apropiado utilizar 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 a las preguntas iniciales.

  

Un compilador crearía un lenguaje de máquina que se ejecute en el físico   hardware directamente?

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.

  

Por lo tanto, un intérprete no produce lenguaje de máquina, pero sí un compilador   ¿Para su entrada?

Si al producir se refiere a la salida, entonces un compilador produce un programa objetivo que puede estar en lenguaje de máquina, un intérprete no.

    
respondido por el Giorgio 22.10.2015 - 23:05
22
  

Un compilador crearía lenguaje de máquina

No. Un compilador es simplemente un programa que toma como entrada un programa escrito en el lenguaje A y produce como salida un programa semánticamente equivalente en el lenguaje B . El idioma B puede ser cualquier cosa, no tiene por qué ser el lenguaje de máquina.

Un compilador puede compilar de un lenguaje de alto nivel a otro lenguaje de alto nivel (por ejemplo, GWT, que compila Java a ECMAScript), de un lenguaje de alto nivel a un lenguaje de bajo nivel (por ejemplo, Gambit, que compila Esquema a C), desde un lenguaje de alto nivel a código de máquina (por ejemplo, GCJ, que compila Java a código nativo), desde 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), desde un lenguaje de bajo nivel a otro lenguaje de bajo nivel (por ejemplo, el SDK de Android, que compila el bytecode JVML hasta el bytecode Dalvik), desde un lenguaje de bajo nivel hasta código de máquina (por ejemplo, el compilador C1X que forma parte de HotSpot, que compila el código de bytes JVML en el código de la máquina), el código de la máquina en un lenguaje de alto nivel (cualquier "decompilador", también Emscripten, que compila el código de la máquina LLVM en ECMAScript), el código de la máquina en el lenguaje de bajo nivel (por ejemplo, el compilador JIT en JPC, que compila el código nativo x86 a código de bytes JVML) y el código nativo a código nativo (por ejemplo, El compilador JIT en PearPC, que compila el código nativo de 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 uno sea un "código de máquina nativo" pero no el otro? Además, cada idioma es el código de una máquina abstracta para ese idioma.

Hay muchos nombres especializados para compiladores que realizan funciones especiales. A pesar de que estos son nombres especializados, todos estos son todavía compiladores, solo tipos especiales de compiladores:

  • si se percibe que el lenguaje A se encuentra aproximadamente en el mismo nivel de abstracción que el lenguaje B , el compilador podría llamarse transpiler ( por ejemplo, un transpiler de Ruby a ECMAScript o un transpiler de ECMAScript2015 a ECMAScript 5)
  • si se percibe que el lenguaje A se encuentra en un nivel de abstracción más bajo que el del lenguaje B , el compilador podría denominarse decompiler ( por ejemplo, un x86-machine-code-to-C-decompiler)
  • si el idioma es A == idioma B , el compilador podría llamarse optimizador , ofuscador o minifier (dependiendo de la función particular del compilador)
  

¿Qué se ejecuta directamente en el hardware físico?

No necesariamente. Se puede ejecutar en un intérprete o en una máquina virtual. Se podría compilar en otro idioma.

  

¿Entonces un intérprete no produce lenguaje de máquina pero un compilador lo hace para su entrada?

Un intérprete no produce nada. Simplemente ejecuta el programa.

Un compilador produce algo, pero no necesariamente tiene que ser un 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 optimizada como salida. Hay muchos compiladores ECMAScript que toman ECMAScript como sus entradas y producen ECMAScript optimizado, minificado y ofuscado como su salida.

También te puede interesar:

respondido por el Jörg W Mittag 23.10.2015 - 09:23
15

Creo que deberías dejar de lado la noción de "compilador versus intérprete" en su totalidad, porque es una falsa dicotomía.

  • Un compilador es un transformador : transforma un programa de computadora escrito en un idioma de origen y genera un equivalente en un objetivo idioma . Por lo general, el idioma de origen es más alto que el idioma de destino, y si es al revés, a menudo llamamos a ese tipo de transformador un descompilador .
  • Un intérprete es un motor de ejecución . Ejecuta un programa de computadora escrito en un lenguaje, de acuerdo con la especificación de ese lenguaje. Principalmente usamos el término para software (pero de alguna manera, una CPU clásica puede verse como un "intérprete" basado en hardware para su código de máquina).

La palabra colectiva para hacer que un lenguaje de programación abstracto sea útil en el mundo real es implementación .

En el pasado, una implementación de lenguaje de programación a menudo consistía en solo un compilador (y la CPU para la que generaba el código) o solo un intérprete, por lo que puede haber sido como estos dos tipos de herramientas son mutuamente excluyentes. Hoy, se puede ver claramente que este no es el caso (y nunca fue para empezar). Tomar una implementación sofisticada de lenguaje de programación y tratar de empujar el nombre "compilador" o "intérprete" a él, a menudo lo llevará a resultados no concluyentes o inconsistentes.

Una implementación de un solo lenguaje de programación puede involucrar a cualquier número de compiladores e intérpretes , a menudo en múltiples formas (independiente, sobre la marcha), cualquier número de otras herramientas, como analizadores estáticos y optimizadores , y cualquier número de pasos. Incluso puede incluir implementaciones completas de cualquier número de lenguajes intermedios (que pueden no estar relacionados con el que se está implementando).

Ejemplos de esquemas de implementación incluyen:

  • Un compilador de C que transforma el código de máquina de C a x86 y una CPU x86 que ejecuta ese código.
  • Un compilador C que transforma C en LLVM IR, un compilador backend LLVM que transforma LLVM IR en código de máquina x86 y una CPU x86 que ejecuta ese código.
  • Un compilador de C que transforma C en LLVM IR y un intérprete de LLVM que ejecuta LLVM IR.
  • Un compilador de Java que transforma Java en un bytecode JVM y un JRE con un intérprete que ejecuta ese código.
  • Un compilador Java que transforma Java en código de bytes JVM, y un JRE con un intérprete que ejecuta algunas partes de ese código y un compilador que transforma otras partes de ese código en código de máquina x86, y una CPU x86 que ejecuta ese código .
  • Un compilador Java que transforma Java en un bytecode JVM y una CPU ARM que ejecuta ese código.
  • Un compilador de C # que transforma C # en CIL, un CLR con un compilador que transforma CIL en código de máquina x86 y una CPU x86 que ejecuta ese código.
  • Un intérprete de Ruby que ejecuta Ruby.
  • Un entorno Ruby con un intérprete que ejecuta Ruby y un compilador que transforma Ruby en un código de máquina x86, y una CPU x86 que ejecuta ese código.

... y así sucesivamente.

    
respondido por el Theodoros Chatzigiannakis 23.10.2015 - 14:04
7

Si bien las líneas entre compiladores e intérpretes se han ido borrando con el tiempo, aún se puede trazar una línea entre ellos 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 (normalmente en un lenguaje de nivel inferior como el código de máquina) que, si se ejecuta ese programa, hará lo que su programa debería hacer.

Un intérprete hará lo que su programa debe hacer.

Con estas definiciones, los lugares donde se vuelve borroso son los casos en los que se puede pensar que su compilador / intérprete hace cosas diferentes según cómo se mire. Por ejemplo, Python toma su código de Python y lo compila en un código de bytes de Python compilado. Si este bytecode de Python se ejecuta a través de un bytecode intérprete 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 eligen pensar en el CPython intérprete como interpretando 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.

    
respondido por el Cort Ammon 23.10.2015 - 01:50
6

Aquí hay una simple desambiguación conceptual entre compiladores e intérpretes.

Considere 3 idiomas: programación lenguaje, P (en qué está escrito el programa); dominio idioma, D (para lo que sucede con el programa en ejecución); y el idioma de destino , T (un tercer idioma).

Conceptualmente,

  • un compilador traduce P a T para que pueda evaluar T (D); mientras que

  • un intérprete evalúa P (D) directamente.

respondido por el Lawrence 22.10.2015 - 22:09

Lea otras preguntas en las etiquetas