Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Lex Sint PDF
Lex Sint PDF
Procesadores de Lenguajes
OBJETIVO
Dar respuesta a las siguientes preguntas:
Qu es el anlisis lxico-sintctico de un lenguaje?
Cmo se disea y construye un analizador lxico-sintctico?
LENGUAJE DE EJEMPLO
Para presentar este tema utilizaremos un lenguaje de programacin hipottico llamado LF.
Definicin informal : Se trata de un lenguaje de programacin secuencial con variables enteras y
dos tipos de instrucciones: (a) definicin de variables con expresin entera (DEF) y (b)
evaluacin de variables (EVAL). No se acepta el uso de variables sin declarar. La declaracin de
variables asocia valor 0 por defecto. Cuando se define una variable se le asocia una expresin
entera sin evaluar. Esta expresin se evala justo al ejecutar la instruccin EVAL sobre dicha
variable. Toda variable definida sobre s misma se le asocia un valor indefinido.
Se muestra un programa tpico para precisar la sintaxis de LF.
VARIABLES
x, y, z, a, b;
INSTRUCCIONES
a DEF -1;
b DEF (a+1);
EVAL b;
a DEF 2;
EVAL b;
b DEF b + 1;
z DEF 2*y;
EVAL z;
EVAL b;
b = 3
z = 0
Sentencia
Filtro
1.1:
Analizador
lxico
lexemas
s
Filtro
1.2:
(asa)
Analizador
sintctico
Para reconocer los lexemas de un lenguaje usaremos expresiones regulares y para reconocer
estructuras sintcticas usaremos gramticas independientes de contexto (gramtica en
adelante).
Una gramtica es un conjunto de reglas. Cada regla es de la forma genrica:
cabeza : cuerpo1 | cuerpo2 | ... | cuerpoN
siendo N>=1
Ejemplo 2. Derivacin.
programa -> variables instrucciones -> VARIABLES idents PyC
instrucciones -> VARIABLES VAR COMA idents PyC instrucciones ->
Si no es posible construir una derivacin que genere la sentencia completa como secuencia de
lexemas entonces dicha sentencia no pertenece al lenguaje especificado en la gramtica.
Una gramtica es determinista si toda sentencia perteneciente al lenguaje especificado por
dicha gramtica tiene una nica derivacin. La gramtica propuesta para el lenguaje LF (Ejemplo
1) no es determinista. El no determinismo se debe a la existencia de prefijos comunes para
distintas alternativas en una misma regla. Por ejemplo, la regla idents : VAR COMA idents
| VAR | ; tiene el prefijo comn VAR en sus 2 primeras alternativas. Los prefijos comunes
pueden producirse sobre smbolos no terminales. Por ejemplo sobre los smbolos expr1 y
expr2 en las reglas correspondientes a la definicin de expresin.
Una forma de resolver el problema del prefijo comn es usar predicados sintcticos. Los
predicados sintcticos son condiciones aadidas a las alternativas para reconocer de manera
tentativa un determinado prefijo de lexemas. Si es as, se selecciona la alternativa
correspondiente. Si no, se selecciona la siguiente alternativa en la regla (y as sucesivamente).
La siguiente gramtica resuelve el problema de la gramtica original (Ejemplo 1) usando prefijos
comunes.
Los lexemas o tokens son los smbolos terminales que aparecen en la gramtica y representan
las distintas categoras de palabras y smbolos de puntuacin que podemos encontrar en una
sentencia del lenguaje. Los lexemas de un lenguaje se definen con reglas de la forma:
LEXEMA : expresion regular
donde expresion regular puede ser:
(1) carcter (ej. '('),
(2) concatenacin de caracteres (ej. "INSTRUCCIONES") ,
(3) rango de caracteres (ej. '0'..'9'),
(4) conjunto negativo de caracteres (ej. ~('0'|'1')),
(5) opcin (ej. (('a'..'z')?),
(6) alternativa (ej. 'a'..'z'|'A'..'Z') y
(7) cierre (ej. (LETRA)+).
Las reglas que definen los lexemas del lenguaje LF se muestran a continuacin.
expr2
NUMERO
MENOS^ expr
VAR
PA! expr PC!
El asa es una expresin #(nodo, subrbol1 , , subarbolk) donde nodo es un asa elemental
formado por un nico lexema y subrbol1, , subarbolk son los asas hijos de nodo.
El asa elemental o nodo se puede expresar de diferentes maneras:
1. #[LEXEMA, "txt"] donde LEXEMA es el identificador del lexema y "txt" es el
texto asociado al lexema. Por ejemplo, #[PROGRAMA, "PROGRAMA"]
2. #[LEXEMA] donde LEXEMA es el identificador del lexema.
3. LEXEMA donde LEXEMA es el identificador del lexema.
Cada smbolo no terminal de la gramtica puede sintetizar un asa o una secuencia de asas. Por
ejemplo, el smbolo idents sintetiza una secuencia de asas y el smbolo programa sintetiza un
asa. Cada lexema de la gramtica, por el contrario, slo puede sintetizar un asa con un nico
nodo.
Podemos referenciar los asas sintetizados con etiquetas. Por ejemplo, la regla variables !:
a:VARIABLES b:idents PyC; define dos etiquetas: la etiqueta a para referirse al asa
#[VARIABLES] y la etiqueta b para referirse al asa #idents.
Para referirnos a todos los asas sintetizados por el cuerpo de una regla se tiene la expresin ##.
La programacin de asas es una actividad importante en el desarrollo de un procesador.
ANTLR construye asas de forma automtica segn el orden de derivacin. Por ejemplo, la regla
definicion : VAR DEF expr PyC; construira un asa #definicion con nodo raz VAR y
con 3 asas hijos (de izquierda a derecha: #[DEF], #expr y #[PyC]). Podemos cambiar la forma
de sintetizar el asa haciendo uso de los operadores ^ y !. El operador ^ slo se puede usar como
sufijo de un lexema y sirve para enraizar. El operador ! se puede usar como sufijo de cualquier
smbolo y sirve para evitar la construccin de asas. Por ejemplo, la regla definicion : VAR
DEF^ expr PyC!; construye un asa llamado #definicion donde DEF es la raz , VAR es el
primer asa hijo (con un nico nodo) y expr es el segundo asa hijo. PyC es un lexema que no
forma parte del asa. Cuando este operador ! se usa como sufijo en la cabeza de la regla, la regla
no construye ningn asa de forma automtica.
ANTLR proporciona una biblioteca para programar asas llamada antlr. Esta biblioteca incluye
una interfaz AST para el tipo rbol sintaxis abstracta y la clase CommonAST para implementarlo.
El nodo del asa tiene 2 campos principales: el lexema y el texto asociado el lexema. Podemos
consultar estos campos con las operaciones: getType() y getText().Podemos modificar
estos campos con las operaciones: setType(int) y setText(String).
Las operaciones getFirstChild() y getNextSibling() servirn para visitar los nodos del
asa y las operaciones setFirstChild(AST) and setNextSibling(AST) para construir el
asa.
ANTLR tambin proporciona una clase ASTFactory que permite hacer una copia de un asa
dupTree(AST) y una copia de una secuencia de asas dupList(AST).
Una vez diseada la gramtica se tiene constancia de los lexemas del lenguaje. El diseo de
los lexemas se basa en un conjunto de recomendaciones:
Los lexemas con formas alternativas de caracteres pueden expresarse con expresiones
regulares alternativas. Por ejemplo, BTF: (' '|'\t'|NL);.
Los lexemas con formas iterativas de caracteres pueden expresarse con expresiones regulares
de tipo cierre. Por ejemplo, NUMERO : (DIGITO)+;.
Los lexemas con partes opcionales pueden expresarse con expresiones regulares de tipo
opcin.
Los lexemas con forma de rango de caracteres pueden expresarse con expresiones regulares de
tipo rango. Por ejemplo, LETRA : 'a'..'z'|'A'..'Z';
Los lexemas con forma de secuencia de caracteres pueden expresarse con expresiones
regulares de tipo concatenacin. Por ejemplo, INSTRUCCIONES: "INSTRUCCIONES";
Los lexemas con 1 carcter pueden expresarse con expresiones regulares de tipo carcter.. Por
ejemplo, MAS : '+' ;.
El uso de lexemas auxiliares facilita la legibilidad de las expresiones regulares. Por ejemplo, VAR
: (LETRA)+; siendo LETRA : 'a'..'z'|'A'..'Z'; un lexema auxiliar.
En este punto, se propone la implementacin de la primera versin del analizador lxicosintctico en ANTLR.
La gramtica mostrada en Ejemplo 5 constituir el ncleo principal del parser ANTLR.
Ejemplo 6. Parser Antlr para el lenguaje LF.
class Anasint extends Parser;
programa : variables instrucciones EOF
;
variables : VARIABLES idents PyC
;
idents : (VAR COMA) => VAR COMA idents
| VAR
|
;
instrucciones : INSTRUCCIONES (definicion|evaluacion)*
;
definicion : VAR DEF expr PyC
;
evaluacion : EVAL idents PyC
;
expr : (expr1 MAS) => expr1 MAS expr
| (expr1 MENOS) => expr1 MENOS expr
| expr1
;
expr1 : (expr2 POR) => expr2 POR expr1
| expr2
;
expr2 : NUMERO
| MENOS expr
| VAR
java.io.FileInputStream;
java.io.IOException;
java.io.FileNotFoundException;
antlr.RecognitionException;
antlr.TokenStreamException;
Si lo que se quiere testar es slo el analizador lxico entonces el programa de prueba para
hacerlo se muestra en el siguiente ejemplo.
java.io.FileInputStream;
java.io.FileNotFoundException;
antlr.Token;
antlr.TokenStreamException;
Una vez testada la primera versin del analizador, se anota la gramtica para que sea capaz
de construir rboles de sintaxis abstracta. Para anotar la gramtica, primero hay que tener
claro cul es la estructura del rbol. El siguiente ejemplo muestra la estructura de asa requerida.
10
Ejemplo 11. Parser Antlr para el lenguaje LF con la capacidad de construir ASAs.
class Anasint extends Parser;
options{
buildAST = true;
}
tokens{
PROGRAMA;
}
programa : variables instrucciones EOF!
{#programa = #(#[PROGRAMA, "PROGRAMA"], ##);}
;
variables !: a:VARIABLES b:idents PyC {#variables = #(#a,#b);}
;
idents : (VAR COMA) => VAR COMA! idents
| VAR
11
java.io.FileInputStream;
java.io.FileNotFoundException;
antlr.RecognitionException;
antlr.TokenStreamException;
antlr.collections.AST;
antlr.debug.misc.ASTFrame;
12