Você está na página 1de 41

Universidad Nacional Experimental de Guayana

Vice-Rectorado Acadmico
Proyecto de Carrera: Ingeniera en Informtica
Lenguajes y Compiladores 2016-I
Seccin 2

Analizador Sintctico

PROFESOR:
INTEGRANTES: Flix Mrquez.

Capella

Genghis V-19800720
Castro Jhon V-18579925
Fernndez Carlos V-20219273
Morales Nstor V-19995576

Ciudad Guayana, julio 2016.

Actividad del tema.


1. Presentar un informe de investigacin terico-prctico en el cual explique el
mtodo de cada tipo de parser, es necesario que indique la fuente donde se obtienen
los conceptos que presentar en dicho informe y presente al menos dos ejemplos 2 de
parser realizado a la gramtica seleccionada en el tema 3 tanto para anlisis
ascendentes como descendentes para una secuencia de componentes lxicos elegidos
por Usted. En otras palabras, se mencionaron 5 mtodos, el grupo debe presentar 2
ejemplos de parser por cada mtodo.

Qu es el analizador sintctico
Es la fase del analizador que se encarga de chequear el texto de entrada en base a
una gramtica dada. Y en caso de que el programa de entrada sea vlido, suministra el
rbol sintctico que lo reconoce.
En teora, se supone que la salida del analizador sintctico es alguna
representacin del rbol sintctico que reconoce la secuencia de tokens suministrada
por el analizador lxico.
En la prctica, el analizador sintctico tambin hace:

Acceder a la tabla de smbolos (para hacer parte del trabajo del analizador

semntico).
Chequeo de tipos (del analizador semntico).
Generar cdigo intermedio.
Generar errores cuando se producen.
En definitiva, realiza casi todas las operaciones de la compilacin. Este mtodo

de trabajo da lugar a los mtodos de compilacin dirigidos por sintaxis.

Tipo de gramtica que acepta un analizador sintctico

Centrndonos en el anlisis sintctico para lenguajes basados en gramticas


formales, es la mejor forma para comprensin del compilador ya que de otra forma se
no aria difcil, y se pueden corregir, quizs ms fcilmente, errores de muy difcil
localizacin, como es la ambigedad en el reconocimiento de ciertas sentencias.

La gramtica que acepta el analizador sintctico es una gramtica de contexto


libre:

Gramtica: G (N, T, P, S) N = No terminales.


T = Terminales.
P = Reglas de Produccin.
S = Axioma Inicial.

Tipos de Anlisis
De la forma de construir el rbol sintctico se desprenden dos tipos o clases de
analizadores sintcticos. Pueden ser descendentes o ascendente

Descendentes: Parten del axioma inicial, y van efectuando derivaciones a


izquierda hasta obtener la secuencia de derivaciones que reconoce a la
sentencia.

Pueden ser: Con retroceso.


Con recursin.
LL(1)

Ascendentes: Parten de la sentencia de entrada, y van aplicando reglas de


produccin hacia atrs (desde el consecuente hasta el antecedente), hasta
llegar al axioma inicial.

Pueden ser: Con retroceso.


LR(1)
Anlisis descendente con retroceso.

Objetivo: El mtodo parte del axioma inicial y aplica todas las posibles
reglas al no terminal ms a la izquierda.

Ejemplo: Utilizaremos la siguiente gramtica (No recursiva por la izquierda)

Para reconocer la cadena de entrada: (a + b) * a + b

Mediante este rbol se pueden derivar todas las posibles sentencias reconocibles
por esta gramtica y el objetivo de este algoritmo es hacer una bsqueda en este rbol de
la rama que culmine en la sentencia a reconocer. El mecanismo funciona mediante una

bsqueda primero en profundidad. Mira si todos los tokens a la izquierda de un No


Terminal coinciden con la cabeza de la secuencia a reconocer. En todo el rbol de
derivaciones, se pretende profundizar por cada rama hasta llegar a encontrar una forma
sentencial que no puede coincidir con lo que se busca, en cuyo caso se desecha, o que
coincide con lo buscado, momento en que se acepta la sentencia. Si por ninguna rama se
puede reconocer, se rechaza la sentencia.
NOTA: Este mtodo no funciona con gramticas recursivas a la izquierda, ya que puede
ocurrir que entre en un bucle infinito. No existen muchos analizadores sintcticos con
retroceso. En parte, porque casi nunca se necesita el retroceso para analizar
sintcticamente las construcciones de los lenguajes de programacin. En casos como el
anlisis sintctico del lenguaje natural, el retroceso tampoco es muy eficiente, y se
prefieren otros mtodos.
Reconocer con el algoritmo (a+b)*a+b

Anlisis descendente con recursin. Diagramas de Conway


Una gramtica de contexto libre puede expresar un lenguaje al igual que puede
hacerlo la notacin BNF, y los diagramas de Conway.

Definicin: Un diagrama de Conway es un grafo dirigido donde los


elementos no terminales aparecen como rectngulos, y los terminales
como crculos.

Para demostrar que permite representar las mismas gramticas que la BNF, se hace por
induccin sobre las operaciones bsicas de BNF:

De esta forma todos los posibles caminos desde el inicio del grafo hasta el final,
representan formas sentenciales vlidas. En todo diagrama de Conway hay un origen y un
destino.

