Construyendo el compilador Parte IX: Código intermedio de asignaciones, de métodos, if, etc

 Hola blogeros de las 3 C de mi vida. 

Ha sido un largo viaje, pasando por el lexer, parser y ahora el analizador semántico. Si, ufff...laaaargo caminito pues. Además, ahora estamos en la fase de codigo intermedio, siemptre es bueno recordar el pasado, para que cuando las recompensas salgan, sintamos que SI esta bien lo que hacemos y lo que logramos. Asi me gusta!

Bueno, para no aburrirlos, esta semana mi blog es sobre la creación de codigo intermedio para asignaciones, métodos, If, etc

Colocaré algunos ejemplos

DISFRUTEN!


Traduciendo métodos a código intermedio

Para esto, simplemente podemos crear una etiqueta para indicar que EMPIEZA un método y otro para indicar que ACABA el método, imaginemos que tenemos esto:
class Program{
    void patito(){
        int a;
    }
    void senzontle(){
        int a;
    }
    void main(void) {
        int a;
    }
}

Como vemos, son puras declaraciones, que traducidas a codigo intermedio sería:

DEF PATITO:
END DEF PATITO


DEF SENZONTLE:
END DEF SENZONTLE


DEF MAIN:
END DEF MAIN

Esto es simple, compliquemoslo más

Traduciendo llamada a métodos y parámetros

Tenemos el siguiente codigo woo

class Program{
    int factorial(int n)
    {
      return n * 2;

    }

    void main(void) {
        int a;
        a = factorial(2);
    }
}


Entonces, como vemos, llamamos a factorial
El código generado es
DEF FACTORIAL:

t0 = fp[0] * 2
RETURN t0

END DEF FACTORIAL


DEF MAIN:
 PARAM 2
 CALL factorial, 1
 fp[0] = R
END DEF MAIN

Como vemos, creamos el DEF de factorial, y dentro, en una temporal multiplicamos la variable fp[0] (que representa el parámetro n) y lo retornamos. En el lado del DEF MAIN, tenemos un PARAM para decir que el PARAMETRO será el valor de 2, luego hacemos un CALL a factorial,  y el RETURN se lo asignamos al fp[0] del método main, que en este caso es la variable A que creamos. AWESOME!


Ahora metámosle algo de condicionales, ¿si?


Traduciendo condicionales (IF) a código intermedio

Primero veamos algo simple

class Program{

    void main(void) {
        int a;
        int b;
        int c;
        if(a > 1159){
            c = 3;
        }
    }
}

Tenemos un if que si la variable a es mayor a 1159 (sip, un numero grande) entonces a c le coloque el valor de 3. Esto en código intermedio es 

DEF MAIN:

t0 = fp[0] > 1159

IF t0 > 0 GOTO IF_TRUE_0

GOTO IF_FALSE_0

IF_TRUE_0:


  fp[8] = 3

IF_FALSE_0:


END DEF MAIN

La primera etiqueta lo que hace es que a una temporal le dice: ey, mira si la variable a es mayor a 1159 entonces ese resultado se guarda en t0, ¿estamos?. Vale, la magia ocurre luego, dentro del IF se tiene que si t0>0 (es decir que si la condicion de asignacion de t0 es mayor a 0) entonces vamos a IF_TRUE_0. Si notamos, el ELSE es un IF_FALSE_0. Si vamos al true, al fp[8] le asignamos el 3, y si no NADA entonces no hacemos nada, un codigo de corto circuito.

Algo más complejo!:

class Program{

    void main(void) {
        int a;
        int b;
        int c;
        if((a > 1159)||(b<150)){
            c = a * b;
        }
    }
}


Como vemos, ahora tenemos un OR, y dos condiciones, y una multiplicacion, el codigo generado es:

DEF MAIN:

t0 = fp[0] > 1159

t1 = fp[4] < 150

t2 = t0  || t1

IF t2 > 0 GOTO IF_TRUE_0

GOTO IF_FALSE_0

IF_TRUE_0:

t3 = fp[0] * fp[4]

 fp[8] = t3

IF_FALSE_0:


END DEF MAIN


Notamos como ahora tenemos dos temporales, las t0 y t1 que hacen las condiciones, la t2 se encarga de la operacion condicional, si t2 es mayor a cero, osea que si es real, entonces vamos al TRUE0, esta label tiene el resultado de multiplicar valores normales y de asignarlos a c. De lo contrario nada.



Espero les haya gustado!

En el próximo post, un resumen final de este proyecto.
Gracias por ver! (y leer)



Comentarios

Entradas populares de este blog

Construyendo el compilador Parte I: ANTLR V4 (ya van 4 versiones, increible), café y una miradita a los parser y lexer generados con Java

Construyendo el compilador Parte V: Finalizando el analizar Semántico

Construyendo el compilador Parte III: ANTLR V4, Listener vs Visitor y la tabla de Símbolos