Foro de elhacker.net

Programación => Programación General => Mensaje iniciado por: leogtz en 4 Julio 2012, 10:34 am



Título: ¿Y si creamos un lenguaje de programación? [ACTUALIZADO]
Publicado por: leogtz en 4 Julio 2012, 10:34 am
Hola a todos, en estas vacaciones me he dedicado a escribir un intérprete para un lenguaje de programación, el cuál llamé "Yare".

Está escrito en C, con ayuda de lex y yacc.

El lenguaje que estoy haciendo aún es muy limitado, pero ya tiene algunas cosas algo "rescatables", como por ejemplo:

- Ciclos: for, while, do-while, unless.
- Condicional if y algunas expresiones se pueden procesar así:

Código
  1. expresion == expression && sentencia;

Un ejemplo:
Código
  1. 1 == 1 && "Ok\n";
-Sentencia tipo "read(var)"
-Inicialización con valor aleatorio, ejemplo:
Código
  1. x = ?;

- Lo he hecho bastante "rico" en comentarios, es decir, se admiten comentarios de la forma
Código
  1. /* hjkhjkasd
  2. asdasd
  3. */
Código
  1. rem Comentario de una sóla línea
Código
  1. # Comentario de una sóla línea
Código
  1. -- Comentario de una sóla línea
Código
  1. // Comentario de una sóla línea
Código
  1. :: Comentario de una sóla línea

- Caracteres especiales en la sentencia "puts(string)", los mismos que en C:
\n, \t, \s(este es de Perl), \b, \r, \f.
Añadí uno propio así:
\q el cuál inserta una doble comilla '"'.

- Además añadí unos caracteres de escape de nueva línea numéricos, es decir.

Código
  1. puts("Hola\1mundo") <- Haría que se insertara un \n
  2. puts("Hola\2mundo") <- Haría que se insertara dos \n
  3. puts("Hola\3mundo") <- Haría que se insertara tres \n
  4.  
y así hasta el 9.

No hay tipos de datos por ahora, el tipo de dato que manejo es "double".

Hay 26 variables por default, las variables son de la "a" a la "z" y no es sensible a mayúsculas y minúsculas. Estas variables siempre están ahí disponibles.

-Se pueden definir variables propias de este modo:
Código
  1. :suma: = 2^3;
ó así:
Código
  1. declare(:suma:, 2^3);
Código
  1. declare(:suma:);

Los identificadores pueden ser bastante flexibles, ejemplo:
Código
  1. : _Hola mundo # 123342432 : = 123;
  2. printn(: _Hola mundo # 123342432 :);

Se pueden definir bloques de código:
Código
  1. {
  2.   sentencias...
  3. }

-Constantes numéricas:
número pi, número e, logaritmo en base 2 de el número e, y varias más, se pueden utilizar así:
Código
  1. printn(cos(const.pi^2));

-Operadores:
+, -, *, /, ^, %, <<, >>, |, &, &&, ||, ! y ~ para negación, XOR.

-Funciones matemáticas:
Código
  1. factorial(expr), abs(expr), ln(expr), cos(expr), sin(expr), tan(expr), atan(expr), asin(expr), acos(expr), floor(expr), sinh(expr), sumatoria(expr, expr), etc.

-Operadores de posdecremento y posincremento, de esta manera:
Código
  1. a = 1;
  2. a+@;
  3. a-@;
  4.  
  5. ó incr(variable), decr(variable)

-Operador variable, lo que llamé operador variable no es más que un operador global que puede ser modificado, algo así:
Código
  1. _@_= *;
  2. _@_ = /;
  3. _@_ = -;
  4. etc...

Y que luego pueda ser usado de esta manera:

Código
  1. _@_ = *;
  2. printn(1 + 2 _@_ 3);
  3.  
¿Para qué podría servir esto? no lo sé :)

