sábado, 23 de abril de 2011

Aprendiendo a hacer un lenguaje de programación III: Definiendo Plancton

Con GOTO  ya hemos visto lo mínimo que se despacha y en su día enumeré los cinco elementos que voy a incluir en Plancton pero no van a ser los únicos, también caerán el proto-polimorfismo y la proto-encapsulación, que más tarde definiré. 

Últimamente ando muy pendiente de mi proyecto de final de carrera y estoy asqueado con C y C++. Un petardazo con un puntero a null y ponte a buscar donde petardea. El problema es que tienes que estar muy sobrio para encontrar el error, tambien mi C/C++ es una basura y estoy manejando un API (OpenCV) que jamás había usado antes, continuamente ves que el código esta bien escrito y es cierto pero una mala inicialización hace que todo se vaya al garete y pierdas un buen rato intentando averiguar que coño pasa. La mejor solución para estos problemas son las excepciones con sus bellísimos stacktrace. Si quiero que mi lenguaje sea fácil de programar, tengo que hacer fácil la depuración de errores cuando uno se ha tomado 3 o 4 cervezas con lo que habrá en mi lenguaje excepciones. 

Empecemos a definir nuestro lenguaje de programación

Tipos de datos:

En las variables es donde se almacenan las cosas, básicamente necesitamos guardar numeros y textos. Con lo que vamos a tener 2 tipos de datos a los que llamaré num y text. Qué importancia tiene definir tipos.
Al definir un tipo estamos definiendo que datos entran en esa variable y que operaciones vamos a hacer con élla por ejemplo no es lo mismo sumar dos números que dos textos, en el segundo tipo de datos se hace una concatenación. 
También habrán estructuras de datos en las que se guardará por ejemplo la información de un dni con lo que internamente tendrán text, num y otras estructuras, el usuario tendrá que definirlas con la palabra struct antes de usarlas por ejemplo voy a definir la estructura fecha y dni. 

struct fecha{
    num dia;
    num mes;
    num año;
} 

struct dni{
    num id;
    text nombre;
    text apellido1;
    text apellido2;
    fecha nacimiento;
}

Después si se quiere acceder a los campos se hace de la siguiente forma en fecha mi_fecha.dia. Si queremos acceder al año del dni sería mi_dni.nacimiento.año.
En las estructuras también implementaré herencia que ya explicaré mas adelante y por supesto todos los tipos de datos tendrán sus respectivas operaciones habituales.
No se permiten variables globales, todas tendrán que estar dentro de una función y la definición del tipo tendrá que estar fuera de las funciones.

Estructuras de control selectivas:

Sirven para "decidir un camino" si se cumple una condición lógica usaré el clásico if(), else if(), else nada más para no liar al personal. Por ejemplo:
Si mi variable es igual a 3, imprime "hola" si es mayor que 3, imprime "adios" y en otro caso imprime "tu puta madre". 

if(X=3){
    print("hola");
} else if(X>3){
    print("adios");
} else {
    print("tu puta madre");
}

Otro ejemplo: Si mi variable multiplicada por 2 y divida por 4 vale 0, imprimir "hola que tal", en otro caso imprimo "ja, no" y a mi variable le sumo 2 y se lo asigno a ella misma. 

if(X*2/4){
    print("hola que tal");
}else{
    print("ja, no");
    X=X+2;
}

También se puede usar solo la sentencia if o la sentencia if con else if.

Estructuras de control repetitivas:

Estos son los bucles, hago continuamente una serie de operaciones varias veces mientras se cumple una condición, cuando se rompe la condición continuo por fuera del bucle. Para los bucles solo usaré el while(){}
por ejemplo mientras x sea menor que y imprimo "tu puta madre". 

while(X<Y){
     print("tu puta madre");
     X=X+1; 
}

Esta instrucción X=X+1; es muy importante para controlar la salida del bucle, si no nunca saldriamos de él hasta que apagásemos el ordenador.

Hablemos de las funciones:

Las funciones permiten recopilar código para reutilizarlo y en general están muy relacionadas con la herencia, el polimorfismo y la encapsulación, pero aquí solo voy a explicar como se definen y se usan y cuando explique esos elementos expondré mas formas de uso.
Para definir una función hay que poner el tipo de salida si tienen el nombre y los tipos de entrada que tiene con los nombres de las variables que entran, por ejemplo: 

text mi_funcion(text nombre, num edad){
    instruccion 1;
    instruccion 2;
    instruccion 3; 
    return nombre;
}

Esta función devuelve un text (nombre) y entran, un text guardado en la variable nombre y un num guardado en edad, importante poner un return si se devuelve algo y que la variable que se devuelve sea del mismo tipo que el de salida. Si por ejemplo no se devuelve nada, simplemente se modifican los valores de entrada, no habría que poner return ni tipo de salida.
El programa que hagamos se ejecutará en una función principal a la que llamaré main que tendrá la siguiente forma text main (text args[]) que no voy a explicar por qué tiene esa forma, simplemente hay que tener fe.