Ejemplo: Yuxtaposicin

Ejemplo:

Consideremos la siguiente gramtica:


S : 'c' A 'd'
A : 'a' 'b'
A : 'a
Cadena de entrada: w=cad

Anlisis descendente de gramticas LL(1)


Una gramtica LL(1) es aquella en la que su tabla de chequeo de sintaxis no posee
entradas mltiples, o sea, es suficiente con examinar slo un smbolo a la entrada, para
saber qu regla aplicar. Toda gramtica reconocible mediante el mtodo de los diagramas
de Conway es LL(1)
El mtodo consiste en seguir un algoritmo partiendo de:

La cadena a reconocer, junto con un apuntador, que nos indica cual es el token

actual.
Una pila de smbolos (terminales y no terminales)
Una tabla asociada de forma unvoca a una gramtica.

En este ejemplo no vamos a ver como calcular dicha tabla. La cadena de entrada acabar
en el smbolo $, que consideramos como si fuese un EOF (End Of File - Fin de Fichero).
Sea X el elemento encima de la pila, y a, el apuntado en la entrada. El algoritmo consiste
en:
1.- Si X = a = $ entonces ACEPTAR.
2.- Si X = a g $ entonces
- se quita X de la pila
- y se avanza el apuntador.
3.- Si X T y X g a entonces RECHAZAR.
4.- Si X N entonces consultamos la entrada M[X,a] de la tabla:
- M[X,a] es vacia: RECHAZAR.
- M [X,a] no es vacia, se quita a X de la pila y se inserta el
consecuente en orden inverso
- M [X,a] no es vacia, se quita a X de la pila y se inserta el
consecuente en orden inverso.
Ejemplo: Si M[X,a] = {X UVY}, se quita a X de la pila, y se meten UVY en orden

inverso

5.- Ir al paso 1.
Una vez aplicada una regla, no ser desaplicada por ningn tipo de retroceso.
El algoritmo comienza con $ y con el axioma inicial metidos en la pila.
Ejemplo:

Ejemplo:

Anlisis Ascendente con retroceso.

Cuando se da cuenta que llega a una situacin en la que no puede continuar,


entonces vuelve atrs deshaciendo todos los cambios. En el anlisis con retroceso no se
permiten las reglas , puesto que estas se podrn aplicar de forma indefinida.
Este mtodo parte del axioma inicial y aplica todas las posibles reglas al no terminal ms a
la izquierda.

Se usa el retroceso para resolver la incertidumbre.

Sencillo de implementar.

Muy eficiente.

Ejemplo:

Ejemplo: (Vamos a ver por qu no se permiten las reglas ). Supongamos la siguiente


gramtica.

No puede aparecer en una gramtica ascendente con retroceso porque da lugar a


recursin infinita.
Ejemplo: Reconocer a*a = id * id, dada la siguiente gramtica:

(Llevaremos una pila para el Backtraking)

Analizadores LR
Anlisis sintctico LR(k); la L es por el examen de la entrada de izquierda a
derecha (en ingls, left-to-right), la R por construir una derivacin por la derecha (en
ingls, rightmost derivation) en orden inverso, y la k por el nmero de smbolos de entrada
de examen por anticipado utilizados para tomar las decisiones del anlisis sintctico.
Cuando se omite, se asume que k, es 1. El anlisis LR es atractivo por varias razones.
Pueden reconocer la inmensa mayora de los lenguajes de programacin que puedan ser
generados mediante gramticas de contexto-libre. El mtodo de funcionamiento de estos
analizadores posee la ventaja de localizar un error sintctico en el mismo instante que se
produce con lo que se adquiere una gran eficiencia de tiempo de compilacin frente a
procedimientos menos adecuados como puedan ser los de retroceso.

El principal inconveniente del mtodo es que supone demasiado trabajo construir


un analizador sintctico LR a mano para una gramtica de un lenguaje de programacin
tpico. Se necesita una herramienta especializada, un generador de analizadores sintcticos
LR para ello.
Existen tres tcnicas para construir una tabla de anlisis sintctico LR para una
gramtica.

El primer mtodo, llamado LR sencillo (SLR, en ingls) es el ms fcil de


implantar, pero el menos poderoso de los tres. Puede que no consiga
producir una tabla de anlisis sintctico para algunas gramticas que otros

mtodos si consiguen.
El segundo mtodo, llamado LR cannico, es el ms poderoso y costoso.
El tercer mtodo, llamado LR con examen por anticipado (LALR, en
ingls), est entre los otros dos en cuanto a poder y costo. El mtodo LALR
funciona con las gramticas de la mayora de los lenguajes de
programacin y, con un poco de esfuerzo, se puede implantar en forma
eficiente.

Funcionalmente hablando, un analizador LR consta de dos partes diferenciadas, un


programa de proceso y una tabla del anlisis.
El funcionamiento del analizador LR es el siguiente
1.- Se determina el estado sm en cabeza de la pila y el smbolo actual ai en el instante de
la cadena de entrada.
2.- Se consulta en la tabla de anlisis la funcin accin con los parmetros anteriores y
que puede dar como resultado.

por su parte la funcin GOTO acta igualmente con un estado y un smbolo de la


gramtica produciendo un nuevo estado.