-Inicialización por medio de smileys....  ;D, algo así:
Código
  1. x = :);   # Lo inicializa a 1
  2. x = :|;  # Lo inicializa a 0
  3. x = :(;  # Lo inicializa a -1.

-Sentencia break para los ciclos, aún no hallo como implementar la sentencia continue.

-Ciclo foreach de esta manera:
Código
  1. foreach(1 ... factorial(5), k) {
  2. printn(k);
  3. }

-Sentencia system(CADENA).

-Asignaciones flexibles:
Código
  1. let x to 1+2;
  2. set x to 1+2;
  3. move 1+2 to x;
  4. x = 1+2;
  5. mov x, 1+2;
  6. x <- 1+2;
  7. let x = 1+2;
  8. set x = 1+2;
  9. x := 1+2;
  10.  
Todas ellas son equivalentes.

-Sentencias tipo assembly:
Código
  1. mov x, factorial(6);
  2. sub x, -123;
  3. add x, 1+2;

-Sentencia "swap" para intercambiar valores:

Código
  1. x = 1;
  2. y = 2;
  3. x <-> y;
  4.  

-Sentencia exit:
Código
  1. exit(-1);

-Sentencia read(variable) para leer desde el teclado, ejemplo:
Código
  1. read(x);
  2. for i = 0, i < x, +1 {
  3. printn(i);
  4. }

-Asignaciones abreviadas:
Código
  1. x += 1;
  2. x -= 1;
  3. x *= 1;
  4. x ^= 3;
  5. x /= 2;
  6. x <<= 1;
  7. x >>= 1;
  8. x |= 1;
  9. x &= 1;
  10. x %= 2;
  11.  

-Función par(expr) para saber si el número resultado de la expresión es par.

-Definición de procedimientos por el usuario, en la forma:
Código
  1. proc $suma$ {
  2. a += b;
  3. # Demás sentencias ...
  4. }
  5.  
  6. a = 1;
  7. b = 2;
  8.  
  9. # Imprime 3
  10. # El valor retornado por el procedimiento o función es
  11. # el resultado de la última sentencia o expresión.
  12. printn(call $suma$);
  13.  

-Soporta recursión, obviamente no tan flexible, un ejemplo de cálculo del factorial con algoritmo recursivo:
Código
  1. # Intento de recursion
  2. proc $factorial$ {
  3. if(a != 1) {
  4. r *= a;
  5. a-@;
  6. call $factorial$;
  7. }
  8. }
  9.  
  10. # Calculando el factorial de 5:
  11. a = 5;
  12. r = 1;
  13.  
  14. call $factorial$;
  15. printn(r);
  16.  
  17. .
  18.  

Da por resultado 120.

La ejecución de algunos programas no es tan lenta, por ejemplo, calculemos el número pi en perl y luego calculemoslo en Yare.
Código
  1. #!/usr/bin/env perl
  2. my $suma = 0.0;
  3. my $i = 0.0;
  4. for($i = 1; $i <= 1000000; $i++) {
  5. $suma += (-1)**($i + 1)/(2 * $i - 1);
  6. }
  7. $suma *= 4.0;
  8. print($suma . "\n");
  9.  
Código:
3.14159165358978

real 0m0.646s
user 0m0.572s
sys 0m0.004s

Ahora en Yare:
Código
  1. :suma: = 0;
  2. for i = 1, i <= 1000000, +1 {
  3. :suma: += (-1)^(i + 1)/(2 * i - 1);
  4. }
  5. :suma: *= 4.0;
  6. puts("pi = ");
  7. printn(:suma:);
  8. .
  9.  
Código:
pi = 3.141592

real 0m0.641s
user 0m0.564s
sys 0m0.000s

Los tiempos de ejecución son muy similares. Obviamente no pretendo decir que la calidad de mi código es superior o si quiera igual que el de Perl, sería una estupidez, pero bueno... .
Estas son algunas cosas que he implementado en Yare, es muy muy limitado, pero bueno, quizás alguien quiera hacerlo crecer junto conmigo.

Lo primero en qué hay que pensar cuando se quiere hacer un lenguaje es "¿para qué va a servir?", "¿qué objetivo tiene?", yo no tengo objetivo, sólo aprender, ver cómo funcionan las cosas, y he aprendido muchisimo, no todo ha sido "miel sobre ojuelas", he batallado mucho con esto, han sido horas y horas de programar y a veces de dedicarle un día entero a algo y ver al final que las cosas no funcionan, y ni modo, a seguir adelante con otra cosa.

Por ahora estoy añadiendo soporte para arrays, pero les soy sincero, ya me aburrí de esto, porque son muchas horas dedicadas a esto y tengo otras cosas que hacer :).


