2010-01-09 18 views
41

Quiero propósito de autoeducación implementar una máquina virtual simple para un lenguaje dinámico, preferir en C. Algo como Lua VM, o Parrot, o Python VM, pero más simple. ¿Existen buenos recursos/tutoriales para lograr esto, además de buscar códigos y documentación de diseño de las máquinas virtuales existentes?Tutorial/recurso para implementar VM

Editar: ¿por qué cerrar votar? No entiendo, ¿esto no es programación? Comente si hay un problema específico con mi pregunta.

+2

Si todavía está interesado, escribí una máquina virtual muy simple en C. Eche un vistazo: http://github.com/tekknolagi/carp – tekknolagi

Respuesta

29

Supongo que quiere una máquina virtual en lugar de un mero intérprete. Creo que son dos puntos en un continuo. Un intérprete trabaja en algo cercano a la representación original del programa. Una máquina virtual funciona con instrucciones más primitivas (y autónomas). Esto significa que necesita una etapa de compilación para traducir el uno al otro. No sé si quieres trabajar en eso primero o si aún tienes una sintaxis de entrada en mente.

Para un lenguaje dinámico, desea un lugar que almacene datos (como pares clave/valor) y algunas operaciones que actúen sobre él. La VM mantiene la tienda. El programa que se ejecuta en él es una secuencia de instrucciones (incluido el flujo de control). Debes definir el conjunto de instrucciones. Yo sugeriría un conjunto sencillo para empezar, como:

  • operaciones aritméticas básicas, incluyendo comparaciones aritméticas, acceder al almacén
  • flujo de control básico
  • incorporado en la impresión

Usted Puede que quiera usar un enfoque de cálculo basado en la pila para la aritmética, como lo hacen muchas máquinas virtuales. Todavía no hay mucha dinámica en lo anterior. Para llegar a eso queremos dos cosas: la capacidad de calcular los nombres de las variables en tiempo de ejecución (esto solo significa operaciones de cadena), y algún tratamiento del código como datos. Esto podría ser tan simple como permitir referencias de función.

La entrada a la máquina virtual sería idealmente en bytecode. Si aún no tiene un compilador, esto podría generarse a partir de un ensamblador básico (que podría ser parte de la VM).

La máquina virtual en sí consiste en el bucle:

1. Look at the bytecode instruction pointed to by the instruction pointer. 
2. Execute the instruction: 
    * If it's an arithmetic instruction, update the store accordingly. 
    * If it's control flow, perform the test (if there is one) and set the instruction pointer. 
    * If it's print, print a value from the store. 
3. Advance the instruction pointer to the next instruction. 
4. Repeat from 1. 

Tratar con los nombres de variables calculadas podría ser complicado: una instrucción necesita especificar qué variables los nombres calculados están en Esto se podría hacer al permitir que las instrucciones para hacer referencia. a un conjunto de constantes de cadena proporcionadas en la entrada.

un programa de ejemplo (en el montaje y código de bytes):

offset bytecode (hex) source 
0  01 05 0E   //  LOAD 5, .x 
3  01 03 10   // .l1: LOAD 3, .y 
6  02 0E 10 0E  //  ADD .x, .y, .x 
10  03 0E   //  PRINT .x 
12  04 03   //  GOTO .l1 
14  78 00   //  .x: "x" 
16  79 00   //  .y: "y" 

Los códigos de instrucción implícita son:

"LOAD x, k" (01 x k) Load single byte x as an integer into variable named by string constant at offset k. 
"ADD k1, k2, k3" (02 v1 v2 v3) Add two variables named by string constants k1 and k2 and put the sum in variable named by string constant k3. 
"PRINT k" (03 k) Print variable named by string constant k. 
"GOTO a" (04 a) Go to offset given by byte a. 

Es necesario variantes para cuando las variables son nombrados por otras variables, etc. (y los niveles de indirección son difíciles de razonar). El ensamblador mira los argumentos como "ADD .x, .y, .x" y genera el bytecode correcto para agregar desde las constantes de cadena (y no las variables calculadas).

+0

nice. alguna idea de recurso para ir desde aquí? – zaharpopov

+1

@zaharpopv: No estoy muy seguro sobre la implementación de la funcionalidad dinámica de su idioma, pero un simple diseño de VM como el anterior es bastante fácil, una vez que lo haya hecho, aprenderá qué tan adecuado es y puede darse el lujo de cambiarlo. para admitir características más interesantes. Además, mirar el conjunto de instrucciones para el intérprete de Python puede darte algunas ideas sobre cómo apoyar el dinamismo. – Edmund

9

Bueno, no se trata de implementar una VM en C, pero como era la última pestaña que tenía abierta antes de ver esta pregunta, siento que necesito señalar article about implementing a QBASIC bytecode compiler and virtual machine en JavaScript usando la etiqueta <canvas> para mostrar. Incluye todo el código fuente para obtener lo suficiente de QBASIC implementado para ejecutar el juego "nibbles", y es el primero de una serie de artículos sobre el compilador y el intérprete de códigos de bytes; éste describe la máquina virtual y promete artículos futuros que describen el compilador también.

Por cierto, no voté para cerrar su pregunta, pero el voto cercano que obtuvo fue como un duplicado de question from last year sobre cómo aprender sobre la implementación de una máquina virtual. Creo que esta pregunta (sobre un tutorial o algo relativamente simple) es lo suficientemente diferente de la que debería permanecer abierta, pero es posible que desee consultarla para obtener más información.

4

Otro recurso a considerar es la implementación del Lua language. Es una máquina virtual basada en registro que tiene una buena reputación de rendimiento. El source code está en ANSI C89, y generalmente es muy legible. Como lengua de scripting de alto rendimiento. , y más). El texto de origen se compila en el código de bytes de la VM para su ejecución por una implementación de máquina virtual cuyo contorno es más o menos como se describe en Edmund's answer.

Se ha realizado un gran esfuerzo para mantener la implementación de la máquina virtual tanto portátil como eficiente. Si se necesita aún más rendimiento, existe un just in time compiler del código de bytes de VM a las instrucciones nativas para 32-bit x86, y está en versión beta para 64-bit.

2

Para comenzar (aunque no C, pero C++) usted podría dar un vistazo a muParser.

Es un analizador de expresiones matemáticas que usa una simple máquina virtual para ejecutar operaciones. Creo que incluso tú necesitas tiempo para entender todo; de todos modos, este código es más simple que una VM completa capaz de ejecutar un programa completo real completo. (Por cierto, estoy diseñando un similar lib en C# - es sus primeras etapas, pero las próximas versiones permitirán la compilación de .NET/VM IL o tal vez una nueva máquina virtual simple como muParser).

Otra cosa interesante es NekoVM (ejecuta .n archivos de código de bytes). Es un proyecto de código abierto written in C y se cree que su idioma principal (.neko) es generado por la tecnología source-to-source compiler. En el espíritu del último tema, vea Haxe del mismo autor (código abierto también).

1

Como usted también he estado estudiando máquinas virtuales y compiladores y un buen libro que puedo recomendar es Compiler Design: Virtual Machines. Describe las máquinas virtuales para lenguajes imperativos, funcionales, lógicos y orientados a objetos al proporcionar el conjunto de instrucciones para cada VM junto con un tutorial sobre cómo compilar un lenguaje de alto nivel para esa máquina virtual. Solo he implementado la VM para el lenguaje imperativo y ya ha sido un ejercicio muy útil.

Si recién está empezando, entonces otro recurso que puedo recomendar es PL101. Es un conjunto interactivo de lecciones en JavaScript que lo guía a través del proceso de implementación de analizadores e intérpretes para varios idiomas.