Ejemplo: Expresiones aritmticas y tablas LR Sea la gramtica ya conocida de generacin


de expresiones aritmticas.

La figura siguiente muestra la tabla de anlisis con las funciones ACCIN y


GOTO para la gramtica anterior.

El significado de las entradas de la tabla anterior es la siguiente:


1.
2.
3.
4.

Di significa desplazar y meter en la pila el estado i,


Rj significa reducir por la regla de produccin con nmero j,
ACEP significa aceptar.
las entradas en blanco significan un error sintctico.

Ejemplo de reconocimiento para la cadena de entrada

a * ( a + a) = id * (id + id)
(Suponemos que el estado s0 queda representado por 0).

Se ha considerado reducir la cadena de entrada al smbolo inicial S, por lo tanto, la


sentencia pertenece al lenguaje generado por la gramtica dada. A la hora de hacer una
reduccin hay que tener cuidado al elegir las reglas a usar. Si en el paso 6 del ejemplo del
ejemplo anterior se fuese reducido usando la regla 3 en lugar de la 2 nos habra quedado
en la pila.

Y no se podra seguir a partir de aqu porque en la gramtica no existe ninguna regla a esa
combinacin de smbolos. Para que no se presente este problema, cada vez que vaya a
hacer una reduccin, el analizador sintctico ascendente tiene que saber reconocer las
reglas de produccin, que no bloqueen el anlisis y produzcan el retroceso (backtracking).
La gramtica LR posee la propiedad de realizar el anlisis ascendente sin retroceso.

2. Informe del metacompilador para anlisis sintctico y su integracin al lxico.

El metacompilador es sinnimo de compilador de compiladores y se refiere a un


programa que recibe como entrada las especificaciones del lenguaje para el que se
desea obtener un compilador y genera como salida el compilador para ese lenguaje.
Sabiendo esto, en nuestro compilador tendremos por un lado un generador de
analizador lxico (JFlex) y un generador de analizador sintctico (CUP), ambos pueden
integrar cada uno de sus procesos de estos compiladores y de esta forma obtener un
compilador mucho ms completo y personalizado.
JFlex es un metacompilador que permite generar rpidamente analizadores
lxicos que se integran con Java.

Las caractersticas sobre salientes de JFlex son las siguientes:

Soporte completo con caracteres Unicode.


Permite generar analizadores lxicos rpidamente.

Tiene una sintaxis cmoda de manipular y fcil de interpretar.


Es independiente de la plataforma debido a que est diseado para ser

integrado con Java.


Permite la integracin con CUP (Analizador sintctico)

Un archivo jflex est dividido en 3 secciones:

Opciones y declaraciones
La primera parte del archivo es el bloque donde se importarn los paquetes
que se van a utilizar para nuestro analizador, es decir, si en nuestro programa
utilizaremos componentes del paquete til debemos importar aqu dicho paquete:
import java.util.*;
Luego sigue un par de signos de porcentaje (%) para indicar que empezar
la definicin del bloque de configuracin del analizador. El bloque de
configuracin se define por el conjunto de parmetros que se especifican en el
archivo para decirle a nuestro a analizador como se debe comportar, cada
parmetro empieza con el smbolo % y se escribe solo uno por lnea, es decir, uno
de bajo del otro.
%unicode
%line
%column

Cdigo de usuario
En el siguiente fragmento de cdigo podremos incluir cdigo Java el cual
podemos utilizar en el analizador, cabe notar que el cdigo que aqu se escriba ser
incluido sin ninguna alteracin al resultado final del analizador, dicho fragmento
ira enmarcado entre las etiquetas%{ al inicio del cdigo y %} al final del mismo.
%{
public static void escribir(String cadena)
{

System.out.println(cadena);
}
%}

Reglas lexicogrficas
El siguiente fragmento formar parte esencial dentro del funcionamiento del

analizador, en este se definirn el conjunto de expresiones regulares que se utilizarn


durante el proceso de anlisis, a continuacin, se presentan unos ejemplos de este tipo
de declaraciones:
FinDeLinea = nr | nn | nrnn

Variable = [:jletter:][:jletterdigit:]*
Si = Si
Entero = 0 | [1-9][0-9]*

En la prxima lnea de cdigo se especifican los posibles estados en los que se


encontrar el analizador, esta funcionalidad es muy til a la hora de identificar el
contexto en el que se est realizando el anlisis. %state CADENA La ltima parte de
cdigo es donde se le especificar al analizador los tokens y que acciones realizar
cuando se encuentren dichos tokens, para inicial este fragmento debemos insertar
nuevamente un doble smbolo de porcentaje (%%):
"Inicio" {System.out.println("Palabra Inicio")}
"+" {System.out.println("Smbolo +")}
{FinDeLinea} {System.out.println("Fin de lnea")}
Reglas y acciones
La seccin de Reglas lxicas de JFlex contiene expresiones regulares y acciones
(Cdigo Java) que son ejecutadas cuando el analizador encuentra cadenas asociadas a las
expresiones regulares. As como el escner lee las entradas, tambin hace seguimiento a
todas las expresiones regulares y activa la accin del patrn que tenga la ms grande
coincidencia, por ejemplo, para la especificacin anterior, la cadena Sino coincide en parte
con la expresin Si, pero como la expresin regular Variable tiene mayor nmero de
coincidencias (coincide totalmente) entonces es esta ltima quien ejecuta la accin.
Para el caso en que dos expresiones regulares coincidan en su totalidad con una
cadena entrante entonces es el patrn que se ha especificado primero el que ejecuta la
accin.
Estados lxicos
Adicionalmente a las expresiones regulares, se pueden utilizar estados lxicos para
hacer las especificaciones ms exactas. Un estado lxico como una condicin de inicio,
una cadena, entre otros. Si el escner se encuentra en estado CADENA, entonces solo las
expresiones regulares que se estn precedidas por la condicin inicial <CADENA> podrn
ser evaluados. La condicin inicial de una expresin regular puede contener ms de un
estado lxico, de ser as, dicha expresin regular se evaluar cuando el escner se
encuentre en cualquiera de esos estados iniciales. El estado lxico inicial del escner es
YYINITIAL y es con este el cual se empieza a escanear, si una expresin regular no tiene