Entonces ahí está la petición, si alguien quiere unirse a desarrollar esto, yo encantado.

Saludos.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: AgnesBlack en 11 Julio 2012, 22:54 pm
excelente trabajo


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: jhonatanAsm en 12 Julio 2012, 07:17 am
Citar
Inicialización por medio de smileys....  , algo así:

Código:
x = :);   # Lo inicializa a 1
x = :|;  # Lo inicializa a 0
x = :(;  # Lo inicializa a -1.

que imaginativo...

salu2.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: leogtz en 17 Julio 2012, 00:15 am
que imaginativo...

salu2.

Gracias :), cualquier otro podría ponerle inicializaciones como quisiera, es bastante sencillo en realidad.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: dac en 17 Julio 2012, 01:48 am
Te esta quedando genial! felicitaciones! , estas implementando el compilado para traducir el código directamente a ASM? o lo parcea luego algún otro compilador en un nivel inferior?


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: leogtz en 17 Julio 2012, 07:10 am
El lenguaje es interpretado, el intérprete está hecho en C, básicamente el intérprete es una función recursiva, lo cual hace fácilmente implementable cualquier función que se desee, pensar crear código objeto es ir bastante lejos, mis conocimientos no son tan grandes.

Saludos.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: Yoghurt en 17 Julio 2012, 12:11 pm
Me ha gustado lo de la iniciación por "caritas" +1

Noté que usas ";" para fin de linea osea lo usas para saber cuando a acabado la declaracion de la expresión, eso siempre ha sido mi punto debil he de admitir por lo que sería genial que añadieras otra forma de finalizar la expresion tal como un "[Intro]" o un "." se parece demasiado al C.

Note que incluiste comentarios de diferentes lenguages y se me paso por la cabeza que éste interprete tuyo podria ser "El lenguaje universal" claro con su nombre Yare ;) es un gran desafío.

la forma de declarar las variables :variable: es vastante novedosa +2 :esto es una variable: :D genial!, aunq como concatenarias tu dos variables?

Código:
:var1: = 'hola ';
:var2: = 'mundo!';
printn(:var1: + :var2:);
printn(:var1: . :var2:);
printn(:var1::var2:);
var2 = 'Esto es una variable?';

mm... siempre me ha gustado la iniciacion de variable tipo "x=b=numero=foo=43" donde x, b, numero, foo tienen el mismo valor 43.

Pregunta; los nombres de las funciones tienen que llevar el "$"?


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: leogtz en 17 Julio 2012, 22:36 pm
Me ha gustado lo de la iniciación por "caritas" +1

 ;D

Noté que usas ";" para fin de linea osea lo usas para saber cuando a acabado la declaracion de la expresión, eso siempre ha sido mi punto debil he de admitir por lo que sería genial que añadieras otra forma de finalizar la expresion tal como un "[Intro]" o un "." se parece demasiado al C.

Se puede, claro, hay que checarlo con detenimiento, por ejemplo, si quisieramos terminar la expresión o sentencia con un '.' podría haber algo así:

1+2.

Pero el intérprete se confundiría ya que puede ser un número decimal o no, cuestiones como esas son las que te topas al programar algo así, aunque pudiera utilizarse otro caracter para fin de sentencia, sólo habría que verificar que no se usara en ninguna otra parte o entrara en conflicto con otras cosas.

la forma de declarar las variables :variable: es vastante novedosa +2 :esto es una variable: :D genial!, aunq como concatenarias tu dos variables?

Código:
:var1: = 'hola ';
:var2: = 'mundo!';
printn(:var1: + :var2:);
printn(:var1: . :var2:);
printn(:var1::var2:);
var2 = 'Esto es una variable?';

