Crea tu propio lenguaje de programación (I)

La evolución de los lenguajes de programación

Después de escribir el primer artículo sobre cómo crear tu propio sistema operativo, alguien me dijo que si podía hacer un artículo sobre cómo crear un lenguaje de programación. Al principio no hice mucho caso, pero ahora y por otros caminos he aprendido bastante más sobre la creación de los lenguajes de programación. Así pues, vamos a hacer un lenguaje de programación básico, fácilmente empotrable en otros programas y que funcione con una máquina virtual que también diseñaremos. Hoy nos toca hacer la máquina virtual más básica.

Probablemente te preguntes: «¿una máquina virtual? ¿Pero eso no es muy difícil y además ralentiza los programas?» Al contrario, una máquina virtual simple es muy sencilla y relativamente rápida. He elegido Rust como lenguaje para la máquina virtual. Pero, ¿qué es Rust?

Rust es un lenguaje de programación que está enfocado en la seguridad en las ejecuciones, así que utilizándolo será prácticamente imposible que alguien consiga cerrar la máquina virtual. Es un lenguaje compilado en desarrollo creado por Mozilla. Servo, el sustituto de Gecko, se está desarrollando en él. Todavía puede cambiar su sintaxis pero el código que voy a usar va a mantenerse hasta la primera versión estable.

Rust se instala en Linux de manera sencilla. Sin embargo, no hay paquetería oficial. Los usuarios de Ubuntu pueden agregar estos dos PPA: ppa:hansjorg/rust  y ppa:cmrx64/cargo, los usuarios de Arch pueden usar AUR (cargo-git es el paquete que instala todo). El resto pueden usar:

curl -s https://static.rust-lang.org/rustup.sh | sudo sh

¿Cómo funciona una máquina virtual?

Si sabes como funciona el mundo en ensamblador es exactamente igual, con el stack o la pila. Si no, te lo explico. Imaginémonos el siguiente código:

print 2+3

El ordenador no entiende lo que significa 2+3, ni tampoco sabe qué orden hay que seguir. Los ordenadores funcionan con pilas o stacks en los que se van acumulando datos y se van sacando continuamente. Ese código en nuestra máquina virtual debería ser algo parecido a esto:

PUSH 2
PUSH 3
ADD
PRINT

Básicamente, pondríamos el 2 en la pila en lo alto, el 3 también. ADD sacaría (es decir, lo elimina de la pila y obtiene su valor) los 2 últimos elementos de la pila y añadiría el resultado en lo alto de la pila. PRINT cogería el último elemento de la pila y lo usaría para mostrárnoslo. Ahora hagamos eso en Rust.

Primeramente deberemos definir un lenguaje para el Bytecode, podríamos usar uno ya existente como el de Java o el CLR de .NET/Mono, pero vamos a crear nosotros uno más básico.

https://gist.github.com/a01de8904fd39a442c20

Usamos notación hexadecimal para cada instrucción. En lo alto hemos puesto #[deriving(FromPrimitive)], es una particularidad de Rust y nos servirá para más tarde poder comparar la enumeración con bytes directamente.

Ahora debemos hacer una función que ejecute cada una de esas instrucciones. Para ello debemos leer un byte y compararlo con las instrucciones que tenemos en la enumeración. Si se encuentra alguna que exista se debe ejecutar su acción.

https://gist.github.com/8950ce212a2de2f397f9

Eso hacemos para leer cada byte individualmente y para ejecutarlas:

https://gist.github.com/12e24a1f0dd65e4cd65d

Como vén, diferenciamos si antes se nos dio la orden de PUSH (nuestra orden INTEGER), el siguiente byte será llevado completamente a la pila. Ahí estamos usando dos funciones que no les he enseñado, self.pop() y self.push(), que se encargan obviamente de manejar el stack.

https://gist.github.com/54147f853a8a2b8c01d9

No son muy complejas, pero la función de pop tiene mecanismos de detección de errores. De hecho, en Rust, si quitásemos esos mecanismos nos daría un error de compilación. Ahora simplemente debemos llamar en un programa a Perin (nuestra máquina virtual) y que ejecute un bytecode.

https://gist.github.com/99b1ab461318b3a644d0

Ese bytecode puede ser leído de un fichero, pero aquí para simplificar lo he almacenado en una variable. Si lo ejecutamos nos dará el resultado esperado:

Perin v0.1
Perin VM executes FlopFlip bytecode
Starting PerinVM instance
PerinVM v0.1.0
Integer value 5

Todo el código está disponible en GitHub bajo la Apache License 2.0: https://github.com/AdrianArroyoCalle/perin. Para compilar deben tener Cargo instalado y poner:

cargo build && ./target/main

En el siguiente capítulo veremos más sobre nuestro lenguaje de programación.


17 comentarios, deja el tuyo

Deja tu comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