condicin inicial esto quiere decir que podr ser evaluada en cualquier estado lxico que
se encuentre el escner.
<YYINITIAL>"Inicio" {System.out.println("Palabra Inicio")}
Dos mtodos importantes que se utilizan en el cdigo de accin de una expresin
regular son yybegin y yytext. yybegin se utiliza para decirle al escner que cambie el
estado lxico, por ejemplo: yybegin(CADENA), esto indica al escner que a partir del
llamado de esa funcin el escner se encontrar en el estado lxico CADENA, por otro
lado, tenemos yytext la cual devuelve la entrada la cual coincidi con la respectiva
expresin regular.
Reglas lxicas
Las reglas lxicas contienen un conjunto de expresiones regulares y acciones.
Definicin de la sintaxis
La sintaxis de las reglas lxicas de JFlex esta descrita por la siguiente gramtica:
LexicalRules ::= Rule+
Rule ::= [StateList] ['^'] RegExp [LookAhead] Action
| [StateList] 'EOF' Action
| StateGroup
StateGroup ::= StateList '{'Rule+ '}'
StateList ::= '<' Identifier (',' Identifier)* '>'
LookAhead ::= '$'| '/'RegExp

Action ::= '{'JavaCode '}'| '|'


RegExp ::= RegExp '|'RegExp
| RegExp RegExp
| '('RegExp ')'
| ('!'|'') RegExp
| RegExp ('*'|'+'|'?')
| RegExp "{"Number [","Number] "}"
| '['['^'] (Character|Character'-'Character)* ']'
| PredefinedClass
| '{' Identifier '}'

| '"'StringCharacter+ '"'
| Character
PredefinedClass ::= '[:jletter:]'
| '[:jletterdigit:]'
| '[:letter:]'
| '[:digit:]'
| '[:uppercase:]'
| '[:lowercase:]'
| '.'
La gramtica usa los siguientes smbolos terminales:

JavaCode
Es una secuencia que describe las especificaciones del lenguaje Java.

Number
Un nmero entero no negativo.
Identifier
Una secuencia de letras seguidas de cero o ms letras, dgitos o rallas al pie (_).

Character
Una secuencia de caracteres que no sean ninguno de los siguientes:
|(){}[]<>n.*+?^$/"!

StringCharacter
Una secuancia de caracteres que no sean ninguno de los siguientes:
\ "
Operadores en las expresiones regulares
Ahora se mostrarn los operadores que se pueden utilizar en la definicin de

expresiones regulares en el analizador lxico JFlex. Sean a y b expresiones regulares,


entonces:

a | b Unin
Es una expresin regular que encuentra todas las entradas que sean vlidas para

a b.

a b Concatenacin
Es una expresin regular que encuentra todas las entradas que sean vlidas para a

seguida de b.

a* Cerradura de Kleene
Es una expresin regular que encuentra todas las entradas que sean vlidas para

cero o ms repeticiones de a.

a+ Iteracin
Es una expresin regular que encuentra todas las entradas que sean vlidas para

una o ms repeticiones de a. Es equivalente a aa*

a? Opcin
Es una expresin regular que encuentra todas las entradas que sean vlidas para

cero o una ocurrencia de a.

!a Negacin
Es una expresin regular que encuentra todas las entradas que sean vlidas para

cualquier expresin diferente de a.

a{n} Repeticin
Es una expresin regular que encuentra todas las entradas que sean vlidas para

exactamente n repeticiones de a.

a{n}{m}
Es una expresin regular que encuentra todas las entradas que sean vlidas para

entre n y m repeticiones de a.

a
Es una expresin regular que encuentra todas las entradas que coincidan

exactamente con a.

Precedencia de operadores
JFlex usa la siguiente precedencia de operadores estndar para expresiones regulares:

Operadores unarios posfijos ('*', '+', '?', {n}, {n,m})


Operadores unarios prefijos ('!', '')
Concatenacin (RegExp::= RegExp Regexp)
Unin (RegExp::= RegExp '|'RegExp)

Entonces la expresin a | abc | !cd* terminar convertida en (a|(abc)) | ((!c)(d*)).

Mtodos y atributos de JFlex asequibles en el cdigo de accin