Eso lo intenté, el realizar algo así:
Código:
print("hola! ", : variable :, " bye", "ok\n\4", 1 + 2.34545, -5, "etc....");

Pero no es tan sencillo, en el analizador sintáctico habría que realizar una buena BNF que soporte todo eso, algo así:

Código:
print_expression_list:
    print_expression_list ',' expression
    | {;} /* por si se escribe print() */

expression:
    constante_numerica
    | cadena
    | variable
    | ID

Habría que checar con detenimiento la forma Backus-Naur,


Sobre lo de los nombres de las funciones delimitadas con $$ se puede cambiar, no es mucho problema, el código actual para eso es bastante sencillo, algo así:

Código
  1. [$].+[$] {
  2. strcpy(yylval.nameFunction, yytext);
  3. yylval.nameFunction[strlen(yylval.nameFunction)] = '\0';
  4. return FUNCNAME;
  5. }

[$].+[$] es la expresión regular que utilizo para coincidir $texto$.

Saludos.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: lnvisible en 17 Julio 2012, 23:30 pm
¿has visto lo que hace coffeescript con javascript o lo que hace clojurescript?

Es mucho más fácil que hacer un lenguaje de programación porque sólo tienes que traducir entre lenguajes, así que no te tienes que preocupar del código intermedio, la tabla de símbolos y todas esas cosas que hay que manejar en un compilador para acabar generando ensamblador. Es más fácil generar javascript que ensanblador.

Lo que puedes hacer es algo parecido a coffeescript, que es un lenguaje muy sencillo y legible, o python, o alguno así que te guste, y generar lisp.

Si generas lisp luego eso se puede traducir a clojure y a clojurescript, es cedir que lo puedes pasar a java y a javascript, servidor y cliente, y montones de librerías para usar, como con scala.

Y sólo por hacer una traducción de algo más legible que lisp.

Un primer paso sería cambiar los paréntesis por niveles de indentación, como en coffeescript y python. Con eso sería mucho más legible en mi opinión.

Piénsalo :D


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: leogtz en 18 Julio 2012, 00:49 am
¿has visto lo que hace coffeescript con javascript o lo que hace clojurescript?

Es mucho más fácil que hacer un lenguaje de programación porque sólo tienes que traducir entre lenguajes, así que no te tienes que preocupar del código intermedio, la tabla de símbolos y todas esas cosas que hay que manejar en un compilador para acabar generando ensamblador. Es más fácil generar javascript que ensanblador.

Lo que puedes hacer es algo parecido a coffeescript, que es un lenguaje muy sencillo y legible, o python, o alguno así que te guste, y generar lisp.

Si generas lisp luego eso se puede traducir a clojure y a clojurescript, es cedir que lo puedes pasar a java y a javascript, servidor y cliente, y montones de librerías para usar, como con scala.

Y sólo por hacer una traducción de algo más legible que lisp.

Un primer paso sería cambiar los paréntesis por niveles de indentación, como en coffeescript y python. Con eso sería mucho más legible en mi opinión.

Piénsalo :D

Sí, de hecho imprimí el libro "how to create your own freaking awesome language" el cuál inspiró a los creadores de coffescript, el problema es que está hecho en ruby, y no me llevo muy bien con él. De hecho los creadores de coffescript utilizan también herramientas como bison y flex, lo bueno del libro es que dan el código para empezar, pero para lograr hacer algo propio hay que estudiar en demasía el código, algo que quizás en su momento me desalentó puesto que yo quería obtener resultados de manera más pronta.

La idea que tengo, que quizás trabaje en unos meses es ponerle tipos de datos e implementar una librería tipo BigInt(o utilizar gmp), para ponerle un propósito al lenguaje ...

Saludos.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: BlackZeroX en 18 Julio 2012, 10:20 am
tal vez mis estructuras de mi CSxript que estoy haciendo te sirvan (por ahora me concentro en funciones y variables)...

