Implementación de Gramática y Generación de Código Intermedio para Compiladores

Informática y Telecomunicaciones6,09 KB

Introducción a las Reglas Gramaticales y Semánticas

A continuación, se presenta la especificación formal de la gramática y sus respectivas acciones semánticas asociadas para la generación de código en ensamblador MIPS. Este documento detalla el manejo de instrucciones básicas, declaraciones, expresiones aritméticas y gestión de paréntesis dentro de un compilador.

Estructura General del Programa

La estructura principal define cómo se componen las listas de instrucciones que conforman el cuerpo ejecutable del programa.

programa ::= lista_instrucciones:li {:  :};
lista_instrucciones ::= instruccion:i {: :} | lista_instrucciones:li {: :};

Definición de Instrucciones y Acciones Semánticas

Las instrucciones contemplan operaciones de entrada y salida (leer y mostrar), así como la asignación de valores y variables. Cada regla incluye validaciones semánticas para verificar la existencia previa de variables en la tabla de símbolos.

Instrucción LEER

Permite capturar un valor desde la consola y almacenarlo en la memoria correspondiente a la variable indicada.

instruccion ::= LEER IDENTIFICADOR:id1 PTOYCOMA COMENTARIO:c  
{: 
  if(!variables.containsKey(id)){
    variables.put(id, ("var_"+id));
    main += "#" + c + "\n"; 
    main += " #Obtener el valor de " + id + " de la consola\n";
    main += " li   $v0,5   #cargar la llamada de lectura en v0\n";
    main += " syscall  #hacer la llamada al sistema\n";
    main += " sw   $v0, " + variables.get(id) + "  #store in memory\n";
    RESULT = main;
  } else {
    main += "#" + c + "\n"; 
    main += " #Obtener el valor de " + id + " de la consola\n"; 
    main += " li   $v0,5   #cargar la llamada de lectura en v0\n";
    main += " syscall  #hacer la llamada al sistema\n";
    main += " sw   $v0, " + variables.get(id) + "  #store in memory\n"; 
    RESULT = main; 
  }
:}

Instrucciones MOSTRAR

Imprimen en la consola el valor actual de una variable, validando previamente su declaración en el ámbito del programa.

| MOSTRAR IDENTIFICADOR:id1 PTOYCOMA COMENTARIO:c  
{:  
  if(!variables.containsKey(id1)) {
    fallo = true;
    error = "ERROR: La variable no ha sido declarada previamente. Línea: " + (id1left+1);
  } else {
    main += "#" + c + "\n";
    main += "#Mostrar el valor de " + id1 + " en la consola\n";
    main += "lw  $a0, " + variables.get(id1) + "  #load in a0\n";
    main += "\nli  $v0, 1 #cargar la llamada de escritura en v0\n";
    main += "syscall  #hacer la llamada al sistema\n";
    RESULT = main; 
  }
:}
|
| MOSTRAR IDENTIFICADOR:id1 PTOYCOMA {: if(!variables.containsKey(id1)) { fallo = true; error = "ERROR: La variable no ha sido declarada previamente. Línea: " + (id1left+1); } else { main += "#Mostrar el valor de " + id1 + "\n"; main += "lw $a0, " + variables.get(id1) + " #load in a0\n"; main += "\nli $v0, 1 #cargar la llamada de escritura en v0\n"; main += "syscall #hacer la llamada al sistema\n"; RESULT = main; } :}

Instrucciones de Asignación

Gestionan la asignación de números literales o resultados de expresiones evaluadas hacia variables específicas.

| IDENTIFICADOR:id1 ASIGNACION NUMERO:n1 PTOYCOMA  
{: 
  if(!variables.containsKey(id1)) { 
    variables.put(id1, ("var_" + id1));
  }
  if(!numeros.contains(n1)){
    numeros.addElement(n1);
  }
  main += "#\n";
  main += "  lw $t1, constants+" + (numeros.indexOf(n1)*4) + "\n";
  main += "  sw $t1, " + variables.get(id1) + "\n";
  RESULT = main;
:}
|
| IDENTFICADOR:id1 ASIGNACION expresion:e PTOYCOMA COMENTARIO:c {: if(!variables.containsKey(id1)) { variables.put(id1, ("var_" + id1)); } main += "#" + c + "\n"; main += e; RESULT = main; :}

Evaluación de Expresiones Aritméticas

Se definen las distintas combinaciones posibles para el cálculo de expresiones que involucran números, variables, operadores y estructuras de agrupación con paréntesis.

expresion ::= 
    RESTA NUMERO:n1 {:  %}
  | RESTA IDENTIFICADOR:id1 {:  %}
  | NUMERO:n1 {:  %}
  | IDENTIFICADOR:id1 {:  %}
  | RESTA IDENTFICADOR:id1 operador:op IDENTIFICADOR:id2 {:  %}
  | RESTA IDENTIFICADOR:id1 operador:op NUMERO:n1 {:  %}
  | IDENTFICADOR:id1 operador:op IDENTIFICADOR:id2 {:  %}
  | IDENTIFICADOR:id1 operador:op NUMERO:n1 {:  %}
  | NUMERO:n1 operador:op NUMERO:n2 {:  %}
  | NUMERO:n1 operador:op IDENTIFICADOR:id1 {:  %}
  | PAR_AB parentesis:p PAR_CERR  {: main += p; RESULT = main;  %}
  | PAR_AB parentesis:p PAR_CERR operador:op PAR_AB parentesis:p PAR_CERR {:  %}
  | PAR_AB parentesis:p PAR_CERR operador:op IDENTIFICADOR:id1 {:  %}
  | PAR_AB parentesis:p PAR_CERR operador:op NUMERO:n1 {:  %}
  | IDENTIFICADOR:id1 operador:op PAR_AB parentesis:p PAR_CERR {:  %}
  | NUMERO:n1 operador:op PAR_AB parentesis:p PAR_CERR {:  %};

Manejo de Paréntesis y Prioridad de Operadores

El tratamiento de los paréntesis permite asegurar la precedencia correcta en operaciones complejas dentro de la pila de registros temporales.

parentesis ::= 
    IDENTIFICADOR:id1 operador:op parentesis:p {:  %}
  | NUMERO:n1 operador:op parentesis:p  
    {: 
      if(!numeros.contains(n1)) { 
        numeros.addElement(n1); 
      } 
      main += " lw   $t" + pos + ", constants+" + (numeros.indexOf(n1)*4) + "\n";
      pos++; 
      main += p;
      main += " " + op + "   $t0, $t1, $t2"; 
    %}
  | IDENTIFICADOR:id1 {:  %}
  | NUMERO:n1  
    {: 
      if(!numeros.contains(n1)) { 
        numeros.addElement(n1); 
      } 
      main += " lw   $t" + pos + ", constants+" + (numeros.indexOf(n1)*4) + "\n"; 
    %};

Operadores Soportados

Se mapean los operadores aritméticos básicos a sus respectivas instrucciones mnemotécnicas de ensamblador.

operador ::= 
    SUMA {: RESULT = "add"; %}
  | RESTA {: RESULT = "sub"; %}
  | MULT {: RESULT = "mult"; %}
  | DIV {: RESULT = "div"; %};

Descargar

PDF Word HTML