Todos los mtodos y atributos asequibles para el cdigo de accin de JFlex tiene el
prefijo yy para evitar que al momento de que el usuario. Los use generen conflicto con
otros mtodos o atributos de las dems clases. JFlex no tiene mtodos ni atributos pblicos
o privados, por el contrario utiliza los prefijos yy y zz para indicar que estos pueden ser
usados en el cdigo de accin o para el cdigo interno respectivamente. El API actual que
se puede utilizar en el cdigo de accin es:

String yytext() Devuelve la cadena que coincidi con la respectiva expresin

regular.
int yylength() Devuelve el tamao de la cadena que coincidi con la respectiva

expresin regular.
char yycharat(int pos) Devuelve el carcter que se encuentra en la posicin pos de

la cadena que coincidi con la respectiva expresin regular.


void yyclose() Cierra el ujo de la entrada de datos, por tanto a todas las entradas

siguientes arrojara n de archivo.


int yystate() Devuelve el estado lxico actual del analizador.
void yybegin(int estado) Cambia el estado lxico actual del analizador por el

nuevo estado especicado como parmetro.


int yyline Contiene el nmero de la lnea en la que se encuentra el analizador.
(Solo si se incluy la directiva%line).

int yychar Contiene el nmero del carcter que se est analizando.


int yycolumn Contiene el nmero de la columna en la que se encuentra el
analizador. (Solo si se incluy la directiva%column)

CUP es un metacompilador utilizado para generar un analizador sintctico ascendente con


algoritmos LALR. CUP es el homlogo para Java del programa YACC utilizado en C.
Sintaxis de un archivo .CUP
Un archivo de entrada CUP consta de las siguientes cinco partes:

1. Definicin de paquete y sentencias import.


2. Seccin de cdigo de usuario.
3. Declaracin de smbolos terminales y no terminales.
4. Declaraciones de precedencia.
5. Definicin del smbolo inicial de la gramtica y reglas de produccin.
Sentencias import e inclusin de paquete
Las especificaciones comienzan de forma opcional con las directivas package y
import Estas tienen la misma sintaxis y juegan el mismo rol que el package y el import de
un programa normal escrito en Java. La declaracin de un paquete tiene la forma:
package nombre_del_paquete; donde nombre_del_paquetes es el nombre del paquete al
que se est incluyendo la clase en Java. En general, CUP implementa las convenciones
lxicas de Java, como por ejemplo, soporta los dos tipos de comentarios que soporta Java.
Despus de la declaracin opcional de package, luego se pueden importar cero o ms
paquetes Java. Al igual que un programa escrito en Java importar un paquete se hace de la
forma:
import nombre_del_paquete.nombre_de_la_clase;
o
import nombre_del_paquete.*; En general, la declaracin del paquete indica en donde se
van a incluir las clases sym y parser que son generadas por el analizador. Todos los import
que aparezcan en el archivo fuente parecern luego en el archivo de la clase parser
permitiendo de esta forma utilizar las clases incluidas en el cdigo de accin.
Cdigo del programador
Despus de la declaracin opcional de import y package, viene una serie de
declaraciones opcionales que permiten al usuario escribir cdigo que luego har parte del
analizador generado como parte del archivo parser, pero separado en una clase no-pblica
que contendr todo el cdigo escrito por el usuario. Este cdigo va incluido entre la
siguiente directiva:
action code {: ... :};

en donde el cdigo que se incluir en el archivo parser ser el que esta incluido entre las
etiquetas {: :}.
Luego de la declaracin del cdigo de accin se puede hacer la declaracin
opcional del cdigo del analizador el cual se agregar directamente a la clase parser, este
cdigo es til cuando se va a personalizar algunos de los mtodos del analizador:
parser code {: ... :};
Otra vez, el cdigo que se copia dentro de la clase parser es el que se encuentra entre las
etiquetas {: :}.
La siguiente declaracin opcional es:
init with {: ... :};
Esta declaracin provee el cdigo que se va a ejecutar antes de que el analizador llame al
primer token. Esta declaracin es usada usualmente para inicializar el escner con tablas y
cierto tipos de datos que luego podrn ser utilizados por las acciones semnticas. En este
caso, el cdigo se escribir en un metodo void que se encuentra dentro de la clase parser.
La siguiente declaracin opcional permite indicar al analizador como debe preguntar por
el siguiente token del escner.
scan with {: ... :};
Al igual que la declaracin init el cdigo de este bloque se incluye en un mtodo dentro de
la clase parser, de cualquier forma este mtodo deber devolver un objeto de tipo
java_cup.runtime.Symbol, en consecuencia con esto el cdigo que sea incluido dentro de
la declaracin scan with deber devolver un objeto de este tipo.

Smbolos terminales y no terminales


Seguido de las declaraciones de cdigo de usuario viene la primera parte requerida
de las especificaciones: la lista de smbolos. Esta declaracin es la responsable de listar y
asignar un tipo para cada smbolo terminal o no terminal que aparece en la gramtica.
Como se mostrar, cada smbolo terminal o no terminal est representado en tiempo real
por un objeto de tipo Symbol. En el caso de los terminales, estos son retornados por el
escner y colocados en la pila del analizador. En el caso de los no terminales reemplazan
una serie de objetos Symbol en la pila del analizador siempre y cuando este concuerde con