Código
  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdbool.h>
  6.  
  7. struct String;
  8. struct Variable;
  9. struct VariableList;
  10. struct Function;
  11.  
  12. struct Params;
  13. struct ParamsList;
  14. struct Instruction;
  15. struct InstructionList;
  16.  
  17. const long INVALID_INDEX = -1;
  18.  
  19. /*
  20. typedef struct Variable Variable ;
  21. typedef struct Function Function;
  22. typedef struct VariableList VariableList;
  23. */
  24.  
  25. struct String {
  26.    char* text;
  27.    size_t size;          //  Tamaño del bloque reservado (mas no el que se usa).
  28. };
  29.  
  30. struct Variable {    //  Define una varible.
  31.    enum FORMAT_VARIABLE{
  32.        _NONE_      = 0x0,
  33.        //  Tipos...
  34.        _CHAR_      = 0x1,
  35.        _INT_       = 0x2,
  36.        _FLOAT_     = 0x4,
  37.        _DOUBLE_    = 0x8,
  38.        _VOID_      = 0x10,
  39.  
  40.        //  Modificadores...
  41.        _UNSIGNED_  = 0x100,
  42.        _LONG_      = 0x200,    //  Se permite usar 2 veces solo en INT y 1 vez en DOUBLE.
  43.        _SHORT_     = 0x400,    //  Se permite usar 1 vez en INT.
  44.        _CONST_     = 0x800,    //  Solo una vez en todos los tipos de variables.
  45.        _PTR_       = 0x1000,   //  Indica que la variable es un puntero.
  46.        _SHARED_    = 0x2000,   //  Se usa en combinacion de una variable tipo puntero (Se usa para que la memoria pedida no se autolibere al salir de la función).
  47.        _STATIC_    = 0x3000    //  Se usa para que una variable no pierda su valor al salir de una funcion.
  48.    } a;
  49.    struct String name;         //  Nombre de la variable.
  50.    long flags;                 //  Tipo de variable (Es una combinacion de las enumeraciones superiores).
  51.    size_t size;                //  Tamaño en bytes de la variable.
  52.    void* value;                //  Valor.
  53. };
  54.  
  55. struct VariableList {           //  Lista de variables.
  56.    struct Function* parent;    //  Funcion padre donde estan alojadas las variables.
  57.    unsigned long count;        //  Cantidad de variables.
  58.    struct Variable** list;     //  Puntero a la lista de las funciones.
  59. };
  60.  
  61. struct Params {
  62.    enum FORMAT_PARAM {
  63.        _VARIABLE_ = 1,
  64.        _FUNCTION_ = 2,
  65.        //_VOID_ = 4
  66.    } a;
  67.    void* value;                //  Apuntador al parametro (Segun flags debera de realizarse un cast adecuado).
  68.    long flags;                 //  Tipo de parametro: variable, funcion...
  69. };
  70.  
  71. struct ParamsList {
  72.    struct Instruction* parent; //  A que instruccion pertenece este parametro?.
  73.    struct Params* list;        //  Lista d elos parametros.
  74.    size_t count;               //  Cantidad de parametros.
  75. };
  76.  
  77. struct Instruction {
  78.    enum {
  79.        //  Flags Predeterminados.
  80.        //_NONE_,             //  No es ninguna instruccion.
  81.  
  82.        //  Asignaciones.
  83.        _ASIGN_,            //  Asignacion (A = B).
  84.        _ASIGN_ADD_,        //  Asignacion con Sumatoria/Resta ( A += B, A >- B).
  85.        _ASIGN_ROL_,        //  Asignacion con dezplazamientode de N bits a la izquierda ( A <<= B).
  86.        _ASIGN_ROR_,        //  Asignacion con dezplazamientode de N bits a la derecha ( A >>= B).
  87.  
  88.        //  Comparaciones.
  89.        _EQUAL_,            //  Igual que (A == B).
  90.        _GREATTHAT_,        //  Mayor que (A > B).
  91.        _LESSTHAT_,         //  Menor que (A < B).
  92.        _GREATTHAT_EQUAL_,  //  Mayor o igual que (A >= B).
  93.        _LESSTHAT_EQUAL_,   //  Menor o igual que (A >= B).
  94.        _AND_,              //  A y B (A && B).
  95.        _OR_,               //  A o B (A || B).
  96.  
  97.        //  Operaciones Basicas (base 10).
  98.        _ADD_,              //  Resta/Suma (A+B).
  99.        _ADD_PRE_,          //  Resta/Suma -/+ 1 (++A, --A).
  100.        _ADD_POST_,         //  Resta/Suma -/+ 1 (A++, A--).
  101.        _MULTIPLY_,         //  Multiplicacion (A * B).
  102.        _MOD_,              //  Residuo de A entre B (A % B) (retorna un unsigned long long).
  103.        _DIV_,              //  A entre B (A / B) (Retorna un long double).
  104.  
  105.        //  Operaciones Binarias (base 2).
  106.        _ROL_,              //  Rotacion de N bits a la izquierda (A << N).
  107.        _ROR_,              //  Rotacion de N bits a la izquierda (A >> N).
  108.        _AND_BIT_,          //  A y B (A & B).
  109.        _OR_BIT_,           //  A o B (A | B).
  110.        _XOR_,              //  A xor B (A ^ B).
  111.        _NOT_               //  complemento binario (not A).
  112.    } a;
  113.    struct Function* parent;    //  A que funcion pertenece la instruccion?.
  114.    int opcode;                 //  De que tipo es la instruccion?.
  115.    struct ParamsList arg;      //  Lista de argumentos d ela funcion.
  116. };
  117.  
  118. struct InstructionList {
  119.    struct Function* parent;    //  A que funcion pertenece la lista de instrucciones?.
  120.    struct Instruction* list;   //  Lista de instruccion.
  121.    size_t count;               //  Cantidad de instrucciones contenidas.
  122. };
  123.  
  124. struct Function {
  125.    struct Function* stackCall; //  Pila del proceso (Quien llamo al proceso).
  126.    struct String name;         //  Nombre de la funcion.
  127.    struct VariableList* vars;  //  Lista de variables.
  128.    struct InstructionList code;//  Codigo de la funcion Cada linea representa una instruccion.
  129.    struct Variable ret;        //  Valor que retorno la funcion.
  130. };
  131.  
  132.  
  133. bool            stringInit(struct String* str);
  134. struct String*  stringCreate();
  135. char*           stringRedim(struct String* str, size_t size);
  136. bool            stringFinalize(struct String* str);
  137. bool            stringFree(struct String* str);
  138. struct Variable*        variableCreate(const char* name);
  139. bool            variableFree(struct Variable* var);
  140. bool            variableFreeList(struct Variable** varlist, size_t count);
  141. struct Variable**       variableListFind(struct VariableList* varlist, const char* find);
  142. struct VariableList*    variableListCreate();
  143. struct VariableList     variableListInit();
  144. bool            variableListFinalize(struct VariableList* varlist);
  145. bool            variableListFree(struct VariableList* varlist);
  146. unsigned long   variableListLink(struct VariableList* varlist, struct Variable* var);
  147. long            variableListIndex(struct VariableList* varlist, struct Variable** ptr);
  148. unsigned long   variableListUnLink(struct VariableList* varlist, struct Variable** ptr);
  149.  
  150.  

Dulces Lunas!¡.


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: gonzalo57 en 25 Julio 2012, 12:37 pm
Ojala lo termines pronto y pongas cursillos y etc..

te esta quedando  PERFECTO!  :D :D


Título: Re: ¿Y si creamos un lenguaje de programación?
Publicado por: leogtz en 21 Marzo 2013, 08:11 am
Terminé por así decirlo la versión 1.0 hace unos meses, les dejo las características que tiene incorporadas el lenguaje:

https://dl.dropbox.com/u/58795303/yare_doc.docx (https://dl.dropbox.com/u/58795303/yare_doc.docx)

Cualquier retroalimentación es bienvenida :)

El que desee el código fuente por favor me lo pida por mensaje privado.

Saludos!