TEMA 2: PARSERS Y CONSTRUCCIÓN DEL ÁRBOL DE SINTAXIS ABSTRACTA PARA L-0 En este tema se divide en tres secciones:
(1) la definición el analizador léxico de L-0, (2) el conjunto de reglas sintácticas de L-0 y
(3) el analizador sintáctico extendido para la construcción del árbol de sintaxis abstracta del lenguaje L-0.
En las tres secciones usamos ANTLR. 1.- ANÁLISIS LÉXICO DE L-0
class Analex extends Lexer; options{
// Importación del vocabulario de tokens desde el analizador // sintáctico (Anasint.g)
importVocab=Anasint;
// Por defecto no se activa la comprobación de literales // declarados en la sección tokens
testLiterals=false;
//2 símbolos de anticipación para tomar decisiones //(los tokens DP y ASIG justifican su necesidad) k=2;
} tokens{
// Palabras reservas (unidad de programa) MODULO="modulo";
// Palabras reservadas (instrucciones compuestas) // palabras reservadas en condicionales
SI="si";
ENTONCES="entonces"; SINO="sino";
FINSI="finsi";
// palabras reservadas en iteraciones MIENTRAS="mientras";
HACER="hacer";
FINMIENTRAS="finmientras";
// Palabras reservadas (devolución resultado) DEV="dev";
// Palabras reservadas (visibilidad) OCULTO="oculto";
// Palabras reservadas (clase instanciable) INST="inst";
// Palabras reservas (tipos predefinidos simples) ENTERO="entero";
REAL="real"; LOGICO="logico"; CARACTER=”caracter”;
// Palabras reservas (tipos predefinidos compuestos) FORMACION="formacion";
// Palabras reservas (tipos no predefinidos) CLASE="clase";
// Palabras reservadas (literales lógicos) CIERTO="cierto";
FALSO="falso";
// Palabras reservadas (operadores lógicos) Y="y";
O="o"; NO="no"; }
//Tokens inútiles para el análisis sintáctico //(B)lancos y (T)abuladores BT : (' '|'\t') {$setType(Token.SKIP);} ; //(S)altos de (L)inea SL : "\r\n" {newline();$setType(Token.SKIP);} ; // Comentario de línea COMENT_LIN: "//" (('\r')+ ~('\n') | ~('\r') )* "\r\n" {newline();$setType(Token.SKIP);} ; // Signos de puntuación
DOS_PUNTOS : ':'; //(D)os (P)untos
PARENTESIS_ABIERTO : '('; // (P)arentesis (A)bierto PARENTESIS_CERRADO : ')'; // (P)arentesis (C)errado LLAVE_ABIERTA: '{'; // (LL)ave (A)bierta
LLAVE_CERRADA: '}'; // (LL)ave (C)errada
CORCHETE_ABIERTO: '['; // (COR)chete (A)bierto CORCHETE_CERRADO: ']'; // (COR)chete (C)errado COMA: ','; // (CO)ma
PUNTO_Y_COMA: ';'; // (PU)nto y (C)oma PUNTO:'.'; // (PU)nto // Operadores aritméticos MAS: '+'; MENOS: '-'; POR: '*'; DIVISION: '/'; // Operadores relacionales MENOR:'<';
MENOR_IGUAL:"<="; MAYOR:'>' MAYOR:IGUAL:">="; IGUAL: '='; DISTINTO: "!="; // Asignación ASIGNACION : ":=" ; // Lexemas auxiliares protected DIGITO: ('0'..'9'); protected LETRA: ('a'..'z'|'A'..'Z'); // Literales Enteros y Reales
NUMERO : ((DIGITO)+ '.') => (DIGITO)+ '.' (DIGITO)+ {$setType(LIT_REAL);} | ((DIGITO)+) => (DIGITO)+ {$setType(LIT_ENTERO);}
;
//Literales Carácter
LIT_CAR: ‘\’’! (~(‘\’’|‘\n’|‘\r’|’\t’)) ‘\’’! // Lexema IDENT (Identificadores)
// Se activa la comprobación de palabras reservadas.
// Las palabras reservadas tienen preferencia a cualquier otro identificador. IDENT options {testLiterals=true;}: LETRA(LETRA|DIGITO)* ;
2.- REGLAS PARA EL ANÁLISIS SINTÁCTICO DE L-0 ///////////////////////////////////////////////////////// // DECLARACION DE MODULO ///////////////////////////////////////////////////////// declaracion_modulo : nombre_modulo definicion_modulo EOF ;
nombre_modulo : MODULO IDENT ; definicion_modulo : lista_declaraciones_clases ; lista_declaraciones_clases : (declaracion_clase)+ ; /////////////////////////////////////////////////////////// // DECLARACIÓN DE CLASE /////////////////////////////////////////////////////////// declaracion_clase : cualificador_clase nombre_clase definicion_clase ; cualificador_clase: INST | ;
nombre_clase : CLASE IDENT ; definicion_clase :
LLAVE_ABIERTA
declaraciones_elemento_clase LLAVE_CERRADA
;
// La definición de la clase se completa con declaraciones de // atributos y métodos. declaraciones_elemento_clase : (declaracion_elemento_clase)* ; declaracion_elemento_clase : cualificador_elemento_clase
((IDENT PARENTESIS_ABIERTO) => declaracion_metodo | tipo IDENT PUNTO_Y_COMA
;
cualificador_elemento_clase: OCULTO |
;
// Declaración de método consta de prototipo y definición // Prototipo o perfil de la operación.
// Definición de método compuesto de declaración de // variables locales e instrucciones.
declaracion_metodo : prototipo_metodo definicion_metodo ; prototipo_metodo: IDENT PARENTESIS_ABIERTO declaracion_parametros PARENTESIS_CERRADO (DEV tipo)? ; declaracion_parametros :
declaracion_parametro (COMA declaracion_parametro)* |
;
declaracion_parametro : tipo IDENT ; definicion_metodo : LLAVE_ABIERTA declaraciones_variables_locales bloque LLAVE_CERRADA ; declaraciones_variables_locales :
(declaracion_variables_locales tipo IDENT) =>
declaracion_variables_locales declaraciones_variables_locales | (declaracion_variables_locales) => declaracion_variables_locales | ; declaracion_variables_locales :
lista_nombres_variables_locales :
nombre_variable_local (COMA nombre_variable_local)* ; nombre_variable_local : IDENT ; /////////////////////////////////////////////////////////// // INSTRUCCIONES ///////////////////////////////////////////////////////////
// Instrucciones simples en L-0: asignacion, retorno, // llamada a método
// Instrucciones compuestas en L-1: condicional e iteración /////////////////////////////////////////////////////////// instrucciones : (instruccion)* ; instruccion: instruccion_simple PUNTO_Y_COMA | instruccion_compuesta ; instruccion_simple :
(expresion ASIGNACION) => asignacion | llamada_metodo | retorno ; instruccion_compuesta : condicion | iteracion ; // Asignación. asignación :
expresion ASIGNACION expresion ;
// Devolución de resultado. retorno : DEV expresion ;
// Llamada a método (procedimiento) llamada_metodo : acceso PARENTESIS_ABIERTO lista_expresiones PARENTESIS_CERRADO ;
// Lista de expresiones
lista_expresiones : expresion (COMA expresion)* |
;
// Condicional: si condicion entonces ... en otro caso ...
condicion : SI PARENTESIS_ABIERTO expresion PARENTESIS_CERRADO ENTONCES bloque
(SINO bloque)? FINSI ;
// Iteración: mientras condicion hacer ...
iteracion : MIENTRAS PARENTESIS_ABIERTO expresion PARENTESIS_CERRADO HACER bloque
FINMIENTRAS ;
// Bloque de instrucciones en instrucciones compuestas y métodos bloque: instrucciones
;
///////////////////////////////////////////////////////////// // EXPRESIONES
////////////////////////////////////////////////////////////
// Reglas para cubrir estructuralmente una expresión en L-0 // Las expresiones pueden ser: lógicas, aritméticas (enteras // o reales) o de carácter //////////////////////////////////////////////////////////// expresion : expresion_nivel_1 (O expresion_nivel_1)* ; expresion_nivel_1 : expresion_nivel_2 (Y expresion_nivel_2)* ; expresion_nivel_2 : NO expresion_nivel_2 | expresion_nivel_3 ; expresion_nivel_3 : expresion_nivel_4 ((MAYOR|MAYOR_IGUAL|MENOR|MENOR_IGUAL|IGUAL|DISTINTO) expresion_nivel_4)? ; expresion_nivel_4 :
expresion_nivel_5 ((MAS|MENOS) expresion_nivel_5)* ;
expresion_nivel_5 :
expresion_nivel_6 ((POR|DIVISION) expresion_nivel_6)* ; expresion_nivel_6 :
| expresion_nivel_7 ;
expresion_nivel_7 :
PARENTESIS_ABIERTO expresion PARENTESIS_CERRADO | (acceso PARENTESIS_ABIERTO) => llamada_metodo
| (acceso CORCHETE_ABIERTO) => acceso_tabla | acceso | LIT_ENTERO | LIT_REAL | LIT_CAR | CIERTO | FALSO ;
// Acceso a un elemento de una formación
acceso_tabla: acceso CORCHETE_ABIERTO lista_expresiones_nv CORCHETE_CERRADO ;
// Accesos simples y a objetos (máximo un nivel) acceso:
(IDENT PUNTO) => IDENT PUNTO IDENT | IDENT
;
// Lista no vacía de expresiones lista_expresiones_nv :
expresion (COMA expresion)* ;
////////////////////////////////////////////////////////// // TIPOS
/////////////////////////////////////////////////////////
// L-0 dispone de tipos predefinidos básicos, tipos // predefinidos compuestos y clases definidas por el // programador. ///////////////////////////////////////////////////////// tipo : tipo_predefinido_simple | tipo_predefinido_compuesto | IDENT ;
// Los tipos básicos o predefinidos en L-0 son: // entero, real, carácter y lógico
tipo_predefinido_simple : ENTERO
| LOGICO | CARACTER ; tipo_predefinido_compuesto : formacion ;
formacion : FORMACION lista_enteros (tipo_predefinido_simple | IDENT);
3.- ANÁLISIS SINTÁCTICO Y CONSTRUCCIÓN DEL ASA DE L-0 header{
import java.util.*; import antlr.*; }
class Anasint extends Parser; options{ buildAST=true; } tokens{ PROGRAMA; VISIBLE; NO_INST; ATRIBUTO; METODO; PROTOTIPO; PARAMETRO; PARAMETROS; EXPRESIONES; RESULTADO; DEFINICION; VACIO; VARIABLE_LOCAL; VARIABLES_LOCALES; INSTRUCCION; INSTRUCCIONES; MENOSUNARIO; LLAMADA; ACCESO_TABLA; ACCESO_OBJETO; ACCESO_SIMPLE; LISTA_ENTEROS; } { } ///////////////////////////////////////////////////////// // DECLARACION DE MODULO /////////////////////////////////////////////////////////
declaracion_modulo! : n:nombre_modulo d:definicion_modulo EOF { #declaracion_modulo = #(#[MODULO,"modulo"],#n, #d); } ;
nombre_modulo : MODULO! IDENT ; definicion_modulo : lista_declaraciones_clases ; lista_declaraciones_clases : (declaracion_clase)+ ; /////////////////////////////////////////////////////////// // DECLARACIÓN DE CLASE /////////////////////////////////////////////////////////// declaracion_clase ! : c:cualificador_clase n:nombre_clase d:definicion_clase { #declaracion_clase = #(#[CLASE,"clase"],#n,#c,#d); } ; cualificador_clase! :
INST {#cualificador_clase = #(#[INST]);}
| {#cualificador_clase = #(#[NO_INST,"no_inst"]);} ;
nombre_clase : CLASE! IDENT ; definicion_clase : CLASE IDENT METODO/ATRIBUTO
*
INST / NO INST MODULO IDENT CLASE+
LLAVE_ABIERTA! declaraciones_elemento_clase LLAVE_CERRADA! ; declaraciones_elemento_clase : (declaracion_elemento_clase)* ; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // DECLARACIÓN DE ELEMENTO CLASE: MÉTODO O ATRIBUTO ///////////////////////////////////////////////////////////////////////////////////////////////////////////// declaracion_elemento_clase! : c:cualificador_elemento_clase ((IDENT PARENTESIS_ABIERTO) => a:declaracion_metodo { #declaracion_elemento_clase = #(#[METODO,"metodo"],#a,#c); } | t:tipo i:IDENT PUNTO_Y_COMA
{ #declaracion_elemento_clase = #(#[ATRIBUTO,"atributo"],#i,#t,#c); }) ;
// Cualificador de visibilidad cualificador_elemento_clase! :
OCULTO {#cualificador_elemento_clase = #(#[OCULTO]);}
ATRIBUTO
IDENT tipo OCULTO/VISIBLE
METODO
PROTOTIPO DEFINICION OCULTO/VISIBLE
IDENT PARAMETROS RESULTADO
tipo / VACIO PARAMETRO
VARIABLES_LOCALES INSTRUCCIONES
VARIABLE_LOCAL INSTRUCCION
| {#cualificador_elemento_clase = #(#[VISIBLE,"visible"]);} ; declaracion_metodo : prototipo_metodo definicion_metodo ; prototipo_metodo! : i:IDENT PARENTESIS_ABIERTO p:declaracion_parametros PARENTESIS_CERRADO (DEV t:tipo {#prototipo_metodo = #(#[PROTOTIPO,”prototipo”],#i,#(#[PARAMETROS,"parametros"],#p), #(#[RESULTADO,"resultado"],#t));} | {#prototipo_metodo = #(#[PROTOTIPO,”prototipo”],#i,#(#[PARAMETROS,"parametros"],#p), #(#[RESULTADO,"resultado"],#[VACIO, “vacio”]));} ) ; declaracion_parametros :
declaracion_parametro (COMA! declaracion_parametro)* |
;
/////////////////////////////////////////////////////////// // DECLARACIÓN DE PARÁMETRO ///////////////////////////////////////////////////////////
declaracion_parametro!: t:tipo i:IDENT
{#declaracion_parametro = #(#[PARAMETRO,”parametro”],#i,#t);} ; definicion_metodo! : LLAVE_ABIERTA d: declaraciones_variables_locales b: bloque LLAVE_CERRADA {#definicion_metodo= #(#[DEFINICION,”definicion”],#(#[VARIABLES_LOCALES,”variables_locales”],#d), #b);} PARAMETRO IDENT tipo
;
declaraciones_variables_locales :
(declaracion_variables_locales tipo IDENT) =>
declaracion_variables_locales declaraciones_variables_locales |(declaracion_variables_locales) => declaracion_variables_locales | ; declaracion_variables_locales :
t:tipo! lista_nombres_variables_locales[#t] PUNTO_Y_COMA! ; lista_nombres_variables_locales [AST t] :
nombre_variable_local[#t] (COMA! nombre_variable_local[#t])* ;
///////////////////////////////////////////////////////////////// // DECLARACIÓN DE VARIABLE LOCAL ////////////////////////////////////////////////////////////////// nombre_variable_local! [AST t] : i:IDENT { #nombre_variable_local = #(#[VARIABLE_LOCAL,"variable_local"],#i,#t); } ; /////////////////////////////////////////////////////////// // INSTRUCCIONES /////////////////////////////////////////////////////////// instrucciones : (instruccion)* ; instruccion! : i:instruccion_simple PUNTO_Y_COMA {#instruccion=#(#[INSTRUCCION,"instruccion"],#i);} | j:instruccion_compuesta {#instruccion=#(#[INSTRUCCION,"instruccion"],#j);} ; instruccion_simple :
(expresion ASIGNACION) => asignacion | llamada_metodo
| retorno ;
VARIABLE_LOCAL
instruccion_compuesta : condicion
| iteracion ;
asignacion! :
e1:expresion ASIGNACION e2:expresion { #asignacion = #(#[ASIGNACION],#e1,#e2); } ;
retorno! : DEV e:expresion { #retorno = #(#[DEV],#e); } ; llamada_metodo! : i:acceso PARENTESIS_ABIERTO s:lista_expresiones PARENTESIS_CERRADO { #llamada_metodo = #(#[LLAMADA,"llamada"],#i,#(#[EXPRESIONES,”expresiones”],#s)); } LLAMADA acceso expresion
*
EXPRESIONES ASIGNACION expresion expresion DEV expresion;
lista_expresiones : expresion (COMA! expresion)* |
;
condicion : SI^ PARENTESIS_ABIERTO! expresion PARENTESIS_CERRADO! ENTONCES! bloque
(SINO! bloque)? FINSI! ;
iteracion : MIENTRAS^ PARENTESIS_ABIERTO! expresion PARENTESIS_CERRADO! HACER! bloque FINMIENTRAS! ; bloque!: i:instrucciones {#bloque=#(#[INSTRUCCIONES,”instrucciones”],#i);} ; ///////////////////////////////////////////////////////////// // EXPRESIONES //////////////////////////////////////////////////////////// expresion :
expresion_nivel_1 (O^ expresion_nivel_1)* ;
SI expresion INSTRUCCIONES
*
INSTRUCCION INSTRUCCIONES*
INSTRUCCION MIENTRAS expresion INSTRUCCIONES*
INSTRUCCION
expresion_nivel_1 :
expresion_nivel_2 (Y^ expresion_nivel_2)* ; expresion_nivel_2 : NO^ expresion_nivel_2 | expresion_nivel_3 ; expresion_nivel_3 : expresion_nivel_4 ((MAYOR^|MAYOR_IGUAL^|MENOR^|MENOR_IGUAL^|IGUAL^|DISTINTO^) expresion_nivel_4)? ; expresion_nivel_4 :
expresion_nivel_5 ((MAS^|MENOS^) expresion_nivel_5)* ;
expresion_nivel_5 :
expresion_nivel_6 ((POR^|DIVISION^) expresion_nivel_6)* ; expresion_nivel_6 : MENOS i:expresion_nivel_6 {#expresion_nivel_6=#(#[MENOSUNARIO,"menosunario"],#i);} | j:expresion_nivel_7 {#expresion_nivel_6=#j;} ; expresion_nivel_7 :
PARENTESIS_ABIERTO! expresion PARENTESIS_CERRADO! | (acceso PARENTESIS_ABIERTO) => llamada_metodo
| (acceso CORCHETE_ABIERTO) => acceso_tabla | acceso | LIT_ENTERO | LIT_REAL | LIT_CAR | CIERTO | FALSO ; ///////////////////////////////////////////////////////////////////////////////// // ACCESOS A ELEMENTOS DE FORMACIONES /////////////////////////////////////////////////////////////////////////////////
acceso_tabla! :
c:acceso CORCHETE_ABIERTO d:lista_expresiones_nv CORCHETE_CERRADO {#acceso_tabla =#(#[ACCESO_TABLA,"acceso_tabla"], #c,
#(#[EXPRESIONES,”expresiones”],#d));} //////////////////////////////////////////////////////////////
// ACCESOS SIMPLES Y A OBJETOS //////////////////////////////////////////////////////////////
acceso:
(IDENT PUNTO)=> i1:IDENT PUNTO i2:IDENT
{#acceso=#(#[ACCESO_OBJETO,"acceso_objeto"],#(#[ACCESO_SIMPLE],#i1),#i2);} | i:IDENT
{#acceso=#(#[ACCESO_SIMPLE,"acceso_simple"],#i);} ;
lista_expresiones_nv :
expresion (COMA! expresion)* ; ////////////////////////////////////////////////////////// // TIPOS ///////////////////////////////////////////////////////// tipo : tipo_predefinido_simple | tipo_predefinido_compuesto | IDENT ACCESO_TABLA acceso expresion
+
EXPRESIONES ACCESO_SIMPLE IDENT ACCESO_OBJETO ACCESO_SIMPLE IDENT IDENT; tipo_predefinido_simple : ENTERO | REAL | LOGICO | CARACTER ; tipo_predefinido_compuesto : formacion ;
formación! : FORMACION l:lista_enteros ( t:tipo_predefinido_simple
{#formacion = #(#[FORMACION],#(#[LISTA_ENTEROS,”lista_enteros”],#l),#t);} | i:IDENT
{#formacion = #(#[FORMACION],#(#[LISTA_ENTEROS,”lista_enteros”],#l),#i);} );
lista_enteros : LIT_ENTERO (COMA! LIT_ENTERO)*;
FORMACION
LISTA_ENTEROS Tipo
LIT_ENTERO