la parte derecha de alguna produccin. Para efectos de especificar al analizador que tipo
de objeto es cada smbolo terminal o no terminal, se hace de la siguiente forma:
terminal Nombre_de_la_clase simbolo1, simbolo2, ... ; terminal simbolo1, simbolo2, ... ;
non terminal Nombre_de_la_clase simbolo1, simbolo2, ... ; non terminal simbolo1,
simbolo2, ... ;
donde Nombre_de_la_clase es la clase a la que pertenece el objeto simbolox.

Definicin de la precedencia de operadores


La siguiente seccin que es opcional, es donde se especifica la precedencia y
asociatividad de los terminales. Esta herramienta es muy til a la hora de analizar
gramticas ambiguas. Como se muestra en el siguiente ejemplo existen tres tipos de
declaraciones:
precedence left terminal, terminal, ...; precedence right terminal, terminal, ...; precedence
nonassoc terminal, terminal, ...;
La coma separa los terminales que deben tener asociatividad y en ese nivel de precedencia
que se esta declarando. El orden de la precedencia del mayor a menor es de abajo a arriba.
En el siguiente ejemplo el producto y la divisin son asociativos y tiene mayor
precedencia que la suma y la resta que son asociativos entre ellos.
precedence left SUMA, RESTA;
precedence left PRODUCTO, DIVISION;

La precedencia resuelve problemas de reduccin. Por ejemplo, en la entrada 3 + 53, el


analizador no sabe si reducir la pila, si por el + o por el , de cualquier forma, utilizando
precedencia se tiene que el tiene mayor precedencia que el + por lo tanto reducir
primero por el .
Definicin del smbolo inicial de la gramtica y reglas de produccin
Para denir el smbolo inicial de la gramtica se utiliza la construccin start with...;

start with Prog;


Ejecutando en generador de analizadores sintcticos
Como se ha mencionado, CUP esta escrito en Java. Para invocarlo se necesita un
interprete Java para invocar el mtodo esttico java_cup.Main(), pasando un arreglo de
string que contiene las opciones. La forma mas fcil de invocarlo es directamente desde la
lnea de comando de la siguiente forma:
java -jar java-cup-11a.jar opciones erchivo_de_entrada
Si todo ha salido bien se debern generar dos archivos .java, el sym.java y el
parser.java. La siguiente es la lista de opciones que se pueden pasar al archivo que genera
el cdigo del analizador: package name: Se le especifica al analizador que las clases sym y
parser sern agregadas al paquete name. Por defecto estas clases no sern agregadas a
ningn paquete.

parser name: Hace que el archivo del analizador se llame name en vez de parser

symbols namr: Hace que el archivo de smbolos se llame name en vez de sym
expect

number: Por lo general el analizador resuelve problemas de precedencia, esta


opcin coloca un lmite a ese nmero de errores que se pueden corregir, una vez
exceda este lmite el analizador se detendr por s solo.

nowarn: Evita que analizador arroje mensajes de prevencin o alertas (En ingles:
warnings)

nosummary: Normalmente, el sistema imprime una lista con cierto tipo de cosas
como los terminales, no terminales, estados del analizador, etc. al final de cada
ejecucin. Esta opcin elimina esta funcionalidad.

progress: Esta opcin causa que el sistema imprima pequeos mensajes indicando
varias partes del proceso de la creacin del analizador.

dump: Esta opcin causa que el sistema imprima pedazos de la gramtica, estados
del analizador y tablas de anlisis con el en de resolver conflictos en el anlisis.

time: Causa que el sistema muestre detalles de las estadisticas sobre los tiempos
resultantes del analizador. Muy til para futuros mantenimientos y optimizacin
del analizador.

version: Causa que CUP imprima la versin actual con la que se esta trabajando.

3. Informe de actividad donde documente paso a paso como construy su analizador


sintctico.
En la construccin de nuestro analizador sintctico resaltaremos los pasos ms
importantes en la construccin del mismo a continuacin:
1. Descargar CUP y agregarlo a nuestro proyecto de NetBeams
2. Luego de descargado el CUP descomprimir y ese archivo copiarlo en nuestro

directorio donde se aloja nuestro proyecto en nuestro caso

3. Ahora construimos nuestro archivo flex el cual tendr la siguiente estructura


(cada seccin se separa mediante %%):
Cdigo de usuario
Opciones y declaraciones
Reglas lxicas
Quedar definido de la siguiente manera:
import java.lang.System;
import java_cup.runtime.Symbol;
%%
%cup
%ignorecase
%type java_cup.runtime.Symbol
%class scanner
%implements java_cup.runtime.Scanner
%{
public void PrintToken(String str){
System.out.println(str);
}

%}
%eofval{
{System.exit(0);}
%eofval}
%line
%char