Y por último la herencia:

Entendiéndose por herencia la importación de otras funciones y tipos de datos predefinidos. Para ello vamos a usar la palabra import seguido de la ruta del fichero acompañado de un as mas un alias, si estamos windows sería.
Import c:/plancton/libs/ArrayList.ptn as ArrayList
Después para usar las funciones y tipos de datos se haría de la siguiente forma. Si en ArrayList.ptn está definida la funcion void add(list l, struct str) se pondría alias.función:
ArrayList.add( lista, mi_str);

Si es un tipo de dato sería alias.tipoDato por ejemplo si está definido list sería:
ArrayList.list lista;

Con todo esto ya tenemos un lenguaje de programación básico, un pequeño gatito que ronronea que más adelante lo haré crecer y le pondré polimorfismo, encapsulación, excepciones, herencia de la buena, garras y dientes.También junto al gatito voy a deasrrollar un pequeño IDE para poder empezar a chapurrear código y algunas librerías como la entrada/salida estándar, los arrays, las listas,  etc... y conforme se estabilice el parser le iré añadiendo más características al lenguaje.

sábado, 9 de abril de 2011

Aprendiendo a hacer un lenguaje de programación II


En el anterior post enumeré cinco conceptos a implementar para mi propio lenguaje de programación, y alardeé muy alegremente gracias a mis cinco cervezas de que lo que iba a hacer lo era, pero realmente ¿Qué es un lenguaje de programación? ¿De qué se compone? ¿Tengo suficiente con las cinco cosas que hay en mi lista? Para responder a estas preguntas hay que hacer un poco de historia, voy a presentar el primer lenguaje de programación, creado como siempre por un matemático, llamado GOTO.

¿Qué es un lenguaje de programación?

Los matemáticos son los creadores de las sumas, restas, multiplicaciones, logaritmos... que son operaciones que todos sabemos hacer porque siempre alguien que nos las explica. Nos han dicho como debemos representar los datos y que pasos tenemos que seguir hasta completar nuestras respuestas. Los matemáticos han definido una serie de “algoritmos” que nos permiten ejecutar esas operaciones, que son muy fáciles de transmitir, almacenar y enseñar. Pero como son tan exigentes consigo mismos algunos decidieron estandarizar la cosa, creando una sintaxis con unas palabras reservadas para generar las instrucciones, así todo el que entiende las instrucciones puede tanto entender como generar algoritmos cada vez mas complejos y lo más importante empezaron a pensar si podían crear un lenguaje y una máquina que supiera interpretar ese lenguaje recogiendo esos algoritmos en programas.

¿De que se compone?

Corría allá por el año 1900 y pico en el que los señores de la informática, los matemáticos, intuían que podían crear una máquina en la que podían ejecutar todos sus queridísimos algoritmos para generar sus cálculos y mientras ésta trabajaba sin destajo, ellos podían dedicarse a tomar sus cervecitas y gambas y a vivir la vida de una forma más alegre y placentera. Siempre he dicho que la pereza mueve montañas.
Estos señores entre otras cosas crearon un modelo de computación llamado GOTO que define los principios más básicos en los que se basa la programación actual, con GOTO se puede hacer un Windows aunque puedes morirte de asco en el intento.

Empecemos a definir GOTO para intentar comprender de que se compone un lenguaje de programación. 

- Tipos de datos y variables:

Todos son números de tipo entero, pero hay tres clases de variables, las de entrada, salida y auxiliares representadas por las Xs, las Ys y las Zs.
Por ejemplo un programa que tenga dos variables de entrada, una de salida y tres auxiliares tendría:
X1, X2, Y1, Z1, Z2, Z3
Cada una representan un número entero y al principio valen 0.

- Instrucciones:

Tiene 3,5 instrucciones, incremento, decremento, salto y me quedo igual.
La de me quedo igual vale 0,5 y las otras tres 1, supongo que esta se la propuso el gato del país de las maravillas a cambio de un poquito más de lo que se estaba fumando.

Me quedo igual
simplementese mantiene el estado de la variable y se representa así V<--V

Operaciones de Incremento y Decremento
A mi variable le sumo/resto 1 y se representa como V<--V+1 / V<--V-1

Salto, esta es la más importante y dice así.
Si mi variable es distinta de 0 entonces salto a la etiqueta E, ¿Qué es una etiqueta? ¿Qué quiere decir eso de salto a una etiqueta? veámoslo en un ejemplo:
Tengo el siguiente programa en el que decremento la variable X1
y mientras X1 sea distinta de 0 vuelvo a donde está mi etiqueta y continuo mi programa.

A X1<--X1-1
    IF X1 GOTO A

