5

He estado programando en Ruby por un tiempo con la implementación estándar de MRI de Ruby, pero siempre he tenido curiosidad sobre las otras implementaciones de las que tanto escucho.¿Cómo se puede interpretar un idioma por sí mismo (como Rubinius)?

Estaba leyendo acerca de Rubinius el otro día, un intérprete de Ruby escrito en Ruby. Intenté buscarlo en varios lugares, pero estaba teniendo dificultades para entender exactamente cómo funciona algo así. Nunca he tenido mucha experiencia en compiladores o en la escritura de idiomas, pero estoy realmente interesado en descubrirlo.

¿Cómo se puede interpretar un idioma por sí mismo? ¿Hay un paso básico en la compilación que no entiendo dónde esto tiene sentido? ¿Puede alguien explicarme esto como si fuera un idiota (porque de todos modos no estaría muy lejos de la base)

Respuesta

8

Es más simple de lo que crees.

Rubinius no está 100% escrito en Ruby, solo en su mayoría.

De http://rubini.us/

Un gran aspecto de lenguajes populares como C y Java es que la mayoría de la funcionalidad disponible para el programador está escrito en el lenguaje mismo. Rubinius tiene el objetivo de agregar Ruby a esa lista. Los rubyists podrían agregar funciones al lenguaje más fácilmente, corregir errores y aprender cómo funciona el lenguaje. Siempre que sea posible Rubinius está escrito en Ruby. Donde no es posible (todavía), es C++.

+0

¿Es esto solo en el caso de Rubinius, o todos los compiladores auto interpretados tienen un poco de otro lenguaje involucrado solo para comenzar? – joeellis

+0

Rubinius no está solo. Creo que la pregunta que hace en el comentario de seguimiento da en un tema más profundo. Por lo tanto, en lugar de responderlo directamente, te señalaría este artículo en wikipedia sobre los compiladores. http://en.wikipedia.org/wiki/Compiler Específicamente, para esta pregunta, eche un vistazo a las secciones "Compilación" y "Salida del compilador". – jefflunt

1

Supongamos que el idioma en el que está trabajando es un lenguaje, por ejemplo Lisp, aunque no importa. (Podría ser C++, Java, Ruby, cualquier cosa.)

Bueno, usted tiene una implementación de Lisp. Llame a esta implementación Imp (solo algunos nombres inventados para IMPlementation). Como Imp es un programa en sí mismo, su computadora puede ejecutarlo. Ahora escribe su propia implementación para Lisp escrita en Lisp y lo llama Circ. Circ es solo un programa compilado (o interpretado si se quiere) a partir del código Lisp. Su código está escrito para que se lea en un archivo, lo analice (lo procese en datos significativos) y haga algo con los datos. ¿Qué es esto? En el caso de Circ, ejecuta los datos.

Pero, ¿cómo lo hace?

Bueno, supongamos que para un caso simple que el código Circ lee y analiza es algo simple como hacer algunas operaciones matemáticas y sacar el resultado. Circ procesa el código en datos fáciles de usar (bueno para un lenguaje como Lisp, es fácil comenzar, pero eso está más allá del punto) y lo almacena. Bueno, en Lisp puedes escribir código para contrastar números, por lo que el código escrito para Circ puede hacerlo también porque está escrito en Lisp. Entonces, los datos procesados ​​se conectan a algún código de procesamiento adicional ... ¡y listo! ¡Tienes el resultado numérico! Entonces su programa Circ da como resultado el resultado.

Lo mismo se puede hacer con cosas más complejas que las matemáticas simples. De hecho, puede compilar/interpretar otros aspectos del lenguaje. Escribe suficiente de estos "otros aspectos" y pégalos, obtendrás un compilador de Lisp escrito en Lisp.

Como el compilador es compilado por Imp, puede ser ejecutado por su máquina, ¡y listo! Estás listo.

+0

Creo que te estás perdiendo el punto un poco. Sí, si imp es un compilador, puedo compilar otro compilador y el usuario puede ejecutarlo en su máquina (aunque si los programas imp-compiled requieren algún entorno de ejecución, los usuarios del circ-compiler también necesitarían instalar el imp-runtime) . Sin embargo, si imp y circ son intérpretes, cualquiera que quiera usar el circ-intérprete tendría que instalar el imp-intérprete primero y luego ejecutar sus aplicaciones lisp usando imp para interpretar circ y circ para interpretar la aplicación. Si este fuera el caso de Rubinius nadie lo usaría. – sepp2k

+0

Oh, ya veo. Pensé que el OP estaba haciendo una pregunta ligeramente diferente. –

2

En el caso de Rubinius, la VM está escrita en C++ y se ocupa de todas las operaciones básicas y de bajo nivel (relacionadas con el sistema operativo). La máquina virtual tiene su propio formato de código de bytes (como la JVM también tiene la suya) y cuando se inicia Rubinius, inicia la máquina virtual que ejecuta el código de bytes. La mayor parte de la biblioteca estándar de Rubinius (que es parte del lenguaje de Ruby) se implementa en Ruby sin embargo, en comparación con C (MRI) o Java (JRuby). Además, el compilador de códigos de bytes Rubinius también está escrito en Ruby. Así que sí, en algún momento al principio del principio tuvieron que usar el intérprete Ruby (MRI) estándar para arrancar Rubinius. Pero este no debería ser el caso más (aunque no estoy seguro de si aún puede necesitarlo ya que su sistema de compilación usa rastrillo).

4

El concepto que está buscando es compilador de arranque.

medios Básicamente bootstrapping escribir un compilador (o un intérprete) para el lenguaje x en lenguaje x. Esto se hace escribiendo un compilador básico en un nivel inferior a mano (es decir, escribiendo un compilador de C en ensamblado) o utilizando un lenguaje de alto nivel diferente.

Más información sobre bootstrapping en wikipedia. También se recomienda encarecidamente la respuesta de Greg con respecto a los evaluadores metacirculares, incluido el capítulo correspondiente del SICP.

Cuestiones relacionadas