%state COMENTARIO
EspacioOTerminador = [\ \t\f\r|\n|\r\n]
Digito = [0-9]
Letra = [a-zA-Z]
INTAUX = ((("+"|"-")?({Digito})+)(("Ox(OX)"|"0")?))
ENTERO =((("+"|"-")?({Digito})(({Digito})*))(("Ox(OX)"|"0")?))
INT = ({ENTERO})
SEMI = ";"
COMMA = ","
TYPE = "int"
BINARYOP = ("+"|"-"|"*"|"/"|"%")
UNARYOP = ("++"|"--")
LOGICOSOP = (">"|">="|"<"|"<="|"=="|"!="|"&&"|"||"|"!")
ASIGOP = ("="|"+="|"-="|"*="|"/="|"%=")
LP = "("
RP = ")"
LB = "["
RB = "]"
LC = "{"
RC = "}"
STRUCT = "struct"
RETURN = "return"
IF = "if"
ELSE = "else"
BREAK = "break"
CONT = "continue"
FOR = "for"
ID = ({Letra}({Letra}|{Digito}|"_")*)
%%
<YYINITIAL> {TYPE}
{

System.out.println ("TYPE: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {BINARYOP}
{
System.out.println ("BINARYOP: " + yytext() + " en <lin " + yyline + " col " +

yychar + ">");
}
<YYINITIAL> {UNARYOP}
{
System.out.println ("UNARYOP: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {LOGICOSOP}
{
System.out.println ("LOGICOSOP: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {ASIGOP}
{
System.out.println ("ASIGOP: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {LP}
{
System.out.println ("LP: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {RP}
{
System.out.println ("RP: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {LB}
{
System.out.println ("LB: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}

<YYINITIAL> {RB}
{
System.out.println ("RB: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {LC}

{
System.out.println ("LC: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {RC}
{
System.out.println ("RC: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {SEMI}
{
System.out.println ("SEMI: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {COMMA}
{
System.out.println ("COMMA: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {STRUCT}
{
System.out.println ("STRUCT: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {RETURN}
{
System.out.println ("RETURN: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {IF}
{

System.out.println ("IF: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {ELSE}
{
System.out.println ("ELSE: " + yytext() + " en <lin " + yyline + " col " +

yychar + ">");
}
<YYINITIAL> {BREAK}
{
System.out.println ("BREAK: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {CONT}
{
System.out.println ("CONT: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {FOR}
{
System.out.println ("FOR: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {ID}
{
System.out.println ("ID: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> {INT}
{
System.out.println ("INT: " + yytext() + " en <lin " + yyline + " col " +
yychar + ">");
}
<YYINITIAL> [\n\r]+
{
yychar = 0;
}

<YYINITIAL> {EspacioOTerminador}+
{}
<YYINITIAL> "/*"
{
yybegin(COMENTARIO);
}

<COMENTARIO> [^"*/"]
{}
<COMENTARIO> "*/"
{
yybegin(YYINITIAL);
}
<YYINITIAL> .
{
System.out.println("Error lexico en " + yyline + " " + yychar +
" no se reconoce " + yytext());
yychar = 0; }

4. Luego crearemos nuestro parser.cup el cual no es ms que la definicin de la


sintaxis y de todo lo inherente a la definicin y correcta gramtica de nuestro
lenguaje L especificado en el tema anterior.
Nuestro fichero CUP se puede diferenciar del Lexer por:

Especificaciones de package e imports.


Componentes de cdigo de usuario.
Lista de smbolos de la gramtica (terminales no terminales).
Declaraciones de precedencia.
Especificacin de la gramtica.

Para el caso de estudio de la materia quedara definido de la siguiente


manera:
package sintactico;
import java_cup.runtime.*;
import java.io.*;
import java.util.*;

action code{:
public void ImprimeValor(String str){
System.out.println("el valor del token"+str) ;
}
:};
parser code{:
public void syntax_error(Symbol st){

token t=(token)st.value;
report_error("Error Sintactico:"+ t.getValue(),null);
}
public static void cargar(String archivo) throws Exception{
new parser(new scanner(new FileInputStream(archivo))).parse();
}

:};
/* Especificamos los terminales del lenguaje */
terminal Integer INT;
terminal String TYPE;
terminal SEMI, COMMA, BINARYOP, UNARYOP, LP, RP, LB, RB, LC, RC, STRUCT,
RETURN, IF, ELSE, BREAK, CONT, FOR, ID;
/*PARA EVITAR EL ERROR*/
terminal ASSIGN, DOT;
/* Especificamos los no terminales del lenguaje */
non terminal PROGRAM, EXTDEFS, EXTDEF, SEXTVARS, EXTVARS, STSPEC,
FUNC, PARAS, STMTBLOCK, STMTS, STMT, DEFS, SDEFS, SDECS, DECS, VAR, INIT,
EXP, EXPS, ARGS, ARRS;
//Precedencias
precedence left ELSE;
precedence left BINARYOP;

/*
precedence left "||";
precedence left "&&";
precedence left "|";
precedence left "^";
precedence left "&";
precedence left "==", "!=";

precedence left ">", ">=", "<", "<=";


precedence left "<<", ">>";
precedence left "+", "-";
precedence left "*", "/", "%";
precedence left "-", "!", "++", "--", "~";
precedence left "()", "[]", ".";
precedence right "=", "+=", "-=", "*=", "/=", "&=", "^=", "|=", "<<=", ">>=";
*/
/* REGLAS DE PRODUCCION */
PROGRAM ::= EXTDEFS;
EXTDEFS ::= EXTDEF EXTDEFS| ;

EXTDEF ::= TYPE EXTVARS SEMI|STSPEC SEXTVARS SEMI|TYPE FUNC


STMTBLOCK;
SEXTVARS ::= ID|ID COMMA SEXTVARS| ;
EXTVARS ::= VAR|VAR ASSIGN INIT|VAR COMMA EXTVARS|VAR ASSIGN INIT
COMMA EXTVARS;
STSPEC ::= STRUCT ID LC SDEFS RC|STRUCT LC SDEFS RC|STRUCT ID;
FUNC ::= ID LP PARAS RP;
PARAS ::= TYPE ID COMMA PARAS|TYPE ID| ;

STMTBLOCK ::= LC DEFS STMTS RC;


STMTS ::= STMT STMTS| ;
STMT ::= EXP SEMI|STMTBLOCK|RETURN EXP SEMI|IF LP EXP RP STMT|IF LP
EXP RP STMT ELSE STMT|FOR LP EXP SEMI EXP SEMI EXP RP STMT|CONT SEMI|
BREAK SEMI;

DEFS ::= TYPE DECS SEMI DEFS|STSPEC SDECS SEMI DEFS| ;


SDEFS ::= TYPE SDECS SEMI SDEFS| ;
SDECS ::= ID COMMA SDECS|ID;
DECS ::= VAR|VAR COMMA DECS|VAR ASSIGN INIT COMMA DECS|VAR ASSIGN
INIT;
VAR ::= ID|VAR LB INIT RB;
INIT ::= EXP|LC ARGS RC;
EXP ::= EXPS| ;
EXPS ::= EXPS BINARYOP EXPS|UNARYOP EXPS|LP EXPS RP|ID LP ARGS RP|ID
ARRS|ID DOT ID|INT;
ARRS ::= LB EXP RB ARRS| ;
ARGS ::= EXP COMMA ARGS|EXP;

5. Ahora necesitaremos un fichero que cree un objeto parser y comience el


anlisis. Para nuestro caso se crear un parser cada vez que empezemos un
archivo nuevo o en su defecto evaluemos un archivo de prueba ya existente.
Todo esto contenido en nuestra clase principal denominada sintctico.java
private

void

jButton2MouseClicked(java.awt.event.MouseEvent

evt)

{//GEN-

FIRST:event_jButton2MouseClicked
// TODO add your handling code here:
// TODO add your handling code here:

Salida.setText(" ");
if (dire == null) {
Salida.setText("Archivo invalido");
} else {
System.out.println("dir: "+dire);
parser p = new parser();
try {
p.cargar(dire);
} catch (Exception ex) {
Logger.getLogger(Sintactico.class.getName()).log(Level.SEVERE, null, ex);
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {

}
try {
BufferedReader bf = new BufferedReader(new FileReader("c:/Salida.out"));
try {
String str = "";
int x = 0;
bf.mark(0);
bf.reset();
String aux = " ";
while (aux != null) {
aux = bf.readLine();
if (aux == null) {
break;
}
str = str + aux + "\n";
x++;
}
Salida.setText(str);
} catch (IOException ex) {
}
} catch (FileNotFoundException ex) {
}
}
}//GEN-LAST:event_jButton2MouseClicked

private void jMenuItem1MouseClicked(java.awt.event.MouseEvent evt) {//GENFIRST:event_jMenuItem1MouseClicked


// TODO add your handling code here:
System.out.println("OK");
}//GEN-LAST:event_jMenuItem1MouseClicked

6. Por ultimo daremos paso a la construccin de nuestra interfaz para sus


posteriores pruebas de nuestro analizador sintctico.
4. Archivos de entrada al metacompilador, analizador sintctico generado y
compilador (archivo comprimido). Si utiliz algn script shell para realizar el
proceso debe incorporarlo.
Los archivos de entrada del metacompilador cuyo nombre es prueba 1 y prueba 2,
analizador sintctico generado y compilador estn en el directorio sources cuyas siglas
corresponden a src de nuestro proyecto.

Referencias Bibliogrficas

Informacin en Internet:
Metacompiladores:

Libro (Compiladores: principios, tcnicas y herramientas)


https://books.google.co.ve/books?
id=yG6qJBAnE9UC&pg=PA83&lpg=PA83&dq=Informe+para+un+an
%C3%A1lisis+sint%C3%A1ctico+lenguaje+y+compiladores&source=bl&ots=rsQNXa3nT&sig=ovlcxGywFOdhMqSt-oNVmE2VGiQ&hl=es419&sa=X&ved=0ahUKEwi8kY3MqoLOAhXByyYKHdycCFAQ6AEIJDAB#v=
onepage&q=Informe%20para%20un%20an%C3%A1lisis%20sint%C3%A1ctico
%20lenguaje%20y%20compiladores&f=false

http://www.ecured.cu/Analizador_sint%C3%A1ctico_descendente
http://documents.mx/documents/analisis-sintactico-ascendente-y-descendente-

558dd7f932893.html
https://ocw.uma.es/ingenierias/traductores-compiladores-e-interpretes/material-de-

clase-1/Capitulo_3.pdf
http://compiladoresasignatura.blogspot.com/2011/05/analisis-sintactico.html
http://www.lcc.uma.es/~galvez/ftp/tci/tictema3.pdf
http://users.dsic.upv.es/~jsilva/uned/compiladores/Apuntes04.pdf
http://informatica.uv.es/docencia/iiguia/asignatu/2000/PL/2007/tema5.pdf
http://www.jflex.de/docu.html
http://www.slkpg.com/documentation.html

Você também pode gostar