El programa termina cuando X1 vale 0. Esta instrucción es la más importante porque define una estructura de control selectiva y repetitiva a la vez (los if y los while).

- Hablemos de la herencia:

Tambien GOTO permite definir macros que podemos usar en nuestros algoritmos, por ejemplo:
Supongamos que hemos hecho el algoritmo de la suma y lo llamamos suma(X1,X2) y ahora quiero hacer la multiplicacion.

MULTIPLICACION(X1,X2)
    IF X1 GOTO A   #COMPRUEBO X1 NO VALE 0
    Z1<--Z1+1          
    IF Z1 GOTO E
A IF X2 GOTO B   #COMPRUEBO X2 NO VALE 0
    Z2<--Z2+1
    IF Z2 GOTO E
B Y1<--SUMA(Y1,X1)   #A LA SALIDA LE SUMO X1
    X2<--X2-1                  #DECREMENTO X2 PARA LA SIGUIENTE ITERACIÓN
    IF X2 GOTO B           #SI X2 VALE 0 YA HE TERMINADO, SI NO HAGO UN
E  Y1<--Y1                     #NUEVO SALTO A LA ETIQUETA B

Ya tenemos el modelo computacional GOTO mas o menos definido y conocemos los elementos mínimos necesarios para realizar un lenguaje de programación que son los tipos de datos, las instrucciones (tanto las operaciones como las estructuras de saltos y bucles) y la herencia. Pero estos elementos quizás sirvieran hallá por 1900 y pico hoy en día necesitamos mucho más para ser productivos y afrontar problemas enormes en los que necesitemos una gran capacidad de abstracción. Mi objetivo es desarrollar algo fácil de enseñar, pero que permita al usuario dar el paso a la programación orientada a objetos sin demasiados quebraderos de cabeza, en el próximo post empezaré a definir los elementos de mi lenguaje de programación.

sábado, 2 de abril de 2011

Aprendiendo a hacer un lenguaje de programación

Bueno, no se si serán los 28 grados de abril, la salida de la astenia primaveral o las 5 cervezas que llevo por cuerpo, pero se me ha antojado desarrollar mi propio lenguaje de programación, también está en mi lista de cosas que debo hacer antes de morirme así que no hay nada que pueda fallar.
Desarrollar un lenguaje de programación es una ardua tarea y como sólo quiero aprender, voy a desarrollar lo mínimo que se despacha y que sea fácil de aprender.

¿Qué es lo mínimo que se despacha?

Cuando digo lo mínimo que se despacha hablo de hacerlo lo más simple y fácil de implementar, no voy a hacer un lenguaje como java, voy a hacer un lenguaje bajo el paradigma imperativo sin encapsulación, sin interfaces, ni clases, sin excepciones, no va a tener una parte declarativa y otra de implementación, tampoco me voy a pelear con ensamblador, será completamente dinámico y tendrá recolector de basura.

Voy a desarrollar un lenguaje que compile a bytecode de java, creando un parser con java, un pequeño ide  y un pequeño procesador de lenguaje que genera código java que después se compila a bytecode.

¿Se le puede llamar a esto lenguaje de programación?

Sí, si no que se lo digan a java o pyton, a parte que no tengo tiempo, ni recursos, ni ganas de pelearme con ensamblador, c y crear un backend para gcc.

El primer objetivo es aprender y el segundo es enseñar, tanto a desarrollar un lenguaje de programación, como a enseñar a programar bajo el paradigma imperativo. Con lo que debo desarrollar los suficientes elemmentos como para que el usuario comprenda la casuística de la programación y partir de él aprender un lenguaje de más alto nivel en el que pueda aprender los conceptos actuales de la ingeniería del software, hablando siempre de implementacion, como es el uso de patrones en la programación orientada a objetos.

Sí ingeniería, no os asustéis puesto que la ingeniería informática es muy reciente, los conceptos que actualmente se manejan no tienen ni 10 años algunos incluso menos y para alguien que sepa programar les son muy fáciles de aprender, no hay que pelearse con tensores ni ninguna bizarrada matemática de cálculo o álgebra, sólo hay que aprender unos patrones, conocer unos conceptos de desarrollo, gestionar una documentación con la que te puedes poner tanto deacuerdo con tu cliente como con tu equipo de desarrollo y una serie de metodologías de gestión de proyectos, algo muy fácil de aprender que genera mucho éxito y por lo tanto pasta, ya me explayaré otro día sobre ésta cuestión que en mi mundillo genera mucha controversia, símplemente pido que no hay que verlo como algo complicado cuando hablo de ingeniería informática.

¿Que voy a implemetar?

 -Tipos de datos
 -Estructuras de control repetitivas
 -Estructuras de control selectivas
 -Funciones
 -Herencia

En la próxima publicación empezaré a definir cada apartado.