*

  1. Responsable de los datos: Miguel Ángel Gatón
  2. Finalidad de los datos: Controlar el SPAM, gestión de comentarios.
  3. Legitimación: Tu consentimiento
  4. Comunicación de los datos: No se comunicarán los datos a terceros salvo por obligación legal.
  5. Almacenamiento de los datos: Base de datos alojada en Occentus Networks (UE)
  6. Derechos: En cualquier momento puedes limitar, recuperar y borrar tu información.

  1.   roader dijo

    Interesante curiosidad , aunque no sea muy util en realidad , no esta de mas saberlo .

    Es genial que le hagas publicidad a Rust , es un lenguaje que promete mucho no solo es mas seguro que c++ , sino que (de momento) mas claro en su sintaxis .

    En cuanto a foto , yo no consideraria java evolución XD.

    1.    roader dijo

      Y de fortran , nunca lo use , pero no he oido muchas cosas buenas de el …

      1.    Phorious dijo

        Yo sí, y es especialmente útil en ingeniería si bien Python se está abriendo lugar.

      2.    juan dijo

        Fortran es quizás el otro gran lenguaje junto con C. Todavía hoy en cuestiones realmente críticas estarán uno u otro.

        Y resultaría discutible que Fortran esté como ‘evolución’ de C, cuando quizás debería ser al revés, por ser C más nuevo, moderno y con más posibilidades; aunque uno no se desprende del otro en lo más mínimo.

        Aunque los puestos finales todos son discutibles desde algún punto de vista.

    2.    Francisco dijo

      +1 a lo de Java

  2.   portaro dijo

    A ver si me gusta esto que le doy algo a la programación pero básico a ver si entiendo más.

  3.   usergnulinux dijo

    ¿Cual proposito realmente tiene crear un lenguaje de programación nuevo?, a mi personalmente me parece que es una estratagema para ocultar el codigo fuente.

  4.   Yeily dijo

    Amigo que pasó con la continuación de «tu propio sistema operativo»? No lo dejes ahí por favor, continúalo.

    En realidad que eres un master y justo estos dos temas han cautivado por completo mi atención, mas no quisiera que se quedaran a medio camino.

    Se que muchos pensamos igual y estamos a la espera de las continuaciones y conclusiones de estos interesantísimos temas.

  5.   Cristian David dijo

    Muy interesante, muchas gracias. 🙂

  6.   Franco dijo

    Yo no considero a java un lenguaje de programación, mas bien un interpretador de ordenes, ya que no es compilable

    1.    Mario dijo

      [Un lenguaje de programación es un lenguaje formal diseñado para expresar procesos que pueden ser llevados a cabo por máquinas como las computadoras.]

      Por esto mismo, Java es un lenguaje de programación. Incluso el lenguaje Bash (lenguaje para el intérprete de comandos de linux) es un lenguaje de programación en si mismo.

      Hay dos tipos de lenguajes:
      – Compilados
      – Interpretados
      – Mixtos (Máquinas virtuales, se compilan las librerías nativas y se interpreta el código funcional)

      Los intérpretes son muy útiles a la hora de la multiplataforma y no por ello tienen un rendimiento nefasto. Java, VB.NET, C++ .NET, F#, C# son todos lenguajes mixtos. El lenguaje bash, bat, PHP, Javascript y muchos más son lenguajes interpretados.

      Si no consideras Java como lenguaje porque es interpretado (cosa que no es así) no deberías considerar otros muchos lenguajes que se utilizan para hacer programas. Es más, por esa regla de tres no deberías considerar que existe ningún lenguaje de programación a excepción del propio lenguaje máquina.

      Y, ¿por qué no?, ni siquiera el lenguaje máquina podría ser considerado lenguaje ya que realmente solo es un conjunto de órdenes «interpretadas» por el procesador.

      Porque efectivamente, TODOS los lenguajes no son más que un conjunto órdenes que se interpretan en un procesador.

      Te puede gustar más o menos un lenguaje (Java, en este caso), parecerte más o menos útil y potente pero decir que no es un lenguaje de programación porque no es compilado… va en contra de todas las definiciones de lenguaje de programación.

    2.    Mario dijo

      😐 Espero no haber parecido muy brusco

      1.    maria antonieta de manuela cardenas dijo

        no tranquilo solo nos destruiste la vida

      2.    Mario dijo

        jjajajajaja, perdoooon. no era mi intención xD

    3.    carlos dijo

      java es un lenguaje de programacion. porque podes desarrollar una aplicacion y cuando compilas haces un .jar que es interpretado por laJVM.entonces segun tu logica python tampoco porq es iterpretado pero se compila a diferentes ejecutables…

  7.   Elias Mongelos dijo

    Muy buena información

  8.   carlos Arturo dijo

    buena información pero tengo una duda, será posible crea un nuevo lenguaje de programación desde cero sin tener que depender de otras analogías o software. hablo de la misma forma en la que se otros lenguajes fueron hechos como java o el HTML.
    agradecería mucho su ayuda en esta duda.