ami pro - tesisbce.no-ip.org/tesisdomingobecker.pdf · generador de analizadores lexicográficos,...

387
Capítulo 1: Presentación del Trabajo 1.1 Introducción La aparición de los traductores en la computación marcaron un hito haciendo que la programación se simplificara y que la computación se pudiera aplicar a más áreas de la ciencia y la tecnología, ya que la obtención de programas se haría más fácil a medida que aparecían nuevos y mejores lenguajes de programación. Se puede definir a un traductor como un programa que convierte o traduce un texto de entrada escrito en un lenguaje A a otro texto de salida escrito en un lenguaje B. Gráficamente: Fig. 1 Función de un traductor. Al proceso de traducción se lo divide, por conveniencia , en varias fases, entre las que se destacan: el análisis lexicográfico, el análisis sintáctico, el análisis semántico y la generación de código. La escritura del código fuente para las fases de análisis sintáctico, lexicográfico y semántico son en general demasiado complicadas, y la gran cantidad de errores que se cometen desalientan al programador a usar la teoría de los lenguajes formales en sus aplicaciones finales. Por ejemplo, no es común ver un programa que valide la entrada de datos por medio del uso de un lenguaje artificial creado a tal efecto (la carga de un sistema de ecuaciones e inecuaciones puede ser realizada más fácilmente usando un lenguaje artificial para la especificación de las mismas). Este trabajo presenta un generador de analizadores sintácticos y un generador de analizadores lexicográficos, que intentarán ser una buena solución al problema expuesto previamente, para que el programador sólo tenga que concentrar sus esfuerzos en su objetivo sin la necesidad de investigar en profundidad la teoría subyacente en la construcción de los analizadores. La técnica de análisis lexicográfico que utilizarán los analizadores lexicográficos que se obtengan con el generador presentado en este trabajo es Presentación del Trabajo 1

Upload: others

Post on 03-Apr-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 1: Presentación del Trabajo

1.1 Introducción

La aparición de los traductores en la computación marcaron un hitohaciendo que la programación se simplificara y que la computación se pudieraaplicar a más áreas de la ciencia y la tecnología, ya que la obtención deprogramas se haría más fácil a medida que aparecían nuevos y mejoreslenguajes de programación.

Se puede definir a un traductor como un programa que convierte otraduce un texto de entrada escrito en un lenguaje A a otro texto de salidaescrito en un lenguaje B. Gráficamente:

Fig. 1 Función de un traductor.

Al proceso de traducción se lo divide, por conveniencia , en varias fases,entre las que se destacan: el análisis lexicográfico, el análisis sintáctico, elanálisis semántico y la generación de código. La escritura del código fuentepara las fases de análisis sintáctico, lexicográfico y semántico son en generaldemasiado complicadas, y la gran cantidad de errores que se cometendesalientan al programador a usar la teoría de los lenguajes formales en susaplicaciones finales. Por ejemplo, no es común ver un programa que valide laentrada de datos por medio del uso de un lenguaje artificial creado a tal efecto(la carga de un sistema de ecuaciones e inecuaciones puede ser realizada másfácilmente usando un lenguaje artificial para la especificación de las mismas).

Este trabajo presenta un generador de analizadores sintácticos y ungenerador de analizadores lexicográficos, que intentarán ser una buenasolución al problema expuesto previamente, para que el programador sólotenga que concentrar sus esfuerzos en su objetivo sin la necesidad deinvestigar en profundidad la teoría subyacente en la construcción de losanalizadores.

La técnica de análisis lexicográfico que utilizarán los analizadoreslexicográficos que se obtengan con el generador presentado en este trabajo es

���7H[WR�HQ/HQJXDMH�$

��7H[WR�HQ/HQJXDMH�%7UDGXFWRU

Presentación del Trabajo

1

Page 2: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

por medio de autómatas finitos determinísticos que eventualmente seconstruyan para los componentes léxicos a buscar dentro del texto de entrada.Los componentes léxicos podrán ser especificados por medio de expresionesregulares.

Los analizadores sintácticos que se obtengan con el generadorpresentado en este trabajo usarán la técnica LR(1) simple.

La salida de los generadores es un módulo fuente en C++ con elrespectivo analizador (sintáctico o lexicográfico). La implementación realizadaincluye la posibilidad de la generación y uso del analizador en tiempo deejecución, lo que permite cambiar dinámicamente de analizador, durante laejecución del programa.

La tendencia actual en la Ingeniería de Software es el uso degeneradores de programas para desarrollar las partes del sistema que norequieran de la reiterada intervención de la inteligencia humana. Por ejemplo,hoy en día se usan generadores de programas para el desarrollo de la interfaseen pantalla para programas que trabajarán en entornos gráficos tipo Windows,Presentation Manager de OS/2, Macintosh y X Window. Se sabe que elaprendizaje de la programación de una interfase gráfica es un pococomplicado, pero es repetitivo y rutinario, por lo tanto se implantarongeneradores que hagan ese trabajo. Lo mismo ocurre con la Teoría de losLenguajes Formales: la teoría que se maneja es compleja, pero la tarea de laconstrucción de un analizador sintáctico es repetitivo y rutinario, y puede serautomatizado.

Los generadores presentados en este trabajo intentarán ayudar alprogramador en el desarrollo de traductores (de un lenguaje a otro, seanintérpretes o compiladores), de rutinas para la recuperación inteligente de lainformación, y en la utilización de la Teoría de los Lenguajes Formales enotras áreas, como por ejemplo, el reconocimiento de rasgos distintivos encircuitos electrónicos impresos por medio de la concordancia de patrones(Jarvis [1976]).

En nuestro ambiente informático existen herramientas similares a lasque se presentan en este trabajo: LEX es similar al generador de analizadoreslexicográficos y YACC es similar al generador de analizadores sintácticos.Pero hay ciertas diferencias fundamentales con ellos, algunas de las cuales sonimportantes mejoras introducidas en este trabajo. Las mismas se detallan acontinuación.

Presentación del Trabajo

2

Page 3: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

1. Uso del C++ como lenguaje objeto. Se hace uso del ParadigmaOrientado a Objeto. En particular, se hace uso de templates (familias declases y familias de funciones, sólo presente en C++, Stroustrup [1994])para la implementación de los analizadores. Se organiza adecuadamenteel código generado y se encapsula la complejidad del funcionamiento delos analizadores.

2. La modificación manual de los analizadores generados es mucho másfácil puesto que se separa el código que es igual para todos losanalizadores del código que cambia entre ellos, y se los da en módulosseparados.

3. Posibilidad de mostrar las tablas generadas en formato texto para suposterior lectura por parte del programador.

4. El generador de autómatas finitos determinísticos (AFDs) a partir deexpresiones regulares usa un lenguaje para la especificación de laexpresión regular fuente similar al usado por LEX, pero con sintaxismás simple. De esta manera es más fácil y directa la lectura de unaexpresión regular.

5. Es posible reusar los generadores en programas del usuario. De estamanera, es posible cambiar el analizador en tiempo de ejecución. Porejemplo, para la recuperación de la información en bases de datos sepueden usar expresiones regulares; el Paradox y el dBase V usan unlenguaje simplificado de expresiones regulares, en el que no es posibleel uso de paréntesis ni el operador '|'.

6. Se documenta la estructura de las tablas, y las mismas se implementanen estructuras simples, a los efectos de poder retocarlas en caso de sernecesario. En LEX y en YACC esto no es posible.

7. Posibilidad de reusar trabajos hechos y compilados previamente, sin lanecesidad de retocar nada, debido a la independencia de los módulosgenerados. Los módulos generados por YACC y por LEX son muyinterdependientes, y es imposible encadenarlos con otros trabajoshechos anteriormente debido a la colisión de nombres.

8. Debido a que se separan las acciones semánticas en un módulo aparte dedonde se realiza el análisis sintáctico, es más fácil la depuración de lasmismas. En YACC es demasiado complicado depurar las accionessemánticas. Los analizadores sintácticos ni los lexicográficos no se

Presentación del Trabajo

3

Page 4: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

depuran, el código que los implementa ya fue depurado por el autor deeste trabajo.

9. La generación de códigos fuentes en otro lenguaje distinto al C++ esposible escribiendo solamente el código que imprime las tablas yrescribiendo el código que implementa los analizadores (la biblioteca desoporte).

10.A los dispositivos de E/S los elige el usuario de los generadores. No sehace la imposición de usar la entrada y la salida estándar del sistemaoperativo, como ocurre en YACC y en LEX.

En el punto 5 se habla de la posibilidad de reusar los generadores enprogramas del usuario. De hecho, los generadores han sido concebidos comobibliotecas de código C++. Para poder usarlas hace falta escribir un programaque haga uso de esas bibliotecas. A ese programa que se escribe se lodenomina usuario de esas bibliotecas. Luego, los programas generadores aquípresentados son en realidad programas que usan las bibliotecas de soporte. Porlo tanto, la reusabilidad de los generadores es más directa y simple, y son losdos primeros ejemplos de uso que se dan en el trabajo.

Como ejemplos de aplicación, los cuales podrán ser de mucha utilidadpara los estudiantes de la cátedra de Compiladores, se incluyen los siguientes:

El programa generador de analizadores sintácticos y analizadoreslexicográficos a partir de una gramática, que da como salida un texto enC++. Secciones 7.3, 7.4, 20.1 y 20.2.

El programa generador de autómatas finitos determinísticos a partir deexpresiones regulares, que da como salida un texto en C++ con el AFD.Secciones 6.7, 22.1 y 22.2.

Un programa para validar esquemas deductivos por medio de la TeoríaSemántica del Cálculo Proposicional. Sección 11.9, 11.10, 12.12 y 12.13. Semuestra el uso del generador de analizadores sintácticos y del generador deanalizadores lexicográficos.

Una calculadora simple. Capítulo 14. Se muestra generador de analizadoressintácticos y del generador de analizadores lexicográficos.

Consultas a archivos bases de datos BCE. Capítulo 15. Se muestra el uso delgenerador de AFDs usado por el generador de analizadores lexicográficos.El generador de AFDs es encadenado en el programa final.

Presentación del Trabajo

4

Page 5: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Un traductor sencillo para un lenguaje simple, y un intérprete para el códigoobjeto generado por el traductor. Capítulo 16. Se muestra el uso delgenerador de analizadores sintácticos y del generador de analizadoreslexicográficos. Este ejemplo puede servir de mucha utilidad a estudiantes dela cátedra de Compiladores.

La interfase en pantalla de los ejemplos de aplicación fueron todosdesarrollados para Windows 3.1 o posterior. La parte más importante de ellos,la que hace uso de los fuentes generados por los generadores de este trabajo, esportable a cualquier sistema operativo. Los códigos fuentes son tambiéncompilables con Borland C++ 2.0 para OS/2, sin ninguna modificación;funcionarán usando el Presentation Manager. Los fuentes y ejecutables de losejemplos se incluye en el disco que acompaña a este trabajo, a efectos de quepuedan ser mejorados por algún interesado.

Para los programas generadores, en el disco que acompaña este trabajose incluye una versión que funciona bajo Windows y otra bajo DOS. El códigofuente de las versiones Windows de los generadores son compilables sinninguna modificación con Borland C++ 2.0 para OS/2, se podrá obtener unanueva versión que funcionará bajo Presentation Manager de OS/2 Warp. Elcódigo fuente de las versiones modo caracter de los generadores se podráncompilar sin ninguna modificación con Borland C++ 2.0 para OS/2, y obtenerasí una nueva versión que funcionará en OS/2 modo caracter. La versión modocaracter del ejecutable de los generadores funcionarán sin problemas bajoWindows 95 en modo caracter, así como también las versiones gráficas.

Debido a que en la bibliografía de computación no existe un documentoque explique cómo nacen las gramáticas generativas, en el capítulo 17 se dauna introducción a las mismas, tratando de explicar cómo fueron concebidaspor Chomsky.

El presente trabajo intenta servir de bibliografía para los interesados enescribir analizadores sintácticos y/o lexicográficos, así como también para usarla Teoría de los Lenguajes Formales en otras áreas no mencionadas aquí. No esintención de este trabajo el de servir como bibliografía para la escritura decompiladores ni de intérpretes, ya que se deben tratar otros temas como porejemplo la implementación de los espacios de nombres, lo que está fuera delámbito del tema tratado en este trabajo.

Presentación del Trabajo

5

Page 6: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

1.2 Organización del trabajo

Este trabajo está organizado en 4 partes a saber:

Parte 1 - Marco teórico: en esta parte se explicarán los algoritmos degeneración usados por los generadores.

Parte 2 - Implementación de los generadores: en esta parte se documentarála implementación realizada para los generadores.

Parte 3 - Documentación para el usuario: en esta parte se incluye ladocumentación que necesitará el usuario de los generadores. Cada capítulodebe ser tomado como un libro aparte.

Parte 4 - Ejemplos de aplicación: en esta parte se presentan y documentanlos ejemplos de uso de los generadores.

Parte 5 - Anexos, Códigos Fuentes y Conclusión: en esta parte se encontraráinformación adicional relativa a este trabajo, el código fuente de laimplementación documentada en la parte 2 y la conclusión.

1.3 Consideraciones acerca de la Implementación

El software de la implementación de los algoritmos se realizó en C++debido a 3 razones fundamentales:

1. El alto nivel de reusabilidad del lenguaje.

2. Es un lenguaje que ofrece todo lo que un Ingeniero en Software puedepedirle a un lenguaje de programación. Hay disponibles muchasherramientas para trabajar con C++.

3. Está disponible a muy buen precio para muchos sistemas operativos.

Este trabajo no pretende ser un curso de programación. Por esta razón,en la documentación de las implementaciones realizadas se trata en detalle losfundamentos teóricos y en resumen las implementaciones en C++.

Presentación del Trabajo

6

Page 7: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Parte 1. Marco Teórico

7

Page 8: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 2: Introducción a la Teoría de los Lenguajes Formales

2.1 Introducción

Previo a la lectura de los capítulos que se encuentran en la Parte II seaconseja leer el Capítulo 17 en la Parte V en donde se da una correctaintroducción a las gramáticas generativas y la lingüística matemática. Puedeconsultar además la bibliografía que trata la teoría de compiladores.

En los puntos siguientes se hace una breve introducción a los conceptosfundamentales usados por los 2 generadores y en los capítulos siguientes seexplican detalladamente cada uno de los algoritmos de análisis y degeneración. Puede ser que el lector que se esté iniciando en la teoría de loslenguajes formales necesite ver algunos ejemplos; en este capítulo se minimizala inclusión de ejemplos puesto que los conceptos que introduce son muybásicos, por lo que se aconseja leer la bibliografía sobre compiladores eintérpretes.

2.2 Lenguajes y Gramáticas

2.2.1 Alfabeto

Se denomina Alfabeto de un lenguaje a los caracteres que puedenformar parte de las oraciones del mismo. Para el Castellano tenemos comoAlfabeto a todas las letras y los signos de puntuación. Se especifica como unconjunto de elementos.

2.2.2 Cadena o Tira de Caracteres

La noción más básica de la Teoría de los Lenguajes es la tira o cadena

de caracteres, que está formada por la concatenación de caracteres.

La cadena mínima o nula se denomina λ (lambda).

Introducción a la Teoría de los Lenguajes Formales

8

Page 9: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2.2.3 Lenguaje

Un lenguaje es, en general, un conjunto de cadenas de caracteres. Acada cadena de caracteres la denominaremos oraciones. Está formado por losdos elementos siguientes

1. Un diccionario, que indica los significados de las palabras.

2. Un conjunto de reglas para describir las oraciones válidas del lenguaje.Este conjunto de reglas forma la gramática del lenguaje.

Se denomina semántica al estudio del significado de las oraciones yfrases de un lenguaje, y su interpretación.

Se denomina sintaxis al estudio de la estructura del lenguaje. La sintaxisde las oraciones del lenguaje (la estructura del lenguaje) se la explicita a travésde reglas de producciones.

Se denomina análisis sintáctico a la operación que se ejecuta paraverificar la gramaticalidad de una oración. Es un proceso de validación deltexto fuente de entrada. En cualquier situación donde se requiera validar laentrada de datos se puede usar el análisis sintáctico.

Se denomina análisis semántico al proceso que se ejecuta para verificarla coherencia en el significado de una oración.

Se denomina análisis lexicográfico a un caso especial de análisissintáctico en donde se usan técnicas especiales y más rápidas para tratar con laentrada de datos (texto fuente). Lea también el punto 2.3.5.

2.2.4 Noción de Gramática

La noción de gramática que aquí se presenta es debida a Chomsky en elaño 59.

Una gramática generativa transformacional está caracterizada por unacuádrupla ordenada como la siguiente:

G = ( N , T , R , O )

donde:

Introducción a la Teoría de los Lenguajes Formales

9

Page 10: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

N: es el conjunto de símbolos no terminales usados para construir las reglas dela gramática y no figuran en las oraciones del lenguaje. A veces se losdenomina como no terminales o metanociones.

T: es el conjunto de símbolos terminales . Cualquier oración del lenguaje debeser una cadena de símbolos de T, según la estructura que especifiquen lasreglas. A veces pueden ser llamados directamente terminales o nociones.

R: es el conjunto de las reglas de rescritura de la gramática. Tienen la formacadena1 --> Cadena2.

O: es el símbolo más importante del conjunto N, se denomina símbolo inicial,axioma, símbolo distinguido o cabeza de lenguaje. Se usa para comenzar lasderivaciones en el análisis sintáctico de las oraciones.

Al lenguaje L generado por la gramática G está formado por todas lasoraciones tales que se puede encontrar a partir de O, por medio de aplicacionessucesivas de las reglas de la gramática. Se denota por

L(G) = { α / O -*-> α }

2.2.5 El conjunto de Reglas y la Clasificación de Chomsky

La clasificación publicada por Chomsky en el año 1959 introduce 4tipos de gramáticas a base de cambiar solamente el tipo de las reglas dederivación que se encuentran en el conjunto R.

A las gramáticas del Tipo 0 y del Tipo 1 se las suele denominargramáticas generativas trasnformacionales. Lo de transformacional hacereferencia al hecho de que transforman una secuencia de caracteres en otrasecuencia de caracteres en un solo paso.

Gramáticas de Tipo 0 o gramática con estructura de frase

Las reglas en este tipo de gramática tienen la forma:

α ---> β donde α pertenece a (N U T)+ y β a (N U T)*

Por la definición dada, la regla que deriva en λ pertenece al lenguaje.

Introducción a la Teoría de los Lenguajes Formales

10

Page 11: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Este tipo engloba a todos los otros 3 tipos de gramática. Actualmente nose publicó un trabajo en el que se haya presentado un analizador sintáctico quetrabaje con una gramática de éste tipo.

Se dice que la Máquina de Turing puede tratar este tipo de gramática.Las máquinas de Turing son bidireccionales (pueden ir hacia adelante o haciaatrás en la examinación de los caracteres de entrada).

Gramáticas de Tipo 1 o gramática sensible al contexto

Las reglas tienen la forma:

α A β ---> α γ β

donde A está en Ny, α y β en (N U T) * y γ en (N U T)+

Se llama sensible al contexto por que cambia A por gamma sólo en elcontexto formado por alfa ... beta.

Aquí se puede observar que el problema de número que tenemos altrabajar con lenguajes naturales (los que hablamos los humanos) puede sertratado con gramáticas de este tipo (por ejemplo, la concordancia del númerodel verbo con el del sujeto).

Se puede construir un autómata bidireccional para tratar esta gramática.

Gramáticas de Tipo 2 o gramáticas de contexto libre

La forma de las reglas es:

A --> α donde A está en N y α en (N U T)*

Se llama de contexto libre porque se puede cambiar A por α

independientemente del contexto en el que aparezca A.

Este tipo de gramáticas son las que se usan para los lenguajes decomputación. Cuando se utilice el término gramática en capítulos siguientes,se quiere decir gramáticas de Tipo 2 o 3.

Para tratar estas gramáticas es necesario un autómata de pila.

Introducción a la Teoría de los Lenguajes Formales

11

Page 12: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Gramáticas de Tipo 3 o gramáticas regulares

Las reglas pueden tener una de las dos formas siguientes:

A ---> a B o bien

A ---> a

donde A y B son de N y a de T.

El no terminal B puede aparecer a la izquierda de a en la regla.

Tres años antes de la presentación de esta clasificación, Kleene estudiópor primera vez a las expresiones regulares. Resultó ser que las expresionesregulares es otra forma muy compacta de escribir una gramática del Tipo 4.

El tratamiento de este tipo de gramáticas es a través de autómatasfinitos.

2.3 Gramáticas de Contexto Libre

En esta sección estudiaremos conceptos fundamentales acerca de estetipo de gramáticas, para pasar al capítulo siguiente en donde se utilizarán lasoperaciones fundamentales con ellas, que serán usados más adelantes.

2.3.1 Recursividad

La recursividad es un mecanismo amplificador que permite definirformas complicadas de un lenguaje con muy pocas reglas.

Veamos un ejemplo sencillo: sea el lenguaje cuyas oraciones sonnúmeros enteros según la siguiente descripción dada por extensión:

L = { números sin signos formados a partir de la combinación de los dígitoscomprendidos entre el 0 y el 9, por ejemplo el 457 }

Para construir las reglas de la gramática que den cuenta de la estructurade este lenguaje se podrían dar las siguientes reglas:

N ---> DN ---> D D

Introducción a la Teoría de los Lenguajes Formales

12

Page 13: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

N ---> D D DD ---> 0 | 1 | 2 | ... | 9

Se observa que la gramática construida no explica la estructura de losnúmeros de 4 o más dígitos. Aún más, si consideramos la posibilidad de quehay números con gran cantidad de dígitos tendríamos una gramática con unagran cantidad de reglas, si es que utilizamos esta forma de escribirla. Entonces,como solución aparece la recursividad, y a la gramática la rescribiríamos de lasiguiente manera:

N ---> N DN ---> DD ---> 0 | 1 | 2 | ... | 9

2.3.2 Arbol de Análisis Sintáctico

Es una representación gráfica del resultado obtenido al aplicar las reglasde la gramática partiendo de O (el símbolo inicial) hasta llegar a la oración quese esté analizando sintácticamente.

Al proceso de análisis sintáctico se lo menciona muchas veces como elproceso de construir el árbol de análisis sintáctico de la oración.

2.3.3 Arbol sintáctico

Es una versión simplificada de un árbol de análisis sintáctico.

Los nodos de un árbol sintáctico son símbolos terminales y representanoperaciones entre ellos y el orden en que deben ser ejecutadas.

Un árbol sintáctico puede construirse a partir del análisis sintáctico deltexto de entrada.

La definición de árbol sintáctico dada aquí es la que sirve a los efectosde este trabajo y puede no coincidir con alguna definición que se encuentre enla bibliografía sobre compiladores. En términos de esta definición, cualquierárbol que se diga ser árbol sintáctico y que tenga nodos con no terminales seráconsiderado simplemente árbol.

En el capítulo 3 se utilizan árboles sintácticos para expresionesregulares.

Introducción a la Teoría de los Lenguajes Formales

13

Page 14: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2.3.4 Ambigüedad de una Gramática

Una gramática es ambigua si el lenguaje definido por la misma tienealguna oración que tenga más de un árbol de análisis sintáctico.

Se llama ambigua a la gramática y no al lenguaje que define, puesto quefrecuentemente es posible modificar la gramática para que deje de ser ambiguasin tocar para nada el lenguaje implicado. Pero hay lenguajes para los que noexisten más que gramáticas ambiguas: a estos lenguajes se les llama"ambiguos intrínsecos".

La ambigüedad de una gramática es una propiedad indecidible, lo quesignifica que no existe ningún algoritmo que acepte una gramática y determinecon certeza y en un tiempo finito si la gramática es ambigua o no.

Una gramática que es tratable con la técnica LR(k) o con la técnicaLL(k) no es ambigua, por lo que resulta un buen método de determinar laambigüedad.

2.3.5 Gramáticas y el Análisis Sintáctico

La construcción de un analizador sintáctico consiste en el desarrollo desubrutinas que revisen el código fuente de entrada y verificar que el mismocumple con las reglas gramaticales. Si cumple diremos que es gramaticalmentecorrecta, lo cual no significa que sea entendible.

Existen varias técnicas de análisis sintácticos entre las que se destacan 2grupos principales: la técnica LR y la LL.

La técnica LR(k) (Left to right scanning - Rightmost parsing, examende izquierda a derecha - análisis a derechas), es un método de análisisascendente, esto es, se parte de la oración para llegar al símbolo inicial O. Hasido presentado al público por primera vez por Knuth [1965]. Reconocen lagran mayoría de los lenguajes de programación que se puedan generar congramáticas de contexto libre. En general su uso no tiene restricciones, pero laconstrucción del analizador sintáctico es demasiado complicada por lo que sehace necesario disponer de generadores de analizadores sintácticos parasimplificar la tarea.

La técnica LL(k) (Left to right scanning - Leftmost parsing, examen deizquierda a derecha - análisis a izquierdas) es un método descendente, esto es,parte desde el símbolo inicial O para llegar a la oración. Las técnicas deanálisis predictivos fueron estudiadas a fondo por Knuth [1971]. El método es

Introducción a la Teoría de los Lenguajes Formales

14

Page 15: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

mucho más restrictivo que el LR, ya que el número de gramáticas que se puedetratar es mucho menor. Gráficamente:

Fig. 2 Comparación del número de gramáticas tratables con latécnica LR y el número de gramáticas tratables con latécnica LL.

El generador de analizadores presentado en este trabajo generaanalizadores que trabajan con la técnica LR(1) Simple, a la que se le suelellamar SLR(1) o simplemente SLR.

2.3.6 El Análisis Lexicográfico

La función principal del análisis lexicográfico es la de convertirsecuencias de caracteres de entradas en símbolos léxicos.

Hay varias razones para dividir la fase de análisis de la traducción enanálisis lexicográfico y análisis sintáctico:

1. Un diseño sencillo es la consideración más importante. El uso de unanalizador lexicográfico simplifica el analizador sintáctico. Imagine sinoun analizador sintáctico que incluya las convenciones de comentarios yespacios en blanco.

2. Se mejora la eficiencia del compilador. Un analizador léxicoindependiente permite construir un procesador especializado ypotencialmente más eficiente para esta función. Gran parte de tiempo delanálisis se consume en leer el programa fuente y separarlo en símbolosléxicos.

*UDPiWLFDV�/5

*UDPiWLFDV�//

5HVXPHQ�JUiILFR�H[WUDtGR�GH�6DQFKLV�/ORUFD���*DOiQ�3DVFXDO�>����@

Introducción a la Teoría de los Lenguajes Formales

15

Page 16: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

3. Se mejora la transportabilidad del compilador. Las peculiaridades delalfabeto de entrada y otras anomalías propias de los dispositivos deentrada pueden limitarse al analizador lexicográfico.

La forma más simple de especificar símbolos léxicos y la que más se usaactualmente es mediante el uso de expresiones regulares. La construcción deun analizador lexicográfico a partir de estas expresiones regulares es una tareacomplicada, para lo cual es necesario disponer de un generador deanalizadores lexicográficos.

Muchas veces se escuchará decir que la construcción manual delanalizador lexicográfico resulta en uno que funciona mucho más rápido que elque se obtendría a través del uso de un generador. El generador que sepresenta en este trabajo es un intento de solución a este problema.

La inclusión de un analizador lexicográfico en el proyecto deconstrucción de un traductor implica la construcción de otro analizadorsintáctico, sólo que para una gramática del Tipo 3 de la clasificación deChomsky la cual es tratada con técnicas distintas que las del Tipo 2. Lasoraciones encontradas por ese analizador son pasadas al analizador sintácticodel lenguaje fuente, y como consecuencia directa se tiene la simplificación dela gramática del lenguaje fuente. Muchas veces este concepto es confundido.

2.3.7 Esquemas de Traducción

Se define un esquema de traducción como un sistema formal del tipo:

EDT = { N, Te, Ts, R, O }

donde

N: es el conjunto finito de símbolos no terminales.

Te: es el conjunto finito de símbolos terminales del lenguaje de entrada ofuente.

Ts: es el conjunto finito de símbolos terminales del lenguaje de salida u objeto.

R: es el conjunto finito de reglas de traducción que poseen la estructura:

A ---> α , β donde

A pertenece a N

Introducción a la Teoría de los Lenguajes Formales

16

Page 17: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

α pertenece a ( N U Te)*β pertenece a ( N U Ts)*

En cualquier caso se cumple que

N intersección (Te U Ts) = { }

O: es el símbolo inicial.

La estructura del lenguaje de salida se puede explicar con la gramáticasiguiente:

Gs = { N, Ts, P, O }

donde

N: es el conjunto de símbolos no terminales del lenguaje fuente. O es unelemento de este conjunto.

Ts: es el mismo conjunto de símbolos terminales del esquema de traducción.

P: es el conjunto de reglas de la gramática, cuyos elementos son las reglas que:

P = { A ---> β / (A ---> α , β) era una regla de traducción del esquema }

2.3.8 Acciones Semánticas / Rutinas Semánticas

En la bibliografía utilizada se encontrarán definiciones distintas de loque son las acciones semánticas y las rutinas semánticas.

En Sanchis Llorca-Galán Pascual [1986], los términos acciones

semánticas se aplican a los autómatas finitos, y los términos rutinas

semánticas a los analizadores sintácticos (que en definitiva son tambiénautómatas).

En Aho-Sethi-Ullman [1990], los términos acciones semánticas seaplican a los analizadores sintácticos. Los términos rutinas semánticas no sonutilizados en ese libro.

A los efectos de unificar conceptos, en este trabajo se tomarán comosinónimos a los términos acciones semánticas y rutinas semánticas,

Introducción a la Teoría de los Lenguajes Formales

17

Page 18: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

fundamentado en que existe una analogía entre un analizador sintáctico y unautómata finito.

La definición utilizada será la siguiente: se denomina accionessemánticas a los fragmentos de oraciones de un lenguaje intercalados en laparte derecha de una regla de una gramática libre de contexto.

En la definición dada en el punto anterior se habló de esquemas detraducción, introduciendo un nuevo tipo de reglas en las que en la partederecha se encuentran cadenas de símbolos terminales del lenguaje objeto (ode salida). Se transcribe la forma general de las reglas de traducción:

A ---> α , β

Aquí, β es la cadena de símbolos terminales del lenguaje objeto. Luego, sedenomina acciones semánticas a las acciones que se ejecutan para produciresa cadena de símbolos terminales del lenguaje objeto.

En general, las acciones semánticas se escriben con fragmentos deoraciones de un lenguaje distinto al fuente y al objeto. En este trabajo se utilizael lenguaje C++ para escribir acciones semánticas.

Introducción a la Teoría de los Lenguajes Formales

18

Page 19: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 3: Algoritmos Usados por el Generador de AutómatasFinitos Determinísticos

3.1 Introducción

En este capítulo se presentan los algoritmos usados por el generador deautómatas finitos determinísticos que sirve como base principal para laconstrucción de un analizador lexicográfico.

A diferencia del capítulo 2, en este capítulo se documenta en detallecada aspecto de los algoritmos, y se incluyen ejemplos que clarificarán sufuncionamiento.

Durante su lectura no se debe olvidar que el tratamiento de lenguajescon expresiones regulares es un caso especial de análisis sintáctico(implícitamente se está trabajando con una gramática del Tipo 3), al quecomúnmente se lo denomina análisis lexicográfico. La teoría aquí presentadase puede aplicar a muchas áreas de la ciencia, y no sólo al análisislexicográfico.

3.2 Arbol Sintáctico para una Expresión Regular

3.2.1 Descripción

Se construirá un árbol sintáctico para la expresión regular a partir delanálisis sintáctico de la misma.

Como ya se sabe, en un árbol hay 2 tipos de nodos: nodos hojas y nodosque no son hojas que aquí representarán operaciones. En un árbol sintáctico deuna expresión regular los nodos hojas representarán un caracter (o símboloterminal) que aparece en el texto fuente, el resto de los nodos representaránoperaciones con ellos.

El lenguaje para expresiones regulares con el que trabajaremos es el quese presenta en la sección 10.3. En la misma se definen 5 operaciones, lo quenos da 6 tipos de nodos posibles a saber:

1. Nodo hoja: se representa con un círculo y dentro del mismo el caracterque hay en esa posición.

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

19

Page 20: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2. Nodo concatenación: se representa con un círculo con un punto adentro.

3. Nodo disyunción: se representa con un círculo con un | adentro.

4. Nodo asterisco: se representa con un círculo y un * adentro.

5. Nodo opcional: se representa con un círculo y un ? adentro.

6. Nodo uno o más: se representa con un círculo y un + adentro.

El árbol puede ser construido trabajando con cualquier técnica deanálisis sintáctico que permita construir el árbol sintáctico respetando el ordende examen de los terminales de izquierda a derecha (puede ser LL(k) o LR(k)).

Ejemplo: sea la expresión regular la siguiente:

( '+' | '-' ) ? d +

El árbol sintáctico sería:

Fig. 3 Arbol sintáctico para ( '+' | '-' ) ? d +

A los efectos de poder implementar los algoritmos de generación setrabaja con la expresión regular aumentada "ExpReg #" donde el numeral (#)significa fin de la expresión regular. Al construir el árbol sintáctico para laexpresión regular aumentada, el nodo raíz del árbol será un nodoconcatenación el cual tendrá como subárbol izquierdo el árbol sintácticoconstruido y como subárbol derecho la hoja etiquetada con #. Para el ejemplo

.

+

|

'+' '-'

d

?

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

20

Page 21: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

dado se tendrá:

Fig. 4 Arbol sintáctico para ( '+' | '-' ) ? d + #

En el árbol sintáctico presentado en la figura 4 se muestran las hojasnumeradas de 1 a N. La numeración de las hojas se realizará por el orden deaparición de las mismas en la expresión regular.

3.2.2 Funciones aplicables a nodos de un árbol sintáctico

Definiremos 4 funciones que operan sobre nodos de un árbol sintácticoconstruido para una expresión regular dada: Anulable, PrimeraPos, UltimaPos

y SiguientePos. El sufijo Pos significa posición del árbol. Las funcionesdevuelven algún valor referente a esa posición del árbol.

La función Anulable devuelve como resultado Verdadero o Falso. Esrecursiva por definición y se la caracteriza por medio de la siguiente tabla:

.

+

|

'+' '-'

d

.

#

1 2

3

4 ?

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

21

Page 22: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 5 Función Anulable

Las funciones PrimeraPos y UltimaPos son también recursivas.Devuelven como resultado un conjunto cuyos elementos son los números delas hojas siguientes a la posición actual. Las funciones quedan caracterizadasmediante la siguiente tabla:

Tipo de nodo Anulable(Nodo)

Hoja con número i Falso

|

*

.

+

?

si sd

si sd

s

s

s

Anulable(si) y Anulable(sd)

Anulable(si) o Anulable(sd)

Verdadero

Anulable(s)

Verdadero

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

22

Page 23: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 6 Funciones PrimeraPos y UltimaPos

La función SiguientePos se calcula únicamente para los nodos hoja,pero su cálculo requiere el completo recorrido del árbol sintáctico. Se definepor las dos reglas siguientes:

1. Si n es un nodo concatenación con subárbol izquierdo si y subárbolderecho sd, e i es una posición dentro de UltimaPos(si), entonces todaslas posiciones de PrimeraPos(sd) están en SiguientePos(i).

2. Si n es un nodo asterisco e i es una posición dentro de UltimaPos(n),entonces todas las posiciones de PrimeraPos(n) están en SiguientePos(i).

Ejemplo: para el ejemplo dado (ver figura 4) tenemos:

Funciones PrimeraPos y UltimaPos:

Para el nodo disyunción:PrimeraPos( | ) = { 1, 2 }UltimaPos( | ) = { 1, 2 }

Tipo de nodo PrimeraPos(Nodo)

Hoja con número i

|

*

.

+

?

si sd

si sd

s

s

s

UltimaPos(Nodo)

{ i } { i }

Si Anulable(si) EntoncesPrimeraPos(si) U PrimeraPos(sd)

Sino PrimeraPos(si)

PrimeraPos(si) U PrimeraPos(sd)

PrimeraPos(s)

PrimeraPos(s)

PrimeraPos(s)

Si Anulable(sd) EntoncesUltimaPos(sd) U UltimaPos(si)

Sino UltimaPos(sd)

UltimaPos(sd) U UltimaPos(si)

UltimaPos(s)

UltimaPos(s)

UltimaPos(s)

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

23

Page 24: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Para el nodo opcional:PrimeraPos( ? ) = { 1, 2 }UltimaPos( ? ) = { 3 }

Para el nodo concatenación de más a la izquierda:PrimeraPos( . ) = { 1, 2, 3 }UltimaPos( . ) = { 3 }

Para el nodo concatenación raíz:PrimeraPos( . ) = { 1, 2, 3 }UltimaPos( . ) = { 4 }

Las funciones SiguientePos(i) para cada hoja son:

SiguientePos(1) = { 3 }

SiguientePos(2) = { 3 }

SiguientePos(3) = { 3, 4 }

SiguientePos(4) = { }

3.3 Construcción de un AFD a partir de una expresión regular

3.3.1 Construcción del AFD

La construcción de un autómata finito determinístico (AFD) a partir deuna expresión regular se realiza mediante el siguiente procedimiento:

1. Construir el árbol sintáctico para la expresión regular aumentadaExpReg #, donde # es un marcador de final que se añade a ExpReg yque difiere de los caracteres que pueden aparecer en ExpReg (no debeestar dentro del conjunto de terminales).

2. Calcular las funciones Anulable, PrimeraPos, UltimaPos y SiguientePos

haciendo recorridos en profundidad del árbol.

3. Construir EstadosD (la letra D por Determinístico), el conjunto deestados del AFD, por medio del procedimiento descripto en el puntosiguiente. Los estados dentro de EstadosD son conjuntos de posiciones;al principio, cada estado está "no marcado", y un estado se convierte en

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

24

Page 25: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

"marcado" justo antes de considerar sus transiciones de salida. El estadoinicial del AFD es PrimeraPos(raíz), y los estados de aceptación sontodos los que contienen la posición asociada con el marcador #.

3.3.2 Cálculo del conjunto de estados y de la tabla de transiciones

El procedimiento de cálculo del conjunto de estados y de la tabla detransiciones del autómata finito determinístico para la expresión regular es elque se muestra en la figura siguiente:

Fig. 7 Algoritmo para la construcción del conjunto de estados yla tabla de transiciones para el AFD de la expresiónregular.

3.3.3 Ejemplo de construcción del AFD a partir de la expresión regular

Para la expresión regular utilizada en los puntos precedentes tenemoslos siguientes pasos:

1. Inicialmente EstadosD = { {1, 2, 3} }.El único estado del conjunto está sin marcar.

Al principio, el único estado no marcado en EstadosD es PrimeraPos(raíz), donde raíz

es la raíz del árbol sintáctico construido para ExpReg #.

Mientras haya un estado E sin marcar en EstadosD hacer

Marcar E

Para cada símbolo de entrada a hacer

sea U el conjunto de posiciones que están enSiguientePos(p) para alguna posición p en E, tal que elsímbolo en la posición p es a.

Si U no está vacío y no está en EstadosD entonces

Añadir U como estado no marcado a EstadosD.Transición[E, a] = U.

Sino Transición[E, a] = no definida

FinPara

FinMientras

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

25

Page 26: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2. Sea E = { 1, 2, 3 } el estado actual, al que luego se le dará el número 0:U'+' = { 3 } Transición[ {1, 2, 3}, '+' ] = { 3 }U'-' = { 3 } Transición[ {1, 2, 3}, '-' ] = { 3 }Ud = { 3, 4 } Transición[ {1, 2, 3}, d ] = { 4, 3 }EstadosD = { {1, 2, 3}0, {3}, {3, 4} }

3. Sea E = { 3 } el estado actual, al que luego se le dará el número 1:U'+' = { } Transición[ {3}, '+' ] = no definido

U'-' = { } Transición[ {3}, '-' ] = no definido

Ud = { 3, 4 } Transición[ {3}, d ] = { 3, 4 }EstadosD = { {1, 2, 3}0, {3}0, {3, 4} }

4. Sea E = { 3, 4 } el estado actual, al que luego se le dará el número 2:U'+' = { } Transición[ {3, 4}, '+' ] = no definido

U'-' = { } Transición[ {3, 4}, '-' ] = no definido

Ud = { 3, 4 } Transición[ {3, 4}, d ] = { 3, 4 }EstadosD = { {1, 2, 3}0, {3}0, {3, 4}0 }

5. No hay más estados sin marcar, por lo tanto termina la iteración.

Los estados (conjunto de posiciones siguientes) fueron numerados de 0a n-1, donde n es el cardinal del conjunto EstadosD.

Hay un solo estado final y es el {3, 4} (al que se le dio el número 2),puesto que es el que contiene la posición que corresponde al #, que fuenumerada con 4. El conjunto de estados finales queda así:

Estados Finales = { {3, 4} }

La tabla de transiciones de estados para el autómata finito determinísticoque reconoce cadena de caracteres con la estructura " ( '+' | '-' ) ? d +" es lasiguiente:

Estado '+' '-' d

0 1 1 2

1 no definido no definido 2

2 no definido no definido 2

La gráfica del autómata finito determinístico para el ejemplo dado es:

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

26

Page 27: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 8 Autómata finito determinístico construido para laexpresión regular ( '+' | '-' ) ? d +

3.4 Funcionamiento de un autómata finito determinístico

El siguiente procedimiento ilustra el funcionamiento de un autómatafinito determinístico:

Fig. 9 Algoritmo para el funcionamiento de un Autómata FinitoDeterminístico.

0 1 2'+' / '-' d

d

d

EstadoActual = 0;

Buscar un caracter de entrada y guardarlo en c

Hacer

Si c no es FinDeArchivo entonces

EstadoNuevo = Transición[EstadoActual, c];

Buscar un caracter de entrada y guardarlo en c

Si EstadoNuevo es un estado del autómata entonces

EstadoActual = EstadoNuevo;

FinSi

FinSi

Mientras EstadoActual sea igual a EstadoNuevo;

Si EstadoActual es un elemento del conjunto de estados finales entonces

La cadena de entrada leída hasta este momento cumple con la expresión regular.

FinSi

Algoritmos Usados por el Generador de Autómatas Finitos Determinísticos

27

Page 28: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 4: Algoritmos usados por el Generador de AnalizadoresSintácticos

4.1 Introducción

En este capítulo se presentan los algoritmos usados por el Generador deAnalizadores Sintácticos SLR. Se tratará de clarificar bien los conceptosteóricos utilizados, lo que no hace la bibliografía que se utilizó (luego de lalectura de la bibliografía, en el mejor de los casos quedan muchos conceptosflotando y sin relación alguna, y lo más común es que no se los entienda).

Los analizadores sintácticos generados trabajan con la técnica SLR(1) oSLR para simplificar, la que es un caso especial de LR(k). A diferencia de latécnica LR(1) canónica y de la técnica LALR, esta técnica genera tablasmucho más pequeñas (se minimiza el número de estados del autómata de pila).Se la puede aplicar a casi todas las gramáticas de contexto libre que puedanecesitar un programador (el desarrollo de lenguajes de programación congramáticas complejas puede requerir trabajar con la técnica LALR, pero si latécnica SLR es aplicable entonces el analizador será más eficiente).

La técnica LR ha sido descripta por Knuth [1965], pero no resultópráctica porque el tamaño de las tablas que se debían construir eran demasiadograndes (recordar que en ese tiempo 16 kbytes era mucha memoria). En 1969Korenjak mostró que mediante esa técnica se podían producir analizadoressintácticos de tamaño razonable para las gramáticas de los lenguajes deprogramación. En 1969 y 1971, DeRemer inventó los métodos "LR simples"(SLR por Simple LR) y "LR con símbolo de anticipación" (LALR porlookahead-LR) que son más simples que los de Korenjak.

La utilización de la técnica SLR (y del resto de las LR) simplificamucho el trabajo del desarrollo de un traductor, siempre y cuando se dispongade un programa generador de las tablas de análisis sintáctico. Si no se disponede un generador de las tablas, la construcción de las mismas puede llegar adesalentar la construcción del traductor puesto que se requiere un dominioprofundo de los algoritmos de construcción y de la teoría en la que se basan.Una persona puede entender bien los algoritmos de construcción de las tablas,y aún así cometer muchos errores.

Algoritmos usados por el Generador de Analizadores Sintácticos

28

Page 29: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El analizador SLR es uno solo para todas las posibles gramáticas. Es unautómata de pila determinístico, y su funcionamiento es análogo al autómatafinito determinístico. El algoritmo se lo ilustra en la sección siguiente.

La tabla construida para un analizador SLR se llama tabla SLR, lagramática para la cual se pueda construir una tabla SLR se llamará gramática

SLR. Una gramática para la cual la construcción de la tabla SLR genereconflictos no es SLR, aunque se puedan resolver a mano los conflictos.

4.2 Análisis sintáctico por la técnica SLR (LR Simple)

Antes de explicar cómo se construyen las tablas es necesario verprimero cómo se las usa.

4.2.1 Algoritmo de análisis sintáctico SLR

Se dispone de una pila en la que se pueden almacenar estados (enterosno negativos) o símbolos de la gramáticas (terminales o no terminales).

También se dispone de un par de tablas a las que se les da el nombre deacción e ir_a.

La tabla acción contiene las acciones que puede ejecutar el autómata.Las acciones se especifican con una letra que especifica la acción y el númerode estado al que debe ir el autómata luego de ejecutarla. Las mismas puedenser:

1. Desplazamiento: se simboliza con la letra d y un número que indica elestado al que debe pasar el autómata.

2. Reducción: se simboliza con la letra r y un número que indica el númerode regla por la cual se reduce.

3. Aceptar: se simboliza con la letra a. No tiene un número de sufijo puestoque no hace falta; el autómata se detiene automáticamente al encontraresa orden.

4. Nada: si una entrada en esta tabla no contiene alguna de las tresalternativas anteriores entonces en la posición actual hay error desintaxis.

Algoritmos usados por el Generador de Analizadores Sintácticos

29

Page 30: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La tabla ir_a contiene números enteros no negativos que son los estadosa los que tiene que ir el autómata luego de ejecutar una reducción.

La figura siguiente muestra el algoritmo de análisis sintáctico LRsimple:

Se dispone de una pila vacía en la cual se coloca 0 como estado inicial.

Sea pt el puntero al primer terminal de la cadena de entrada.

Salir = No

Repetir

Sea E el estado en el tope de la pila y t el terminal apuntado por pt.

Si acción[E, t] = dY entonces

Apilar primero t y luego Y.

Avanzar pt al siguiente terminal.

Sino, si acción[E, t] = rX entonces

X es el número de regla por la que hay que reducir, entonces desapilar 2 veces el número de símbolos de la parte derecha de la regla número X.

Sea Y el estado que ahora está en el tope de la pila y A el no terminal dela parte derecha de la regla número X.

Apilar primero A y luego ir_a[X, A].

Sino, si acción[E, t] = a entonces

Se ha llegado al estado de aceptación.

Salir = Si.

Aceptar = Si.

Sino

Salir = Si.

Aceptar = No; hay error de sintaxis.

FinSi

Hasta que Salir = Si.

Si Aceptar = Si entonces

La oración de entrada cumple con la estructura definida por la gramática,esto es, es gramatical.

Sino La oración de entrada no es gramatical.

Algoritmos usados por el Generador de Analizadores Sintácticos

30

Page 31: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 10 Algoritmo de análisis sintáctico SLR

4.2.2 Ejemplo del funcionamiento del analizador sintáctico SLR

Para ejemplificar el funcionamiento del analizador sintácticotrabajaremos con la gramática siguiente (las reglas han sido numeradas):

1: P --> D I 2: D --> 'Var' L ':' 'Tipo' ';' 3: D --> 4: L --> L ',' 'Id' 5: L --> 'Id' 6: I --> I 'Instr' ';' 7: I -->

Las tablas de análisis sintáctico SLR para la gramática dada son lassiguientes:

| acción(estado, símbolo terminal) | ir_a(estado, símbolo no | | terminal)Est | 'Var' ':' 'Tipo' ';' ',' 'Id' 'Instr' FA | P D L I ----+--------------------------------------------+----------------------- 0 | d1 · · · · · r3 r3 | 2 3 · · 1 | · · · · · d4 · · | · · 5 · 2 | · · · · · · · a | · · · · 3 | · · · · · · r7 r7 | · · · 6 4 | · r5 · · r5 · · · | · · · · 5 | · d7 · · d8 · · · | · · · · 6 | · · · · · · d9 r1 | · · · · 7 | · · d10 · · · · · | · · · · 8 | · · · · · d11 · · | · · · · 9 | · · · d12 · · · · | · · · · 10 | · · · d13 · · · · | · · · · 11 | · r4 · · r4 · · · | · · · · 12 | · · · · · · r6 r6 | · · · · 13 | · · · · · · r2 r2 | · · · ·

Fig. 11 Tabla de análisis sintáctico SLR para la gramática de unlenguaje simple.

En la tabla acción el símbolo FA significa Fin de Archivo. Aunque noforma parte del texto de entrada, su inclusión fue realizada durante laconstrucción de las tablas; el símbolo Fin de Archivo es un símbolo terminalde la gramática ampliada (ver más adelante qué es una gramática ampliada).

Sea el texto de entrada el siguiente:

Var Id : Tipo ; Instr ;

Algoritmos usados por el Generador de Analizadores Sintácticos

31

Page 32: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El análisis sintáctico se ilustra en el cuadro siguiente. Se utiliza unespacio como separador de elementos de la pila. Si se ha llegado al fin dearchivo (FA) en la columna Entrada no habrán terminales.

Paso Pila Entrada Acción

1 0 Var Id : Tipo ; Instr ; d1

2 0 Var 1 Id : Tipo ; Instr ; d4

3 0 Var 1 Id 4 : Tipo ; Instr ; r5

4 0 Var 1 L : Tipo ; Instr ; Ir a 5

5 0 Var 1 L 5 : Tipo ; Instr ; d7

6 0 Var 1 L 5 : 7 Tipo ; Instr ; d10

7 0 Var 1 L 5 : 7 Tipo 10 ; Instr ; d13

8 0 Var 1 L 5 : 7 Tipo 10 ; 13 Instr ; r2

9 0 D Instr ; Ir a 3

10 0 D 3 Instr ; r7

11 0 D 3 I Instr ; Ir a 6

12 0 D 3 I 6 Instr ; d9

13 0 D 3 I 6 Instr 9 ; d12

14 0 D 3 I 6 Instr 9 ; 12 r6

15 0 D 3 I Ir a 6

16 0 D 3 I 6 r1

17 0 P Ir a 2

18 0 P 2 Aceptar

Fig. 12 Ejemplo de análisis sintáctico con la técnica SLR.

La pila del analizador puede quedar con muchos elementos y aún asíhaber llegado al estado de aceptación.

4.2.3 Clasificación de los errores que se pueden producir durante elanálisis sintáctico

El algoritmo de análisis sintáctico SLR presentado en la figura 10 noespecifica qué tipos de errores pueden aparecer ni cómo tratarlos. En esta

Algoritmos usados por el Generador de Analizadores Sintácticos

32

Page 33: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

sección se dará una definición de los tipos de errores que pueden aparecer yaque la bibliografía no da una definición rigurosa de los mismos.

Error lexicográfico: se dará este nombre al error que se produce al intentarbuscar un símbolo terminal siguiente al actual y se encontró un símbolo que noes parte del conjunto de símbolos terminales de la gramática. El Fin deArchivo (FA) no es error lexicográfico, sino que simplemente no hay mássímbolos terminales de entrada.

Error semántico: si la implementación del analizador sintáctico incluye laposibilidad de ejecutar acciones semánticas (ver sección 2.3.8 y 12.3.3),durante la ejecución de esas acciones se pueden producir errores. A esoserrores se les dará el nombre de errores semánticos.

Error sintáctico: si no es error lexicográfico ni error semántico entonces essintáctico. El autómata en este caso se queda sin saber qué acción ejecutar (laentrada de la tabla acción no está definida para el estado actual y el terminalde entrada).

Las definiciones precedentes son aplicables a todas las técnicas deanálisis que hay esta el momento de la escritura de este trabajo.

En el contexto de las técnicas LR(k), un error semántico puede serignorado sin que se produzcan efectos indeseados. No ocurre lo mismo con loserrores lexicográficos y sintácticos (nadie sabe con certeza lo que quisoescribir el autor del texto fuente), aunque los efectos colaterales puedenreducirse previo estudio y modificación "a mano" de las tablas.

4.3 Fundamentos de la construcción de las tablas de análisis SLR

Antes de explicar la construcción de las tablas se darán primero algunasdefiniciones, se explicarán algoritmos usados por el algoritmo de construcciónde las tablas de análisis sintáctico SLR y se explicarán los fundamentos de laconstrucción de las tablas del analizador SLR.

4.3.1 Elemento del análisis sintáctico LR(0)

Se denominará elemento del análisis sintáctico LR(0) (elemento paraabreviar) de una gramática G a una regla de G con un punto en alguna posiciónde la parte derecha.

Algoritmos usados por el Generador de Analizadores Sintácticos

33

Page 34: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Una regla que derive en la cadena nula (A --> ) genera un solo elementoque es "A --> . ".

Intuitivamente, un elemento indica hasta dónde se ha visto unaproducción en un momento dado del proceso de análisis sintáctico. Porejemplo, la regla A --> B C D genera cuatro elementos:

A ---> . B C DA ---> B . C DA ---> B C . DA ---> B C D .

El primer elemento indica que a continuación se espera ver en la entradauna cadena derivable de "B C D". El segundo elemento indica que se acaba dever en la entrada una cadena derivable de B, y que a continuación se espera veruna cadena derivable de "C D".

4.3.2 Operación Cerradura

Sea I un conjunto de elementos para una gramática G, Cerradura(I) esel conjunto de elementos construidos a partir de I y de G mediante las dossiguientes reglas:

1. Inicialmente, todo elemento de I se agrega a Cerradura(I).

2. Si A --> α . B β está en Cerradura(I) y B --> γ es una regla, entonces seagrega B --> . γ a Cerradura(I), si todavía no fue agregado. Se aplica estaregla hasta que no se puedan agregar más elementos a Cerradura(I).

Intuitivamente, si A --> α . B β está en Cerradura(I) es porque en algúnmomento del proceso de análisis sintáctico se cree que es posible ver acontinuación una cadena derivable de B como entrada. Si B --> γ es una regla,también se espera ver una subcadena derivable de B --> γ en éste punto, y poresta razón se incluye B --> . γ en Cerradura(I).

Ejemplo: para la gramática utilizada en el punto 4.2.2, sea I = { (P --> • D I) } entonces Cerradura(I) contiene los siguientes elementos:

P ---> • D I D ---> • 'Var' L ':' 'Tipo' ';' D ---> •

Algoritmos usados por el Generador de Analizadores Sintácticos

34

Page 35: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Otro ejemplo: para la gramática utilizada en el punto 4.2.2, sea I = { ( D ---> 'Var' • L ':' 'Tipo' ';' ) }, entonces Cerradura(I) contiene lossiguientes elementos:

D ---> 'Var' • L ':' 'Tipo' ';' L ---> • L ',' 'Id' L ---> • 'Id'

4.3.3 Mangos

Informalmente, un mango de una cadena es una subcadena queconcuerda con el lado derecho de una regla y cuya reducción al no terminal dellado izquierdo de la regla representa un paso a lo largo de la inversa de unaderivación por la derecha.

Formalmente, un mango de una forma de frase derecha γ es una reglaA-->β y una posición de γ donde la cadena β podría encontrarse y sustituirsepor A para producir la forma de frase derecha previa en una derivación por laderecha de γ. Es decir, si O ==>* αAω ==>* αβω, entonces A-->β si laposición que sigue de α es un mango de αβω. La cadena ω a la derecha delmango contiene sólo símbolos terminales.

Si la gramática no es ambigua entonces toda forma de frase derecha dela gramática tiene exactamente un mango.

Para la gramática del ejemplo dado en la sección 4.2.2, obsérvesen lafigura 12, la fila correspondiente al paso 14: la forma de frase derecha es

D I Instr ;

la operación que se va a ejecutar en ese paso es r6 y el mango es "I Instr ;",que concuerda con la parte derecha de la regla 6 ( I --> I 'Instr' ';' ). En estecaso, a la derecha del mango no hay símbolos terminales.

4.3.4 Prefijo Viable

Los prefijos de las formas de frase derecha que pueden aparecer en lapila de un analizador sintáctico por desplazamiento y reducción se denominanprefijos viables.

Una definición equivalente de un prefijo viable es la de que es un prefijode una forma de frase derecha que no continúa más allá del extremo derechodel mango situado más a la derecha de esta forma de frase. Con esta

Algoritmos usados por el Generador de Analizadores Sintácticos

35

Page 36: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

definición, siempre es posible añadir símbolos terminales al final de un prefijoviable para obtener una forma de frase derecha. Por lo tanto, aparentemente nohay error siempre que la porción examinada de la entrada hasta un punto dadopueda reducirse a un prefijo viable.

Por ejemplo, para la gramática del ejemplo dado en la sección 4.2.2,obsérvese en la figura 12, la fila correspondiente al paso 8, la forma de frasederecha es:

Var L : Tipo ; Instr ;

y se reduce por regla 2 el mango "Var L : Tipo ;" para obtener la forma defrase derecha siguiente:

D Instr ;

Aquí, D es un prefijo viable.

4.3.5 Operación ir_a

La función ir_a(I, X) donde I es un conjunto de elementos y X es unsímbolo de la gramática (terminal o no terminal) se define como la cerraduradel conjunto de todos los elementos A --> α X . β tales que A --> α . X βesté en I.

Intuitivamente, si I es el conjunto de elementos válidos para algúnprefijo viable, entonces ir_a(I, X) es el conjunto de elementos válidos para elprefijo viable γX.

Por ejemplo, para la gramática del ejemplo dado en la sección 4.2.2,para el conjunto de elementos I igual a:

P ---> • D I D ---> • 'Var' L ':' 'Tipo' ';' D ---> •

entonces ir_a(I, D) consta de:

P ---> D • I I ---> • I 'Instr' ';' I ---> •

Algoritmos usados por el Generador de Analizadores Sintácticos

36

Page 37: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

4.3.6 Colección Canónica de Conjuntos de Elementos del AnálisisSintáctico LR(0)

La construcción de la colección canónica de conjunto de elementosLR(0) se aplica a una gramática aumentada G' obtenida a partir de G por elagregado de la siguiente regla:

O' --> O

donde O es el símbolo inicial de la gramática G. Ahora O' es el símbolo inicialde la gramática G', a la que se llamará gramática aumentada. El objetivo deesta regla es la de indicar al analizador cuándo debe detener el análisissintáctico y anunciar la aceptación de la cadena. La aceptación se produceúnicamente cuando el analizador está por reducir O' --> O.

El algoritmo se muestra en la siguiente figura, en donde C es conjuntode conjuntos de elementos (la colección canónica LR(0) ):

Fig. 13 Construcción de la Colección Canónica LR(0)

En adelante, a cada I se lo llamará indistintamente conjunto deelementos LR(0) o estado.

Ejemplo: para la gramática dada en la sección 4.2.2, la gramáticaaumentada es:

P' --> PP ---> D I D ---> 'Var' L ':' 'Tipo' ';' D ---> L ---> L ',' 'Id' L ---> 'Id' I ---> I 'Instr' ';' I --->

Sea C = { Cerradura( { O' --> . O } ) }

Repetir

Para cada conjunto de elementos I en C y cada símbolo gramatical X tal queir_a(I, X) no esté vacío y no esté en C  hacer

Agregar ir_a(I, X) a C.

FinPara

Hasta que no se puedan agregar más conjuntos de elementos a C.

Algoritmos usados por el Generador de Analizadores Sintácticos

37

Page 38: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

y la colección canónica es:

Estado 0 (I0):P' ---> • P P ---> • D I D ---> • 'Var' L ':' 'Tipo' ';' D ---> •

Estado 1 (I1):D ---> 'Var' • L ':' 'Tipo' ';' L ---> • L ',' 'Id' L ---> • 'Id'

Estado 2 (I2):P' ---> P •

Estado 3:P ---> D • I I ---> • I 'Instr' ';' I ---> •

Estado 4:L ---> 'Id' •

Estado 5:D ---> 'Var' L • ':' 'Tipo' ';' L ---> L • ',' 'Id'

Estado 6:P ---> D I • I ---> I • 'Instr' ';'

Estado 7:D ---> 'Var' L ':' • 'Tipo' ';'

Estado 8:L ---> L ',' • 'Id'

Estado 9:I ---> I 'Instr' • ';'

Estado 10:D ---> 'Var' L ':' 'Tipo' • ';'

Estado 11:L ---> L ',' 'Id' •

Estado 12:I ---> I 'Instr' ';' •

Estado 13:D ---> 'Var' L ':' 'Tipo' ';' •

4.3.7 Idea Central del Método SLR

Los elementos del análisis sintáctico LR(0) pueden considerarse comolos estados del autómata finito no determinista que reconoce los prefijosviables. Para poder convertir el autómata en determinista hace falta agrupar los

Algoritmos usados por el Generador de Analizadores Sintácticos

38

Page 39: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

elementos en conjuntos. Los conjuntos serían entonces los estados delautómata finito determinista que reconoce los prefijos viables.

La idea central del método SLR es construir primero a partir de lagramática un AFD que reconozca los prefijos viables. Se construye lacolección canónica de elementos LR(0). Cada conjunto de elementos dentro dela colección canónica pasan a ser los estados del analizador sintáctico SLR(del AFD que el mismo usa).

Para el ejemplo dado en el punto anterior, el AFD que reconoce prefijosviables se muestra en la figura siguiente:

Fig. 14 AFD que reconoce prefijos viables de la gramática delejemplo.

El AFD de la figura precedente tiene dos problemas: no tiene estadosfinales y tiene transiciones con símbolos no terminales.

El hecho de tener transiciones con no terminales hace necesariodisponer de una pila para la implementación del autómata. El autómataresultante se pasa a llamar autómata de pila, que como ya se mencionó en elpunto 2.2.5, son los que implementan analizadores sintácticos para gramáticasdel Tipo 2 de la clasificación de Chomsky.

4.3.8 Función Anulable

La función Anulable se aplica a un símbolo no terminal de unagramática y devuelve Verdadero si ese símbolo es anulable.

Un símbolo no terminal A es anulable si de alguna forma, mediantederivaciones sucesivas con las reglas de la gramática, se transforma A en la

0

1

2

3

4

5

6

7

8

9

10

11

12

13

P

'Tipo' ';'

'Id'

I 'Instr' ';'

D

'Var'

'Id'

L ':'

','

Algoritmos usados por el Generador de Analizadores Sintácticos

39

Page 40: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

cadena nula ( A ==>* λ ). (λ representa a la cadena nula. En este trabajocuando en una regla se quiere denotar la presencia de la cadena nula no sepone nada puesto que es más claro.)

Definiremos primero una versión simple de Anulable a la que se lellamará AnulableSimple. Esta función devolverá Verdadero si hay una reglaque derive el no terminal directamente en la cadena nula ( A --> ).

A partir de la función de AnulableSimple se define la función Anulable

de la siguiente manera: un símbolo no terminal X de una gramática G esanulable si:

1. X es Anulable Simple ( X --> ).

2. Si existe alguna regla X --> Y Z, con Y y Z anulables.

El punto 2 hace que la definición sea recursiva, por lo tanto unalgoritmo que la implemente podrá ser recursivo, lo que no es aconsejabledebido a la cantidad de veces que se puede repetir el cálculo de Anulable paraalgunos símbolos no terminales.

Ejemplo: para la gramática siguiente

O ---> A B CA ---> a BA --->

B ---> b CB ---> CC ---> c OC --->

El cálculo de AnulableSimple para cada uno de los símbolos daría elsiguiente resultado:

O: no es anulable simple.A: si es anulable simple.B: no es anulable simple.C: si es anulable simple.

El cálculo de Anulable arroja el siguiente resultado:

O: si es anulable porque A, B y C son anulables.A: si es anulable porque es anulable simple.B: si es anulable porque hay una regla B --> C, y C es anulable.C: si es anulable porque es anulable simple.

4.3.9 La operación Primero

Si α es una cadena de símbolos gramaticales, se considera Primero(α)

como el conjunto de terminales que inician las cadenas derivadas de α.

Algoritmos usados por el Generador de Analizadores Sintácticos

40

Page 41: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Si α ==>* λ, entonces λ también está en Primero(α). El resultado de lafunción Primero es un conjunto de símbolos terminales, que obviamente es unsubconjunto de T (el conjunto de símbolos terminales de la gramática).

Para calcular Primero(X) para todos los símbolos gramaticales X, seproponen las siguientes reglas:

Fig. 15 Cálculo de Primero(X).

Observando la regla 1, se concluye que el cálculo de Primero(X) para Xterminal no tiene sentido, puesto que es un axioma.

A los efectos de la utilización de la función Primero en la generación delas tablas de análisis sintáctico SLR, el agregado de λ no es necesario. En losejemplos siguientes no se incluye λ en donde se debiera.

Ejemplo 1: para la gramática dada en la sección anterior (4.3.8) losconjuntos Primero sin Lambda (λ) son:

Primero(O) = { a b c }Primero(A) = { a }Primero(B) = { b c }Primero(C) = { c }

1. Si X es terminal, entonces Primero(X) es { X }.

2. Si X -- > λ es una regla, entonces agregar λ a Primero(X).

3. Si X es no terminal y X --> Y1 Y2 ... Yk entonces se agrega b aPrimero(X) si, para alguna i, b está en Primero(Yi) y λ está en todoslos conjuntos Primero(Y1), ..., Primero(Yi - 1); esto es, la cadenaY1...Yi - 1 ==>* λ.Si λ está en Primero(Yj) para toda j = 1, 2, ..., k, entonces se agregaλ a Primero(X); esto es, la cadena Y1...Yk ==>* λ.Por ejemplo, todo lo que está en Primero(Y1) sin duda estará enPrimero(X). Si Y1 no deriva en λ, entonces no se agrega nada más aPrimero(X), pero si Y1 ==>* λ, entonces se agrega Primero(Y2), yasí sucesivamente.

4. Se repetirán las tres primeras reglas hasta que no se puedan agregar

Algoritmos usados por el Generador de Analizadores Sintácticos

41

Page 42: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ejemplo 2: para la gramática dada en la sección (4.2.2) los conjuntosPrimero sin Lambda (λ) son:

Primero(P) = { 'Var' 'Instr' }Primero(D) = { 'Var' }Primero(L) = { 'Id' }Primero(I) = { 'Instr' }

4.3.10 La operación Siguiente

La función Siguiente se calcula para los símbolos no terminales de lagramática, únicamente.

Para calcular Siguiente(X) para todos los símbolos no terminales X, seproponen las siguientes reglas:

Fig. 16 Cálculo de Siguiente(X).

Obsérvese las reglas 2 y 3, al decir Primero(β) se está hablando enrealidad de la unión de varios conjuntos Primero(Xi) para i = 1, ..., k y todoslos Primero(Xi) excepto Primero(Xk) contiene a λ. Por lo tanto, se deberá teneresto en cuenta al implementar el algoritmo.

Obsérvese también que en la regla 2, al agregar todo lo que esté enPrimero(β) excepto λ a Siguiente(B) justifica el hecho de que en este trabajose calcula Primero(X) sin λ.

Ejemplo 1: para la gramática dada en la sección anterior (4.3.8) losconjuntos Siguiente(X) son los siguientes:

Siguiente(O) = { c b }Siguiente(A) = { b c }

1. Agregar FA (Fin de Archivo) a Siguiente(O), donde O es el símboloinicial y FA es el delimitador derecho de la entrada.

2. Si hay una regla A ---> α B β, entonces todo lo que esté enPrimero(β) excepto λ se agrega a Siguiente(B).

3. Si hay una regla A ---> α B o una regla A ---> α B β, dondePrimero(β) contenga λ (es decir, β ==>* λ), entonces todo lo queesté en Siguiente(A) se agrega a Siguiente(B).

Algoritmos usados por el Generador de Analizadores Sintácticos

42

Page 43: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Siguiente(B) = { c b }Siguiente(C) = { c b }

Ejemplo 2: para la gramática dada en la sección (4.2.2) los conjuntosSiguiente(X) son:

Siguiente(P) = { }Siguiente(D) = { 'Instr' }Siguiente(L) = { ':' ',' }Siguiente(I) = { 'Instr' }

4.4 Construcción de las tablas de análisis SLR

La construcción de las tablas de análisis sintáctico SLR (similar a lamostrada en la figura 11 de la sección 4.2.2) se resume en el algoritmomostrado en la figura siguiente.

Si los 3 primeros pasos generan acciones contradictorias, se dice que lagramática no es SLR(1) porque el algoritmo no consigue producir las tablaspara el análisis sintáctico. En este caso no se ejecutan los pasos siguientes.

Algoritmos usados por el Generador de Analizadores Sintácticos

43

Page 44: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 17 Construcción de las tablas de análisis sintáctico SLR.

Ejemplo 1: para la gramática dada en la sección 4.2.2, las tablas semuestran en la figura 12 que se encuentra en la misma sección. La coleccióncanónica de elementos LR(0) los encontrará en la sección 4.3.6. Los conjuntosSiguiente(X) los encontrará en la sección 4.3.10.

Ejemplo 2: para la gramática dada en la sección 4.3.8, los conjuntosSiguiente(X) los encontrará en la sección 4.3.10. La colección canónica de

1. Construir G', la gramática aumentada, a partir de G, por elagregado de la regla O' --> O, donde O era el símbolo inicial deG. O' pasa a ser el símbolo inicial en G'.

2. Construir C = { I0, I1, ..., In }, la colección canónica de conjuntosde elementos del análisis sintáctico LR(0) para la gramáticaaumentada G'.

3. El estado i se construye a partir de Ii. Las acciones de análisissintáctico para el estado i se determinan como sigue:

a. Si A --> α . x β está en Ii con x terminal e ir_a(Ii, x) = Ij,entonces asignar "desplazar j" a accion[i, x].

b. Si A --> α . está en Ii, con A distinto de O' entonces asignar"reducir por A --> α" a accion[i, x] para todo x perteneciente aSiguiente(A).

c. Si O' ---> O . está en Ii, entonces asignar "aceptar" a accion[i, FA] (FA es el Fin de Archivo).

4. La tabla ir_a(i, X) para el estado i y el no terminal X seconstruyen utilizando la regla: si ir_a[Ii, X] = Ij entonces ir_a[i, X] = j

5. Todas las entradas de las tablas no definidas por las reglas 3 y 4son consideradas "error".

6. El estado inicial del analizador es el que se construye a partir delconjunto de elementos que contiene a S' ---> . S

Algoritmos usados por el Generador de Analizadores Sintácticos

44

Page 45: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

elementos LR(0) es la siguiente (aquí a los terminales se los encierra entrecomillas simples para que no queden dudas):

Estado 0:O' ---> • O O ---> • A B C A ---> • 'a' B A ---> •

Estado 1:A ---> 'a' • B B ---> • 'b' C B ---> • C C ---> • 'c' O C ---> •

Estado 2:O' ---> O •

Estado 3:O ---> A • B C B ---> • 'b' C B ---> • C C ---> • 'c' O C ---> •

Estado 4:B ---> 'b' • C C ---> • 'c' O C ---> •

Estado 5:C ---> 'c' • O O ---> • A B C A ---> • 'a' B A ---> •

Estado 6:A ---> 'a' B •

Estado 7:B ---> C •

Estado 8:O ---> A B • C C ---> • 'c' O C ---> •

Estado 9:B ---> 'b' C •

Estado 10:C ---> 'c' O •

Estado 11:O ---> A B C •

Al construir la tabla acción obtenemos lo siguiente, en la que sedetectará 6 conflictos de desplazamiento-reducción:

acción(e, x) ir_a(e, X):

'a' 'b' 'c' FA O A B C

Algoritmos usados por el Generador de Analizadores Sintácticos

45

Page 46: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

0 d1 r3 r3 r3 2 3 · · 1 · d4 d5 r7 · · 6 7 2 · · · a · · · · 3 · d4 d5 r7 · · 8 7 4 · r7 d5 r7 · · · 9 5 d1 r3 r3 r3 10 3 · · 6 · r2 r2 r2 · · · · 7 · r5 r5 r5 · · · · 8 · r7 d5 r7 · · · 11 9 · r4 r4 r4 · · · · 10 · r6 r6 r6 · · · · 11 · r1 r1 r1 · · · ·

Los conflictos los generó el paso 3.b del algoritmo y son los siguientes:

1. En el estado 1, con el terminal 'c' hay que elegir entre d5 o r7.

2. En el estado 1, con el terminal 'b' hay que elegir entre d4 o r7.

3. En el estado 3, con el terminal 'c' hay que elegir entre d5 o r7.

4. En el estado 3, con el terminal 'b' hay que elegir entre d4 o r7.

5. En el estado 4, con el terminal 'c' hay que elegir entre d5 o r7.

6. En el estado 8, con el terminal 'c' hay que elegir entre d5 o r7.

Debido a que esta gramática genera conflictos en la construcción de lastablas SLR se dirá que la misma no es SLR. Una definición equivalente esdecir que la gramática es ambigua para la técnica de análisis SLR, lo que nosignifica que sea ambigua a secas (la construcción unívoca de un árbol deanálisis sintáctico no es posible con la técnica SLR, esto es, el algoritmo deconstrucción de las tablas se comporta en este caso como una función noinyectiva porque puede generar varias tablas accion alternativas para la mismagramática).

Más ejemplos de construcción de tablas las puede encontrar en elcapítulo 11 y 12 en donde se muestran ejemplos de ejecución de SLR1.

Algoritmos usados por el Generador de Analizadores Sintácticos

46

Page 47: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 5: El Generador de Analizadores Lexicográficos

Previo a la lectura de este capítulo se aconseja leer la sección 2.3.6donde se explica qué es un analizador lexicográfico (es muy importante que lolea para que no se confundan conceptos).

En este capítulo, al lenguaje reconocido por el analizador lexicográficose lo denominará lenguaje léxico. A las oraciones del lenguaje léxico se losdenominará símbolos. A los símbolos terminales de la gramática subyacente(la que explica la estructura del lenguaje léxico) se los denominará terminales

léxicos, los que usualmente son caracteres ASCII según la especificación OEM(para DOS y OS/2) o ANSI (para Windows).

La definición y el funcionamiento de un analizador lexicográfico seexplica en el punto 5.1, y la construcción de un analizador lexicográfico en5.2.

5.1 Funcionamiento propuesto de un Analizador Lexicográfico

En esta sección se propondrá una definición de analizador lexicográficoy un algoritmo para el funcionamiento del mismo.

5.1.1 Reconocedor de símbolo

Se denominará reconocedor de símbolo al objeto que describe cómo sedebe realizar la búsqueda de un símbolo de un lenguaje dado.

El lenguaje dado puede ser expresado por una expresión regular, y eneste caso se usaría un autómata finito determinístico para reconocer elsímbolo.

La otra forma posible es la de usar una simple comparación literal delsímbolo, como la que se usaría para reconocer palabras claves u operadores deun lenguaje (una simple comparación de cadena).

Entonces, el objeto reconocedor podrá ser un autómata finitodeterminístico o una cadena de terminales léxicos.

El Generador de Analizadores Lexicográficos

47

Page 48: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

5.1.2 Componentes de un Analizador Lexicográfico

Cualquier analizador lexicográfico construido usando esta teoríaconstaría de 2 partes:

1. Un conjunto de reconocedores de símbolos.

2. Un algoritmo que especifique cómo reconocer un símbolo de entradaque incluya reglas para la resolución de posibles conflictos.

Se produce un conflicto cuando 2 o más reconocedores de símbolosreconocen a una cadena de terminales del lenguaje léxico que comienza apartir de la posición actual.

El lenguaje reconocido por el analizador lexicográfico es la unión de loslenguajes reconocidos por cada reconocedor de símbolos, resolviendoconflictos en donde haya intersección de acuerdo a ciertas reglas dadas deantemano (ver sección siguiente).

5.1.3 Algoritmo de Examinación de un Analizador Lexicográfico

Para examinar la cadena de terminales léxicos se propone el siguientealgoritmo:

1. Recorrer el conjunto de reconocedores de símbolos para ver si alguno deellos reconoce una cadena de terminales léxicos a partir de la posiciónactual. Para cada reconocedor, si es autómata finito determinísticoentonces usar el algoritmo estándar de funcionamiento, y si es cadenausar el algoritmo estándar de comparación de cadenas.

2. Si al ejecutar el paso 1 se determina que hay 2 o más reconocedores desímbolos que reconocen una cadena de terminales léxicos a partir de laposición actual, el conflicto se resuelve por medio de las siguientesreglas:

a. Si hay un reconocedor de símbolo que reconoce una secuencia determinales léxicos más larga que el resto de los reconocedores,entonces se elige ése. Si hay empate entre dos o más reconocedores seprocede con las reglas siguientes.

b. Si el grupo de reconocedores para los que se produjo el empate sonAFDs (posiblemente construidos a partir de expresiones regulares), se

El Generador de Analizadores Lexicográficos

48

Page 49: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

elige el que se encontró primero en el conjunto de reconocedores desímbolos.

c. Si en el grupo hay una cadena de terminales léxicos se elige éste. Sihay varias se elige la primera que se encontró en el conjunto dereconocedores de símbolos.

5.2 Construcción de un Analizador Lexicográfico

La construcción de un analizador lexicográfico se reduce entonces a laconstrucción del conjunto de reconocedores de símbolos y a laimplementación de un algoritmo que utilice ese conjunto y que tenga elcomportamiento definido en 5.1.3.

Si un símbolo está definido por una expresión regular entonces sepropone utilizar el algoritmo de construcción de un AFD a partir de unaexpresión regular dado en la sección 3.3 (utilícese un generador) y agregar elAFD resultante al conjunto de reconocedores de símbolos. En cambio, si elsímbolo es una cadena literal, simplemente se la incluirá dentro del conjuntode reconocedores de símbolos.

El algoritmo que utilice el conjunto de reconocedores de símbolos seescribirá y depurará una sola vez. Lo que cambiará para cada analizadorlexicográfico será el conjunto de reconocedores de símbolos.

De esta manera, la complejidad de la construcción de un analizadorlexicográfico se reduce a la complejidad de la construcción de un AFD a partirde una expresión regular.

En este trabajo se separa la generación del analizador lexicográfico de lageneración de AFDs a partir de expresiones regulares. De esta manera, si esnecesario se puede construir manualmente el AFD para algún reconocedor desímbolo.

El Generador de Analizadores Lexicográficos

49

Page 50: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Parte 2. Implementación de los Generadores

50

Page 51: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 6: Implementación del Generador de Autómatas FinitosDeterminísticos

A los efectos de que el generador de autómatas finitos determinísticospueda ser incluido en programas del usuario, se creará una biblioteca C++ queofrecerá todas las funciones necesarias. La biblioteca recibió el nombre deExpReg, por Expresión Regular.

El generador de autómatas finitos determinísticos debe ser visto comoun programa de algún usuario que hace uso de la biblioteca de soporteExpReg. El generador recibió el nombre de AFD por Autómata FinitoDeterminístico.

La E/S se realizó utilizando la biblioteca BCE, cuyo autor es el mismode este trabajo.

El listado de los códigos fuentes los encontrará en la parte 5. Másdocumentación de la implementación la puede encontrar en el capítulo 10 y 13en donde se da una guía del usuario para AFD y ExpReg, respectivamente.

Cuando se quiera decir la función Func de la clase Clase se resumirádiciendo Clase::Func, que en el lenguaje C++ significa eso.

6.1 Estructuras de Datos

Las estructuras de datos de la implementación se hallan repartidas en 2archivos cabeceras (.H) a saber:

1. En expreg.h se encuentra toda la interfase visible por el usuario deExpReg.

2. En genafd.h están las estructuras de datos usadas para la generación delAFD a partir de una expresión regular de entrada.

3. En lse.h (de la Biblioteca BCE) está la implementación de ListasSimples Encadenadas (para cualquier tipo de dato como elemento de lalista), la que se implementa mediante templates.

Implementación del Generador de Autómatas Finitos Determinísticos

51

Page 52: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

6.1.1 Estructura de un Arbol Sintáctico para una Expresión Regular

El árbol sintáctico para una expresión regular ha sido implementado pormedio de la clase NodoArbol que se encuentra declarado en genafd.h.

Los campos dato de la clase son:

Tipo: indica el tipo de nodo. Para las hojas, este campo tiene el número dehoja (no puede haber 2 hojas con el mismo número), valor que est  entre 0 yN_HOJA ambos inclusive.

IdCar: identificador del caracter, es un índice para acceder a un vector dondeestá la descripción de la expresión monocaracter.

PrimUltCalc: tiene 0 si PrimeraPos (Prim) y UltimaPos (Ult) no han sidocalculados, distinto a 0 si ya se calcularon.

pIzq: subárbol de la izquierda del actual. Para los nodos '*', '+' y '?' elsubárbol se engancha en este campo. Para las hojas igual a 0.

pDer: subárbol de la derecha del actual. Se usa solamente para nodos del tipo'.' y '|'. Para los nodos '*', '+', '?' y hojas vale 0.

Prim y Ult: son listas de identificadores de las hojas (valor del campo Tipo delas mismas) que son PrimeraPos y UltimaPos respectivamente, del nodo actual.

Las operaciones PrimeraPos, UltimaPos y SiguientePos quedan a cargode funciones miembro de esta clase.

6.1.2 Estructura de un Estado del AFD durante su Construcción

La estructura de un estado del AFD durante su construcción seimplementa con la clase Estado que se encuentra declarada en genafd.h.

Tiene los siguientes campos:

Id: número de estado (0 a n - 1 si hay n estados)

Trans: es un vector en el que se almacenan los estados siguientes. Es una filade la tabla de transición de estados del AFD en construcción, la que se indexapor columna con caracteres. Tiene tantos elementos como caracteres distintosaparecen en el texto fuente.

Implementación del Generador de Autómatas Finitos Determinísticos

52

Page 53: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Pos: es una lista de las hojas del árbol sintáctico que se agrupan en este estado.

6.1.3 Estructura de un Autómata Finito Determinístico

Los autómatas finitos determinísticos se implementan con la claseAutomFinDet, la que se documenta ampliamente en la sección 10.5 y en lasección 13.2.

6.1.4 Estructura de las Tablas usadas para implementar un AutómataFinito Determinístico

Puesto que se prevé la construcción a mano de un autómata finitodeterminístico, la documentación en detalle de las tablas se incluye en lassecciones 10.5 y 13.2.

6.1.5 Estructura de una Expresión Regular

Una expresión regular se implementa con la clase ExpReg, que agrupa ytodas las funciones necesarias para trabajar con expresiones regulares,encapsulando la complejidad inherente a la construcción de un AFD a partir deuna expresión regular.

Se documenta en detalle en la sección 13.4.

6.1.6 Estructura de un Reconocedor de Símbolos

Los reconocedores de símbolos se implementan con la clase RecSimb,la que se documenta en detalle en la sección 13.5.

6.1.7 Estructura de un Analizador Lexicográfico

Un analizador lexicográfico es implementado con la clase AnaLex, quese documenta en detalle en la sección 13.6.

6.2 Construcción del Arbol Sintáctico para una Expresión Regular

La construcción de un árbol sintáctico para una expresión regular seimplementó usando la técnica de análisis sintáctico SLR. La versión actualutiliza tablas generadas con SLR1 versión 2 y la versión 2 de la biblioteca de

Implementación del Generador de Autómatas Finitos Determinísticos

53

Page 54: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

soporte de SLR1. La primera implementación usaba tablas generadas porSLR1 versión 1, con un analizador lexicográfico hecho a mano. Una vezobtenido una versión del generador de AFDs se implementó otro con la claseAnaLex de la biblioteca ExpReg versión 1; hasta el momento de lapresentación de este trabajo, el analizador lexicográfico continúa siendo elmismo.

El lenguaje de las expresiones regulares se documenta en el capítulo 10.

La función de acciones semánticas que son las que actualmenteconstruyen el árbol se llama AccSem, es conocida solamente en el módulonarbol01.cmm.

6.3 Cálculo de Anulable, PrimeraPos, UltimaPos y SiguientePos

El cálculo de las funciones PrimeraPos, UltimaPos y SiguientePosquedan a cargo de la función NodoArbol::CalcPrimUltSig. La funciónNodoArbol::Anulable realiza el cálculo de la función Anulable.

La función NodoArbol::CalcPrimUltSig ha sido definida en formarecursiva siguiendo las siguientes reglas:

1. Si para un nodo dado PrimeraPos, UltimaPos y SiguientePos ya han sidocalculados entonces no se hace nada.

2. Para cualquier tipo de nodo, primero se calcula PrimeraPos, UltimaPos ySiguientePos de los subárboles que pudiera tener. Luego se procedesegún las reglas dadas en la sección 3.2.2 y en la figura 6.

La función NodoArbol::Anulable es también recursiva, y procede deacuerdo a lo especificado por la figura 5.

6.4 Construcción de la tabla de transición de estados del AFD

La función ExpReg::Reasignar es la que construye un AFD a partir deuna expresión regular de entrada, la que se da en formato texto.

Primero se arma el árbol sintáctico, luego se calcula PrimeraPos,UltimaPos y SiguientePos para los nodos, y finalmente se procede a calcular

Implementación del Generador de Autómatas Finitos Determinísticos

54

Page 55: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

las transiciones mediante el procedimiento dado en la figura 7, en la sección3.3.2.

6.5 Funcionamiento de un AFD

El funcionamiento de un AFD se implementa con la funciónExpReg::Examinar, que se documenta en la sección 13.4.2 con mayordetalle.

6.6 Funcionamiento de un analizador lexicográfico

El funcionamiento de un analizador lexicográfico se encuentraencapsulado en la función AnaLex::Examinar, que se documenta en lasección 13.6.2 con más detalle.

6.7 Funcionamiento del Generador de Autómatas FinitosDeterminísticos

La implementación de un generador de autómatas finitos determinísticosse reduce sólo al uso de las rutinas de la biblioteca ExpReg. Es trabajo delusuario el obtener la expresión regular en formato texto en memoria. Laimplementación usada para AFD v 3.x se resume con los siguientes pasos:

1. Primero se debe obtener la expresión regular en memoria, de cualquierfuente (archivo, pantalla, etc.).

2. Mediante un objeto ExpReg se llama a ExpReg::Reasignar mandandocomo parámetro el texto con la expresión regular de entrada. Si esto noda error, entonces se prosigue con los pasos siguientes. Sino, había unerror en la expresión regular de entrada.

3. El fuente C++ del AFD (definición del objeto AutomFinDet) se realizallamando a la función ExpReg::ImprFuente, que recibe comoparámetro el nombre del archivo donde se debe imprimir y las cadenaspostfijos que se deben usar (ver sección 13.4.2 para más detalle).

4. Una versión en formato texto del AFD se imprime llamando a la funciónExpReg::Imprimir pasando como parámetro el archivo donde sedeberá imprimir.

Implementación del Generador de Autómatas Finitos Determinísticos

55

Page 56: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Los 4 pasos precedentes pueden ser fácilmente implementados en unasola función y en cualquier sistema operativo para el que se disponga de uncompilador de C++. El objetivo de la reusabilidad fácil del generador de AFD

se ha cumplido.

Para la implementación, se puede seguir la siguiente, la cual esindependiente del sistema operativo:

// Sea cad una cadena Ascii terminada por un 0 (una cadena C++) Ascii0 cad; // Paso 1: aquí cargar cad con el texto con la expresión regular

// Paso 2: probar generar el AFD a partir del texto fuente: ExpReg er; Ascii0 CadPosErr; if (! er.Reasignar(cad, CadPosErr)) return ERROR;

// Paso 3: guardar fuente C++ if (! er.ImprFuente(NomArchCMM, 0, 0)) return ERROR;

// Paso 4: guardar archivo de texto con autómata ArchivoSO arch; if (arch.Abrir(NomArchTXT, MA_E, MD_TXT)) return ERROR;

er.Imprimir(arch); arch.Cerrar();

La implementación que se realizó para AFD v 3.x está basada en elcódigo precedente, y se la puede ver en las secciones 22.1 y 22.2, donde semuestra el código fuente.

Implementación del Generador de Autómatas Finitos Determinísticos

56

Page 57: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 7: Implementación del Generador de AnalizadoresSintácticos SLR y del Generador de AnalizadoresLexicográficos

A los efectos de que el generador de analizadores sintácticos SLR puedaser incluido en programas del usuario, se creará una biblioteca C++ queofrecerá todas las funciones necesarias. La biblioteca recibió el nombre deBiblioteca de Soporte del Generador de Analizadores Sintácticos SLR.

El generador debe ser visto como un programa de algún usuario quehace uso de la biblioteca de soporte. El generador recibió el nombre de SLR1por SLR(1).

La E/S se realizó utilizando la biblioteca BCE.

El listado de los códigos fuentes los encontrará en la parte 5. Másdocumentación de la implementación la puede encontrar en el capítulo 11 y 12en donde se da una guía del usuario para la biblioteca de soporte y SLR1.

Este capítulo documenta solamente la implementación usada en laversión 2.x del generador de analizadores sintácticos. La implementaciónusada por la versión 1 se documenta brevemente en el capítulo que presenta laguía del usuario del mismo.

7.1 Estructuras de Datos

Las declaraciones de las estructuras de datos se hallan repartidos envarios módulos cabeceras a saber:

1. En gramlc.h se encuentran declaradas todas las clases y funciones paratrabajar con gramáticas libre de contexto.

2. En genslr.h se encuentran declaradas todas las clases y funcionesutilizadas por el generador de analizadores sintácticos SLR.

3. En slr1.h se encuentran declaradas todas las clases y funciones paratrabajar con analizadores sintácticos SLR(1).

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

57

Page 58: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

7.1.1 Estructura de un Símbolo de una Gramática

La estructura de un símbolo de una gramática se implementa con laclase Simbolo. La clase tiene los siguientes campos datos:

Cad: es un puntero a una cadena Ascii0 asignada dinámicamente que tiene laversión texto del símbolo, exactamente igual a como lo especificó el usuario.

Codigo: es el código del símbolo. Se usa un entero de 15 bits (obsérvese quees un campo tipo bit), por lo que habrá a lo sumo 23767 símbolos posibles.

NoTerminal: este campo es de 1 bit; contiene 0 si éste símbolo es terminal y 1si es no terminal.

Un símbolo de una gramática puede ser unívocamente identificadousando los campos Codigo y NoTerminal. A la combinación de estos doscampos se lo denominará código compuesto del símbolo.

7.1.2 Estructura de un Conjunto de Símbolos

Un conjunto de símbolos es la base para la definición de la estructura deuna regla y de un alfabeto.

La clase ConjSimb define la interfase mínima que debe tener un claseque implemente un conjunto de símbolos e implementa las operacionesfundamentales aplicables a un conjunto de símbolos. Esta clase es virtual pura.

La clase ConjSimbLSE implementa un conjunto de símbolos usandouna lista simple encadenada de símbolos. Se eligió lista simple encadenadadebido a que no se sabe de antemano el número de símbolos que tendrá elconjunto, y de esta forma se ahorra memoria. Por otra parte, como siemprehabrán pocos símbolos (en promedio 4 o 5), la pérdida de tiempo por usarbúsqueda secuencial es mínima.

La clase ConjSimbLSE tiene 2 campos datos:

lse: es la lista simple encadenada de símbolos. Se usa la instanciaLSE<Simbolo> de la familia de clases LSE<X> definida como template enlse.h. El archivo lse.h pertenece a la Biblioteca BCE cuyo autor es el mismo deeste trabajo.

pUlt:es el puntero al último elemento de la LSE de símbolos. Se mantiene elpuntero al último debido a que siempre se agregan elementos al final de la lista

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

58

Page 59: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

para mantener el orden de aparición de los mismos, y de esta manera se reduceal mínimo el agregado de un elemento a la lista.

La función ConjSimbLSE::AgregarSinCad agrega un símbolo alconjunto pero sin asignar el campo Cad del mismo, esto es, sólo se realiza unacopia de su código compuesto.

7.1.3 Estructura de una Regla de una Gramática Libre de Contexto

La estructura de una regla de una gramática libre de contexto seimplementa con la clase ReglaLC, la que deriva de ConjSimbLSE. Se agregaun solo campo dato a esta clase:

AccSem: contiene un texto con el código de las acciones semánticas a ejecutarcuando se reduzca por esta regla. Puede o no ser usado.

En ConjSimbLSE por defecto no se acepta redundancia de símbolos. Sedenominará redundancia de símbolo a la repetición de los mismos dentro de unmismo conjunto. En una ReglaLC si se acepta redundancia, y es a los efectosde contemplar la posibilidad de que un símbolo pueda aparecer varias veces enuna regla.

La flecha (o símbolo separador) no se incluye. El primer elemento de lalista es el no terminal de la izquierda de la regla. El segundo elemento es elprimer símbolo de la parte derecha de la regla. El tercer elemento es elsegundo símbolo de la parte derecha de la regla; y así sucesivamente. Si laregla es de la forma "A --> " ( A --> λ ) entonces la lista tendrá solamente unelemento.

7.1.4 Estructura de un Alfabeto

La estructura de un alfabeto se implementa con la clase Alfabeto. Lamisma deriva de la clase ConjSimbLSE, y no agrega nada a la misma.

7.1.5 Estructura de un Descriptor de un Terminal

La estructura de un descriptor de un terminal se implementa con la claseDescrTerminal.

Los descriptores de terminales sirven para dar soporte a las sentencias#IGNORAR y #TERMINAL de la especificación 2.0 de la metagramática

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

59

Page 60: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

usada por la función Gramatica::Reasignar para la carga de una gramática enmemoria (consulte la sección 12.3 donde se documenta la metagramática).

Los campos datos de esta clase son:

Cadena: es el identificador que aparece en las directivas IGNORAR yTERMINAL. Si la cadena aquí almacenada no es elemento del conjunto desímbolos terminales entonces la directiva usada fue IGNORAR.

NomArch: es el nombre del archivo donde se encuentra la expresión regularque define la estructura de éste terminal. Si aquí hay una cadena nula entoncesse usará Cadena como nombre de archivo.

7.1.6 Estructura de un Descriptor de Acción Semántica

Un descriptor de acción semántica se usa para el caso de que se hayausado la directiva ACCSEM. Al encontrar la directiva ACCSEM se construyeun descriptor de acción semántica que contiene:

Ident: el identificador usado en la directiva.

TxtAccSem: el texto correspondiente al bloque de código especificado en ladirectiva. En donde se encuentre Ident en el texto de la gramática fuente sedeberá entender que se hace referencia a éste bloque de código.

7.1.7 Estructura de una Gramática Libre de Contexto

Una gramática libre de contexto se implementa con la clase Gramatica.Los campos datos de esta clase son:

Term: es el alfabeto de símbolos terminales. Se usa la clase Alfabeto.

NoTerm: es el alfabeto de símbolos no terminales. Se usa la clase Alfabeto.

Reglas: es el conjunto de reglas que definen la estructura del lenguaje. Seimplementa con una lista simple encadenada de objetos ReglaLC.

BlqCodInic: contiene el texto del bloque de código que se puso antes de lasreglas en el texto fuente de esta gramática. Se usa durante la generación delcódigo C++ de las acciones semánticas.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

60

Page 61: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ClaseElemPila: si el analizador sintáctico usará una clase distinta a la definidapor defecto, en este campo estará el nombre de esa clase.

TablaAccSem: es el conjunto de las acciones semánticas definidas usando ladirectiva ACCSEM. Contiene las acciones semánticas que son comunes a 2 omás reglas. Se implementa usando la clase LSE (por medio de lista simpleencadenada).

TablaTerminal: si hay terminales descriptos por expresiones regulares, enesta tabla están los nombres de archivos donde se encuentran esas expresionesregulares. Esta tabla se construye a partir de las directivas TERMINAL eIGNORAR. Se implementa usando la clase LSE.

MayIgualMin: si este campo es igual a 0 entonces las mayúsculas soninterpretadas como diferentes a las minúsculas (como en C++). Si es distinto a0 entonces serán tomadas como iguales (como Pascal).

CodError: contendrá el código de error luego de haber ejecutado la operaciónGramatica::Reasignar.

Esta clase agrupa y encapsula las siguientes funciones importantes:Anulable, Primero, Siguiente, generador del código C++ de las accionessemánticas y al generador de analizadores lexicográficos (Gramatica::

ImprAnaLex).

7.1.8 Estructura de un Símbolo para el Analizador Sintáctico SLR

La estructura de un símbolo para cualquier analizador sintáctico SLRgenerado es una versión resumida de la clase Simbolo. Se implementa con laclase SimboloSLR, que contiene los siguientes campos:

Id: es el código del símbolo.

NoTerminal: si tiene 0 entonces éste símbolo es terminal, caso contrario es noterminal.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

61

Page 62: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

7.1.9 Estructura por defecto de los Elementos de la Pila del AnalizadorSintáctico SLR

La estructura por defecto de los elementos de la pila de cualquieranalizador sintáctico SLR generado se implementa con la clase ElemPila.Contiene los siguientes campos:

Simb: aunque este campo es de acceso publico, sólo debe ser utilizado por elanalizador sintáctico SLR y debe ser usado como de sólo lectura. Contiene elSimboloSLR1 correspondiente a ésta posición de la pila.

Estado: Contiene el número de estado correspondiente a ésta posición de lapila. Aunque este campo es de acceso publico, sólo debe ser utilizado por elanalizador sintáctico SLR y debe ser usado como de sólo lectura.

CadTerm: es la cadena del terminal leído por el analizador lexicográfico yque corresponde a ésta posición de la pila.

Si necesita campos adicionales para utilizarlos en las accionessemánticas, se aconseja que la clase que implemente el elemento de la pila seauna derivada de ésta.

7.1.10 Estructura de un Analizador Sintáctico SLR

La estructura de un analizador sintáctico SLR se implementa con laclase AnalSLR1. Esta clase es una clase template, siendo el tipo de dato delelemento de la pila el parámetro template. De esta manera, se escribió una solavez el código del analizador sintáctico SLR y el mismo servirá para cualquiertipo de elemento de pila que se le pueda ocurrir a cualquier usuario encualquier tiempo.

La clase template AnalSLR1 en realidad define una familia de clases,cada una de las cuales implementa un caso particular de analizador SLR, quesólo difiere del resto en el tipo de elemento de la pila. El funcionamiento delanalizador es el mismo para todas las clases (obviamente), lo único que puedecambiar son las tablas y la pila. El tipo de elemento de la pila y las tablas seespecificarán durante la creación del objeto AnalSLR1.

Al pedir realizar el análisis sintáctico, el analizador le pedirá que leindique quién hará el análisis lexicográfico. De esta forma se contempla laposibilidad que para un analizador sintáctico se puedan usar variosanalizadores lexicográficos en un mismo programa. El analizadorlexicográfico es el que realmente tratará con el texto fuente de entrada (a

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

62

Page 63: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

analizar sintácticamente). Se espera que el analizador lexicográfico haya sidoimplementado usando la clase AnaLex.

Los campos datos de esta clase son protegidos salvo el campoCodError. Ellos son:

ntlpd: es una tabla generada por el generador de analizadores sintácticos.Contiene el número de terminales, el número de no terminales, y para todas lasreglas de la gramática, el código del no terminal de la regla y la longitud de laparte derecha de la regla.

accion: es la tabla acción que se explicó en la sección 4.4. Puede haber sidogenerada por el generador de analizadores sintáctico SLR.

ir_a: es la tabla ir_a cuya construcción de documenta en la sección 4.4. Puedehaber sido generada por el generador de analizadores sintáctico SLR.

fAccSem: es un puntero a la función que ejecuta las acciones semánticas.

fLimPila: es un puntero a la función que limpia la pila.

fVer: es un puntero a la función que permite ver el progreso del análisissintáctico.

CodError: aquí se almacena el código de error que pudiera haberse producidodurante una sesión de análisis sintáctico.

Con limpiar la pila se hace referencia a alguna posible operaciónespecial que a veces es necesario cuando se trabaja con objetos muy complejoscomo campos de la clase que implementa los elementos de la pila. Se aconsejano usar una función que limpie la pila, en su defecto, se debe hacer que eldestructor de la clase que implementa los elementos de la pila sea la querealice la limpieza de ése elemento.

Consulte también la sección 12.8 que documenta esta clase desde unaperspectiva del usuario.

7.1.11 Estructura de la Pila del Analizador Sintáctico SLR

La pila del analizador sintáctico SLR se implementa usando vectores,cuyo tamaño será indicado por el usuario al llamar a la función AnalSLR1::

Analizar.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

63

Page 64: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Por defecto, el tamaño del vector es 50 elementos, lo que es suficientepara la mayoría de las situaciones. Si la gramática con la que se construyó ésteanalizador usa mucho la recursividad por derecha entonces puede necesitar untamaño más grande de la pila.

La pila del analizador es local a la función AnalSLR1::Analizar, estoquiere decir que la misma será construida y destruida cada vez que se llame aesa función. De esta manera, mientras no se esté usando el analizadorsintáctico la pila no estará usando memoria.

Los elementos de la pila son de la clase especificada durante la creacióndel objeto AnalSLR1.

Consulte también el capítulo 12 que documenta a SLR1 v 2.x desde unaperspectiva del usuario.

7.1.12 Estructura de las Tablas del Analizador Sintáctico SLR

Las tablas del analizador sintáctico SLR se implementaron en vectores,con los elementos acomodados por fila mayor.

Aunque las tablas accion e ir_a pueden ser esparcidas. No se contemplala posibilidad de almacenarlas en una estructura que reduzca el espacionecesario para almacenarlas, porque para la gramática más grande con la quese trabajó, las tablas llegaron a ocupar 4000 bytes aproximadamente. Se sabeque cualquier computadora tiene más de 1 megabyte de RAM, entonces no setocó la implementación original de las tablas. Por otro lado, posiblemente seamás conveniente perder espacio y ganar velocidad en acceso (se realizanmuchos accesos aleatorios a las tablas, durante el análisis sintáctico).

ntlpd: viene de no terminal de la izquierda - longitud de la parte derecha de laregla.

Esta tabla contiene elementos de 2 bytes de tamaño. El primer byte es elcódigo del no terminal de la izquierda de la flecha de la regla. El segundo bytecontiene la cantidad de elementos de la parte derecha de la flecha de la regla, 0si deriva en λ.

El elemento 1 contiene información de la regla 1, el elemento 2 contieneinformación de la regla 2, y así sucesivamente.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

64

Page 65: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El elemento 0 contiene información especial, que difiere del resto de loselementos de la tabla: en el primer byte (el byte alto si se está trabajando conuna PC sea cual fuere el sistema operativo) contiene el número de símbolos noterminales de la gramática, el segundo byte (el byte bajo si se está usando unaPC) contiene el número de símbolos terminales.

accion:

Cada elemento de esta tabla debe ser visto como un entero no negativode 2 bytes. Los elementos de la tabla acción se acomodan por fila mayor. Laposición correspondiente al símbolo fin de archivo es la columna 0 de lamatriz, la columna 1 corresponde al primer terminal, la columna 2 al segundoy así sucesivamente.

Los bits 15 y 14 contienen el código de acción, a saber: 00 paradesplazar, 01 para aceptar y 10 para reducir. El código 11 no se usa.

Los bits restantes se usan para especificar el nuevo estado al que debepasar el autómata.

Si un elemento corresponde a una posición de error de sintaxis, sedeberá almacenar un 0.

Si un elemento corresponde a una acción de desplazamiento, el númeroestará en el rango de 0 y 16383, ambos inclusive. Nunca se encontrará laacción d0 puesto que no se encontrará O' a la derecha de ninguna regla (para laconstrucción de las tablas se partió de una gramática ampliada; consulte lasección 4.4).

Para el elemento que tenga la acción aceptar se encontrará el número16384. Habrá únicamente 1 solo elemento con ese valor.

Para los elementos que correspondan a reducciones se encontraránnúmeros en el rango de 32769 al 49151, ambos inclusive.

Si se encuentra un número que no haya sido especificado en los párrafosprecedentes entonces hubo problemas durante la construcción de ésta tabla.

ir_a:

Cada elemento de esta tabla debe ser visto como un entero nonegativo de 2 bytes. Los elementos de la tabla acción se acomodan por fila

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

65

Page 66: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

mayor. La columna 0 corresponde al primer no terminal, la columna 1 alsegundo, la columna 2 al tercero, y así sucesivamente.

Los valores que contiene cada elemento son directamente el número deestado al que debe ir el autómata. Si la entrada de la tabla no está definidaentonces se deberá poner un 0.

7.1.13 Estructura de un Elemento del Análisis Sintáctico LR(0)

La estructura de un elemento del análisis sintáctico LR(0) se implementacon la clase ElemCanonLR0, cuyos campos son:

pr: puntero a la regla a la que corresponde.

punto: puntero a la posición dentro de la regla, en donde se encuentra elpunto.

7.1.14 Estructura de un Conjunto de Elementos del Análisis Sintáctico LR(0)

El conjunto canónico de elementos se implementa por medio de unalista simple encadenada de elementos ElemCanonLR0. La clase queimplementa se llama ConjElem y los campos datos son:

lse: es la lista simple encadenada de elementos.

numelem: es el número de elementos que hay en lse.

Se eligió la estructura de lista simple encadenada para implementar elconjunto porque se desconoce de antemano el número de elementos queresultan luego del cálculo de la función ir_a (ver sección 4.3.5).

7.1.15 Estructura de un Estado del Analizador Sintáctico SLR durante laConstrucción de las Tablas

Un estado se implementa con la clase Estado. Los campos dato de estaclase son:

pce: es un puntero al conjunto de elementos de éste estado.

n: es el número que le tocó a éste estado.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

66

Page 67: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ves: es el vector de estados siguientes a éste estado. Contiene el resultado de lafunción ir_a que se documenta en la sección 4.3.5, para cada símbologramatical. El número de elementos de este vector es el número de terminalesmás el número de no terminales más uno (para el fin de archivo).

7.1.16 Estructura de la Colección Canónica de Conjuntos de Elementos delAnálisis Sintáctico LR(0)

La estructura de la colección canónica de conjunto de elementos seimplementa con la clase ConjEst.

Se eligió la estructura de lista simple encadenada para el conjunto deestado debido a que no se sabe de antemano el número de estados que habrá,ni tampoco se hacen muchos accesos secuenciales como para justificar unaestructura de datos rara.

Los campos dato de la clase son:

lse: la lista simple encadenada de estados. El elemento 0 correspondrá alestado 0, y así sucesivamente.

numest: es el número de estados, número de elementos que hay en lse.

Esta clase es la que actualmente está encargada de construir las tablas deanálisis sintáctico para una gramática dada. La función se llamaConjEst::Armar, y recibe como parámetro una Gramatica.

7.2 Carga de una Gramática en Memoria

Se denominará carga de una gramática en memoria al proceso de pasarde formato texto al formato especificado por la clase Gramatica.

La conversión de formato la realiza la función Gramatica::Reasignar,que recibe como parámetro un texto en formato especificado por lametagramática documentada en la sección 12.3.

Se construyó, a tal efecto, un analizador lexicográfico y un analizadorsintáctico SLR. Se usaron las clases AnaLex y AnalSLR1 respectivamente.Las acciones semánticas escritas se encuentran en la metagramática.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

67

Page 68: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Al finalizar con éxito la ejecución de la funciónGramatica::Reasignar, la gramática está lista para ser procesada a efectos deconstruir un analizador sintáctico y lexicográfico para la misma.

Si hay algún problema, el código del error se encontrará enGramatica::CodError.

7.3 Generación de un Analizador Lexicográfico

La generación de un analizador lexicográfico se realiza a partir de unalista de descriptores de terminales y del conjunto de símbolos terminales deuna gramática. La generación del analizador lexicográfico está basada en lateoría explicada en el capítulo 5.

Se deberá construir un vector de reconocedores de símbolos a partir delos descriptores y del conjunto de terminales usando las siguientes reglas:

1. Si un símbolo terminal se encuentra en la lista de descriptores determinales entonces se asume que el mismo está descripto por unaexpresión regular que se encuentra en un archivo de texto cuyo nombreestá en el descriptor. Se incluirá entonces el autómata finitodeterminístico generador por el programa AFD (o cualquier generadorque use la biblioteca ExpReg) a partir de ese archivo.

2. Si un símbolo terminal no se encuentra en la lista de descriptores y es unliteral (se llamará literal a un símbolo que haya sido especificado entrecomillas simples o dobles), entonces se especifica esa cadena decaracteres en la construcción del reconocedor de símbolo respectivo.

3. Si un símbolo terminal no se encuentra en la lista de descriptores y no esun literal entonces en la especificación de la gramática no se dio unadescripción correcta del mismo. El descriptor de estos terminales seráconstruido de manera similar a los del punto anterior, pero deberá sermodificado a efectos de que el analizador lexicográfico funcione de lamanera esperada.

4. Si hay un descriptor de símbolo para el cual no hay un correspondientesímbolo terminal, entonces se asume que hay un secuencias decaracteres en el texto fuente que deberán ser ignorados, y la estructurade esas secuencias están especificadas por expresiones regulares que seencuentran en los archivos especificados por los correspondientes

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

68

Page 69: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

descriptores. Por ejemplo, es común ignorar blancos y comentarios enun texto correspondiente a una oración del lenguaje.

La función que implementa los pasos anteriores se llama Gramatica::

ImprAnaLex, que es una versión que genera un fuente C++ para el analizadorlexicográfico, que se implementa usando la clase AnaLex.

En este trabajo no se contempla la construcción dinámica deanalizadores lexicográficos. Un constructor dinámico sería el que tome unagramática y construya directamente el objeto AnaLex, dejándolo listo para serusado en el mismo programa en donde se encuentra el constructor dinámico.La base para escribir el constructor dinámico la puede encontrar en el códigofuente de Gramatica::ImprAnaLex.

7.4 Generación de un Analizador Sintáctico SLR

La generación de las tablas para un analizador sintáctico SLR se resumeen los siguientes pasos:

1. Primero cargar la gramática en memoria, esto es, construir un objetoGramatica que contenga la gramática fuente. Se debe utilizar la funciónGramatica::Reasignar para convertir de formato texto a formatoGramatica.

2. A partir de esa gramática se debe armar la colección canónica deconjuntos de elementos del análisis sintáctico LR(0). Esta operaciónconstruye además las tablas acción e ir_a que definen al analizadorsintáctico para la gramática fuente. Se debe utilizar la funciónConjEst::Armar.

3. Para generar el código C++ del analizador lexicográfico se debe utilizarla función Gramatica::ImprAnaLex.

4. Para generar el código C++ de las acciones semánticas se debe utilizarGramatica::ImprAccSem.

5. Para generar el código C++ de las tablas se debe utilizar la funciónConjEst::ImprTablaC.

6. Para generar un archivo de texto con los estados y las tablas delanalizador generado se debe utilizar la función ConjEst::ImprTabla.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

69

Page 70: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La implementación de los pasos precedentes se encuentra en el módulogenslr1.cmm. La parte independiente del sistema operativo del mismo setranscribe a continuación:

// Implementación de la generación de un analizador sintáctico SLR y de un// analizador lexicográfico a partir de una gramática.// El código siguiente deberá estar dentro de alguna función C++.// Si es necesario se deberá intercalar código que muestre el progreso y// los errores que pudieran ocurrir.

// Objetos utilizados: Gramatica G; ConjEst AutomataSLR1; Ascii0 CadPosErr, GramTxt; const char * nom, cmm[] = ".cmm", est[] = ".est", tab[] = ".tab"; ArchivoSO a;

// Cargar la gramática en la memoria: if ( a.Abrir(NomArch, MA_L) ) return ERROR; // imposible abrir archivo

if (! GramTxt.Reasignar(a.Tam()+1)) return ERROR; // falta memoria para cargar el texto

if ( ! a.Leer( (char *) GramTxt, a.Tam() ) ) return ERROR; // error de e/s al intentar leer el texto desde archivo

a.Cerrar();

// Realizar análisis sintáctico y reasignar a objeto Gramatica if (! G.Reasignar(GramTxt, CadPosErr)) return ERROR; // error de sintaxis o lexicográfico en gramática G.ArmarAlfabetos(); // terminal y no terminal

// Generar el código fuente con las acciones semánticas: nom = NomExt(NomArch, cmm); if (a.Abrir(nom, MA_E)) return ERROR;

G.ImprAccSem(a, Sufijo); a << "\n";

// Generar código para el analizador léxico: G.ImprAnaLex(a, Sufijo);

// Imprimir analizador sintáctico: se genera declaración de la forma // AnalSLR1<ElemPila> asSufijo(ntlpdSufijo, accionSufijo, ir_aSufijo, // AccSemSufijo); a << "\n// Definición del analizador sintáctico (SLR1 v 2.3).\n" "// Cambiar de lugar la definición si es necesario.\n\n" "# include \"" << NomExtSinDir(NomArch, tab) << "\" // tablas del analizador sintáctico\n\nAnalSLR1<" << (const char *) G.ClaseElemPila << "> as" << Sufijo << "(ntlpd" << Sufijo << ", accion" << Sufijo << ", ir_a" << Sufijo << ", AccSem" << Sufijo << ");";

a.Cerrar();

// Imprimir la gramática en archivo .est nom = NomExt(NomArch, est);

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

70

Page 71: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if ( a.Abrir(nom, MA_E, MD_TXT) ) return ERROR; // no se puede abrir el archivo .est para escritura a << G;

// Armar las tablas de análisis sintáctico AutomataSLR1.Armar(G, FuncError);

// Imprimir las tablas en archivo .est a << "\n\nEstados: \n\n" << AutomataSLR1; AutomataSLR1.ImprTabla(a, G); a.Cerrar();

// Imprimir las tablas en archivo .tab AutomataSLR1.ImprTablaC(NomExt(NomArch, tab), G, Sufijo);

// Fin de la implementación

7.5 Implantación del Algoritmo de Análisis Sintáctico SLR

El algoritmo de análisis sintáctico SLR que se muestra en la figura 10 dela sección 4.2.1, se implementa con la función AnalSLR1::Analizar, querecibe como entrada el analizador lexicográfico a usar y el tamaño de la pila.

Consulte la sección 12.8 que documenta la función AnalSLR1::

Analizar.

Implementación del Generador de Analizadores Sintácticos SLRy del Generador de Analizadores Lexicográficos

71

Page 72: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Parte 3. Documentación para el Usuario

72

Page 73: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 8: Documentación de AFD versión 1.x

El texto de este capítulo es la documentación de AFD v 1.x, y debe sertomado como un libro aparte. No se hacen referencias a otros capítulos de estetrabajo.

La última versión de AFD importante disponible es la 3.x. Sudocumentación la encontrará en el capítulo 10. Si se planea usar AFD entoncesse debe usar esa versión o alguna posterior.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

8.1 Introducción

El programa AFD (por autómata finito determinístico) es un generadorde autómata finito determinístico (dado en tablas y fuente C++) a partir de unaexpresión regular fuente.

Esta versión ha sido realizada para uso interno del autor solamente, parapoder mejorar el analizador lexicográfico de la versión 2. Es muy limitada encuanto al lenguaje fuente de especificación de una expresión regular. Ademásla inclusión del AFD generado en un programa es un poco complicado.

Esta documentación puede resultar incompleta para el uso de AFD enprogramación. La razón es que debe utilizar la versión 2 o posterior de AFD.

8.2 Descripción general del funcionamiento

El programa AFD v 1 funciona bajo DOS. Utiliza la salida estándar parala comunicación de mensajes. La entrada son los argumentos pasados alarrancar el programa.

La sintaxis de llamada es:

AFD "expreg" [ PostFijoObj ] [ PostFijoSubobj ]

donde:

expreg: es la expresión regular. Su sintaxis se explica más adelante.

Documentación de AFD versión 1.x

73

Page 74: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

PostFijoObj: es la cadena postfijo a utilizar para los nombres del objeto AutomFinDet. Es opcional.

PostFijoSubobj: es la cadena postfijo a utilizar para los nombres de las tablas. Si éste parámetro no es dado se toma el valor de PostFijoObj. Este parámetro también es opcional.

Si utiliza el operador > de redireccionamiento de la salida estándarpuede mandar la misma a un archivo de texto, para luego poder consultarlo endetalle y poder usar el fuente C++ generado.

Las tablas que se generan se presentan en un formato similar utilizadopor la bibliografía que trata sobre AFDs. El fuente se da en C++, lasdeclaraciones importantes las puede encontrar en EXPREG.H, y si usa elfuente C++ debe incluir la biblioteca EXPREG.LIB. El contenido de las tablasy la estructura del fuente C++ se explica más adelante.

8.3 Sintaxis de una expresión regular

Una expresión regular reconocido por AFD versión 1 quedaperfectamente definido por las siguientes reglas:

1. La cadena nula (lambda) es una expresión regular.

2. Si a no es un caracter reservado (operador), a es una expresión regular.

3. Si r y s son expresiones regulares, entonces las siguientes sonexpresiones regulares:

a. r s (concatenación).

b. r | s  (uno u otro).

c. r * (0 o más veces r).

d. r + (1 o más veces r).

e. r ? (0 o 1 vez r).

f. ( r ) (los paréntesis se utilizan para asociar).

Los operadores ( ) (paréntesis) tienen la mayor precedencia. Losoperadores *, +, y ? tienen los tres la misma precedencia y son de menorprecedencia que los paréntesis. Por último, el | junto con la concatenación (que

Documentación de AFD versión 1.x

74

Page 75: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

no tiene carácter que lo represente, simplemente se ponen las expresionesregulares una a la par de la otra) son los que tienen menor precedencia.

La gramática usada por AFD v 1 es la siguiente:

ExpReg --> ExpReg ExpReg2ExpReg --> ExpReg '|' ExpReg2ExpReg --> ExpReg2ExpReg2 --> ExpReg3 '?'ExpReg2 --> ExpReg3 '+'ExpReg2 --> ExpReg3 '*'ExpReg2 --> ExpReg3ExpReg3 --> '(' ExpReg ')'ExpReg3 --> Caracter

El analizador lexicográfico utilizado por esta versión es muy simple.Reconoce sólo caracteres y operadores de la siguiente manera:

Los caracteres |, ?, +, *, ( y ) son caracteres reservados. No pueden serusados como simples caracteres en la expresión regular.

Si el caracter actual no es un caracter reservado, entonces se lo tomaliteralmente. Por ejemplo, "a? b" es una expresión regular formado por unespacio y una b precedido opcionalmente por una a.

8.4 Ejemplos del funcionamiento del programa

8.4.1 Ejemplo 1

En este ejemplo se da una expresión regular para reconocer blancos deun archivo de texto. El rango de caracteres considerados blancos se simbolizancon la letra b. A la hora de implementar el fuente, se deberá cambiar éste porsu correspondiente rango.

Expresión regular: b+

Llamada a AFD: AFD "b+" Blanco

Documentación de AFD versión 1.x

75

Page 76: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Salida de AFD:

Expresión regular: b+Caracter o rango: (0, "b")Tabla de transiciones: 0 0 1 1 1 Estado final: 1

En formato fuente:// Fuente del AFD para la expresión regular "b+"// Generado por AFD versión 1 (Ene 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erBlanco[] = "b+";static const char * vcBlanco[] = { "b"};static const unsigned tBlanco[] = { 1, 1};static const unsigned efBlanco[] = { 1, 1};AutomFinDet afdBlanco = { erBlanco, vcBlanco, 1, tBlanco, efBlanco };

8.4.2 Ejemplo 2

La siguiente expresión regular ha sido extraída del libro "Compiladores- principios, técnicas y herramientas" de Aho, Sethi y Ullman, editorialAddison-Wesley Iberoamericana, página 138 de la versión en Castellano,figura 3.39. La expresión regular se la da en 3.39.a, y el autómata finitodeterminístico para esa expresión regular está en 3.39.b; observe que elautómata resultante es exactamente igual al mostrado en la figura (esto es asíporque AFD v 1 utiliza el mismo algoritmo usado para generar el de esafigura).

Expresión regular: (a|b)*abb

Llamada a AFD: AFD "(a|b)*abb"

Salida de AFD:

Expresión regular: (a|b)*abbCaracteres y/o rangos: (0, "a"), (1, "b")Tabla de transiciones: 0 1 0 1 0 1 1 2

Documentación de AFD versión 1.x

76

Page 77: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2 1 3 3 1 0 Estado final: 3

8.4.3 Ejemplo 3

La siguiente expresión regular sirve para reconocer caracteres enformato C++. Con la letra d se simboliza la comilla doble (que no puede serusada en la llamada a AFD por ser caracter reservado de DOS). Con la letra ese simboliza un caracter usado para representar una secuencia de escape. Conel punto se simbolizan todos los demás caracteres.

Expresión regular: '((\(\|'|d|e))|e|.)'

Llamada a AFD: AFD "'((\(\|'|d|e))|e|.)'" Caract

Salida de AFD:

Expresión regular: '((\(\|'|d|e))|e|.)'Caracteres y/o rangos: (0, "\'"), (1, "\\"), (2, "d"), (3, "e"), (4, ".")Tabla de transiciones: 0 1 2 3 4 0 1 - - - - 1 - 2 - 3 3 2 3 3 3 3 - 3 4 - - - - 4 - - - - - Estado final: 4

En formato fuente:// Fuente del AFD para la expresión regular "'((\(\|'|d|e))|e|.)'"// Generado por AFD versión 1 (Ene 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erCaract[] = "'((\(\|'|d|e))|e|.)'";static const char * vcCaract[] = { "\'", "\\", "d", "e", "."};static const unsigned tCaract[] = { 1, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, 2, TNDEF, 3, 3, 3, 3, 3, 3, TNDEF, 4, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF};static const unsigned efCaract[] = { 1, 4};AutomFinDet afdCaract = { erCaract, vcCaract, 5, tCaract, efCaract };

Documentación de AFD versión 1.x

77

Page 78: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

8.4.4 Ejemplo 4

En este ejemplo se da una expresión regular para reconocer rangos decaracteres en el formato de LEX de UNIX. Con la letra d se simboliza lacomilla doble, con la letra e se simbolizan los caracteres utilizados en lassecuencias de escape, y con el punto se simbolizan el resto de los caracteres.

Expresión regular: [((\(\|'|d|e))|e|.)+]

Llamada a AFD: AFD "[((\(\|'|d|e))|e|.)+]" Rango

Salida de AFD:

Expresión regular: [((\(\|'|d|e))|e|.)+]Caracteres y/o rangos: (0, "["), (1, "\\"), (2, "\'"), (3, "d"), (4, "e"),(5, "."), (6, "]")Tabla de transiciones: 0 1 2 3 4 5 6 0 1 - - - - - - 1 - 2 - - 3 3 - 2 - 3 3 3 3 - - 3 - 2 - - 3 3 4 4 - - - - - - - Estado final: 4

En formato fuente:// Fuente del AFD para la expresión regular "[((\(\|'|d|e))|e|.)+]"// Generado por AFD versión 1 (Ene 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erRango[] = "[((\(\|'|d|e))|e|.)+]";static const char * vcRango[] = { "[", "\\", "\'", "d", "e", ".", "]"};static const unsigned tRango[] = { 1, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, 2, TNDEF, TNDEF, 3, 3, TNDEF, TNDEF, 3, 3, 3, 3, TNDEF, TNDEF, TNDEF, 2, TNDEF, TNDEF, 3, 3, 4, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF, TNDEF};static const unsigned efRango[] = { 1, 4};AutomFinDet afdRango = { erRango, vcRango, 7, tRango, efRango };

8.5 Descripción de la salida de AFD

La salida de AFD v 1 consta de dos partes según se especifique o noel/los postfijo(s) en la sintaxis de llamada. La primera parte es un textoexplicativo del AFD generado a partir de la expresión regular en formato

Documentación de AFD versión 1.x

78

Page 79: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

similar al que se usa en la bibliografía. La segunda parte es una versión C++de la primera parte, y comienza con el mensaje "En formato fuente:".

En ambas partes se muestra primero la expresión regular, en la de C++se usa el prefijo er por expresión regular.

Lo que sigue es la enumeración de los caracteres que aparecen en laexpresión regular. El prefijo usado en el fuente C++ es vc. En la primera partese muestran como una enumeración de pares ordenados en donde la primeracomponente es el número asignado al caracter y la segunda componente es elcaracter. El número asignado al caracter sirve para acceder a la columnacorrespondiente de la tabla de transición de estados del autómata.

Luego se presenta la tabla de transición de estados del autómata finitodeterminístico generado. Por filas están los estados, comenzando por el 0. Porcolumnas están los caracteres que participan en la expresión regular. En laparte de formato texto la primera fila de esta tabla muestra los números decaracter, y la primera columna los números de estado. El número que apareceen la primera fila indica el número de caracter que va allí. Por ejemplo, el 0indica que esa columna corresponde al primer caracter aparecido en laexpresión regular, que es el primero que aparece en la enumeración decaracteres "Caracteres y/o rangos:". En el fuente C++ la tabla tiene nombrecon prefijo t, se almacena por filas en un vector de enteros sin signo. Eltamaño de este vector es: cantidad de estados por cantidad de caracteres.

Los estados finales son almacenados en el vector de enteros sin signoque tiene prefijo vf. El primer elemento de éste vector indica el número deestados finales, a continuación están los estados finales.

La implementación del autómata finito determinístico es realizada con laclase AutomFinDet declarada en EXPREG.H. La declaración es como sigue:

class AutomFinDet {public: const char * ExpRegular; const char * * Caracter; unsigned NumCar; const unsigned * Transicion, * EstFinales;};

en donde:

Documentación de AFD versión 1.x

79

Page 80: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ExpRegular: es una cadena de caracteres en formato C++ que define laexpresión regular reconocida por éste autómata.

Caracter: es un vector de cadena de caracteres que contiene los caracteresposibles como caracteres simples o como rangos.

NumCar: es el número de caracteres, que coincide con el tamaño del vectorCaracter y con el número de columnas de la tabla de transición de estados delautómata.

Transicion: es la tabla de transición de estados del autómata finitodeterminístico que reconoce la expresión regular ExpRegular. Para unatransición no definida se debe utilizar TNDEF o el número hexa 0xffff.

EstFinales: es el conjunto de estados finales del AFD. El primer elemento deeste vector indica el número de estados finales, a continuación, en loselementos siguientes, están los estados finales.

El número de estados no se almacena en la estructura debido a que,como la tabla de transición de estados es generada automáticamente, su uso nollevará a transicionar a un estado inexistente. Pero sí se almacena el número decaracteres debido a que los mismos deberán pasar por un filtro de caracterespara poder ser atendidos por el autómata. El filtro funciona como unclasificador de caracteres; la clasificación (agrupación por rangos o grupos decaracteres) sirve para minimizar la cantidad de estados necesarios.

Puede ver ejemplos de definición de objetos AutomFinDet en losejemplos dados previamente.

8.6 Consideraciones finales

Esta versión de AFD ha sido realizada a efectos de poder hacer unaversión más fácil de usar, en el que la entrada pueda ser dada en un formatomás amigable.

Los AFD generados pueden ser utilizados para implementaranalizadores lexicográficos. Los analizadores lexicográficos constan engeneral de varios autómatas finitos determinísticos. Más información sobre laimplementación de analizadores lexicográficos usando la salida de AFD puedeencontrar en la documentación de la biblioteca ExpReg.

Documentación de AFD versión 1.x

80

Page 81: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Esta versión no ha sido realizada para uso de terceros, sólo para uso delautor. Se debe utilizar alguna de las versiones siguientes.

Documentación de AFD versión 1.x

81

Page 82: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 9: Documentación de AFD versión 2.x

El texto de este capítulo es la documentación de AFD v 2.x, y debe sertomado como un libro aparte. No se hacen referencias a otros capítulos de estetrabajo.

La última versión de AFD importante disponible es la 3.x. Sudocumentación la encontrará en el capítulo 10. Si se planea usar AFD entoncesse debe usar esa versión o alguna posterior.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

La documentación que a continuación se presenta, ha sido hecha a partirde la documentación de AFD versión 1.x.

9.1 Introducción

El programa AFD (por autómata finito determinístico) es un generadorde autómata finito determinístico (dado en tablas y fuente C++) a partir de unaexpresión regular fuente.

A diferencia de la versión 1 de AFD, esta versión tiene un analizadorlexicográfico mejorado que permite el uso de caracteres en formato C++,rangos de caracteres que incluyen secuencias de escape, y la posibilidad dedejar espacio entre símbolos léxicos.

Aunque con esta versión se pueden realizar trabajos de programación, seaconseja usar la versión 3, que tiene una gramática de especificación de laentrada más completa y un analizador léxico mejorado, construido a partir deésta versión.

9.2 Descripción general del funcionamiento

El programa AFD v 2 funciona bajo DOS. Utiliza la salida estándar parala comunicación de mensajes. La entrada son los argumentos pasados alarrancar el programa.

La sintaxis de llamada es:

Documentación de AFD versión 2.x

82

Page 83: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

AFD "expreg" [ PostFijoObj ] [ PostFijoSubobj ]

donde:

expreg: es la expresión regular. Su sintaxis se explica más adelante.

PostFijoObj: es la cadena postfijo a utilizar para los nombres del objeto AutomFinDet. Es opcional.

PostFijoSubobj: es la cadena postfijo a utilizar para los nombres de las tablas. Si éste parámetro no es dado se toma el valor de PostFijoObj. Este parámetro también es opcional.

Si utiliza el operador > de redireccionamiento de la salida estándarpuede mandar la misma a un archivo de texto, para luego poder consultarlo endetalle y poder usar el fuente C++ generado.

Las tablas que se generan se presentan en un formato similar utilizadopor la bibliografía que trata sobre AFDs. El fuente se da en C++, lasdeclaraciones importantes las puede encontrar en EXPREG.H, y si usa elfuente C++ debe incluir la biblioteca EXPREG.LIB. El contenido de las tablasy la estructura del fuente C++ se explica más adelante. Puede tambiénconsultar la documentación de la biblioteca ExpReg para más información.

9.3 Sintaxis de una expresión regular

Una expresión regular reconocida por AFD versión 2 queda perfecta-mente definida por las siguientes reglas:

1. La cadena nula (lambda) es una expresión regular.

2. Si a no es un caracter reservado (operador), a es una expresión regular.

3. Si r y s son expresiones regulares, entonces las siguientes sonexpresiones regulares:

a. r s (concatenación).

b. r | s  (uno u otro).

c. r * (0 o más veces r).

Documentación de AFD versión 2.x

83

Page 84: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

d. r + (1 o más veces r).

e. r ? (0 o 1 vez r).

f. ( r ) (los paréntesis se utilizan para asociar).

Los operadores ( ) (paréntesis) tienen la mayor precedencia. Losoperadores *, +, y ? tienen los tres la misma precedencia y son de menorprecedencia que los paréntesis. Por último, el | es el que tiene menorprecedencia.

La gramática usada por AFD v 2 es la siguiente:

ExpReg --> ExpReg ExpReg2ExpReg --> ExpReg '|' ExpReg2ExpReg --> ExpReg2ExpReg2 --> ExpReg3 '?'ExpReg2 --> ExpReg3 '+'ExpReg2 --> ExpReg3 '*'ExpReg2 --> ExpReg3ExpReg3 --> '(' ExpReg ')'ExpReg3 --> Caracter

El analizador lexicográfico de esta versión se realizó con la versión 1 deAFD. Los símbolos léxicos reconocidos son los siguientes: (cuando seaaplicable se usarán expresiones regulares escritas en formato AFD v 2, porcuanto pueden ser tomadas como ejemplo de especificación)

Operadores: | ? + * ( y )

Constante de caracter: ' ( ( \ ( \ | ' | " | [abtnvfr] ) ) | [abtnvfr] | [^\'\\\"\n] ) '

Rango: [ ( ( \ ( \ | ' | " | [abtnvfr] ) ) | [abtnvfr] | [^\'\\\"\n] ) + ]

Identificador: [a-zA-ZáéíóúñÑüÜ] ( [a-zA-ZáéíóúñÑüÜ] | [0-9] ) +

Observar que se usa + porque sino un identificador se confundiría conun caracter que cualquiera que fuera letra o dígito. La longitud resultante de unidentificador es de por lo menos 2 caracteres.

El identificador no se usa en esta versión debido a que la entrada es laestándar. Se usa recién en la versión 3, aunque el código que maneja

Documentación de AFD versión 2.x

84

Page 85: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

identificadores ya está presente en esta versión. Por lo tanto no debeespecificar identificadores en la entrada.

Comentarios: / / [^\n] *

Los comentarios son iguales a los que se usan en C++, comienzan conun doble // y terminan al final de la línea. No forman parte de la expresiónregular y son ignorados por el analizador léxico de AFD v 2.

Debido a que la entrada es una cadena de caracteres que se especificacomo argumento, se tiene solamente una línea, por lo que el comentario debeestar siempre al final de la expresión regular de entrada, dentro de las comillas.

Blancos: [ \n\r\f\t\v] +

Los blancos no forman parte de la expresión regular y son ignorados porel analizador lexicográfico de AFD v 2.

Otros: si un caracter que aparece en la expresión regular no cumple conalguno de los componentes léxicos dados previamente, entonces es tomadocomo un simple caracter por el analizador lexicográfico de AFD v 2. Así ustedverá que en las expresiones regulares dadas, si hay una comilla simple queabre y no hay otra que cierra dos caracteres más adelante, entonces esa comillaes tomada como literal. Para más detalle ver los ejemplos siguientes.

9.4 Ejemplos de funcionamiento del programa

9.4.1 Ejemplo 1

Expresión regular para un identificador reconocido por el analizadorléxico de AFD v 2.

Expresión regular: [a-zA-ZáéíóúñÑüÜ] ( [a-zA-ZáéíóúñÑüÜ] | [0-9] ) +

Llamada a AFD: AFD "[a-zA-ZáéíóúñÑüÜ] ( [a-zA-ZáéíóúñÑüÜ] | [0-9] )+"

Salida de AFD:

Expresión regular: [a-zA-ZáéíóúñÑüÜ] ( [a-zA-ZáéíóúñÑüÜ] | [0-9] ) +Caracteres y/o rangos: (0, "a-zA-ZáéíóúñÑüÜ"), (1, "0-9")Tabla de transiciones:

Documentación de AFD versión 2.x

85

Page 86: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

0 1 0 1 - 1 2 2 2 2 2 Estado final: 2

9.4.2 Ejemplo 2

Expresión regular para un comentario ignorado por el analizador léxicode AFD v 2.

Expresión regular: / / [^\n] *

Llamada a AFD: AFD "/ / [^\n] * // ejemplo de comentario" Coment

Salida de AFD:

Expresión regular: / / [^\n] * // ejemplo de comentarioCaracteres y/o rangos: (0, "/"), (1, "^\n")Tabla de transiciones: 0 1 0 1 - 1 2 - 2 - 2 Estado final: 2

En formato fuente:// Fuente del AFD para la expresión regular "/ / [^\n] * // ejemplo decomentario"// Generado por AFD versión 2 (Ene 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erComent[] = "/ / [^\n] * // ejemplo de comentario";static const char * vcComent[] = { "/", "^\n"};static const unsigned tComent[] = { 1, TNDEF, 2, TNDEF, TNDEF, 2};static const unsigned efComent[] = { 1, 2};AutomFinDet afdComent = { erComent, vcComent, 2, tComent, efComent };

9.4.3 Ejemplo 3

Expresión regular para los blancos ignorados por el analizador léxico deAFD v 2.

Documentación de AFD versión 2.x

86

Page 87: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Expresión regular: [ \n\r\f\t\v] +

Llamada a AFD: AFD "[ \n\r\f\t\v] +"

Salida de AFD:

Expresión regular: [ \n\r\f\t\v] +Caracter o rango: (0, " \n\r\f\t\v")Tabla de transiciones: 0 0 1 1 1 Estado final: 1

9.4.4 Ejemplo 4

Expresión regular para reconocer un caracter de manera similar alanalizador léxico de AFD v 2.

Expresión regular: ' ( ( \ ( \ | ' | " | [abtnvfr] ) ) | [abtnvfr] | [^\'\\\"\n] ) '

Debido a que la comilla doble es un caracter reservado del DOS y que laexpresión regular se la debe especificar entre comillas dobles en la llamada alarchivo, la comilla doble ha sido cambiada por la letra d en la misma.

Llamada a AFD: AFD " ' ( ( \ ( \ | ' | d | [abtnvfr] ) ) | [abtnvfr] | [^\'\\\nd] ) ' "

Salida de AFD:

Expresión regular: ' ( ( \ ( \ | ' | d | [abtnvfr] ) ) | [abtnvfr] |[^\'\\\nd] ) ' Caracteres y/o rangos: (0, "\'"), (1, "\\"), (2, "d"), (3, "abtnvfr"), (4,"^\'\\\nd")Tabla de transiciones: 0 1 2 3 4 0 1 - - - - 1 - 2 - 3 3 2 3 3 3 3 - 3 4 - - - - 4 - - - - - Estado final: 4

9.5 Descripción de la salida de AFD

La salida de AFD v 2 consta de dos partes según se especifique o noel/los postfijo(s) en la sintaxis de llamada. La primera parte es un textoexplicativo del AFD generado a partir de la expresión regular en formato

Documentación de AFD versión 2.x

87

Page 88: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

similar al que se usa en la bibliografía. La segunda parte es una versión C++de la primera parte, y comienza con el mensaje "En formato fuente:".

En ambas partes se muestra primero la expresión regular, en la de C++se usa el prefijo er por expresión regular.

Lo que sigue es la enumeración de los caracteres que aparecen en laexpresión regular. El prefijo usado en el fuente C++ es vc. En la primera partese muestran como una enumeración de pares ordenados en donde la primeracomponente es el número asignado al caracter y la segunda componente es elcaracter. El número asignado al caracter sirve para acceder a la columnacorrespondiente de la tabla de transición de estados del autómata.

Luego se presenta la tabla de transición de estados del autómata finitodeterminístico generado. Por filas están los estados, comenzando por el 0. Porcolumnas están los caracteres que participan en la expresión regular. En laparte de formato texto la primera fila de esta tabla muestra los números decaracter, y la primera columna los números de estado. El número que apareceen la primera fila indica el número de caracter que va allí. Por ejemplo, el 0indica que esa columna corresponde al primer caracter aparecido en laexpresión regular, que es el primero que aparece en la enumeración decaracteres "Caracteres y/o rangos:". En el fuente C++ la tabla tiene nombrecon prefijo t, se almacena por filas en un vector de enteros sin signo. Eltamaño de este vector es: cantidad de estados por cantidad de caracteres.

Los estados finales son almacenados en el vector de enteros sin signoque tiene prefijo vf. El primer elemento de éste vector indica el número deestados finales, a continuación están los estados finales.

La implementación del autómata finito determinístico es realizada con laclase AutomFinDet declarada en EXPREG.H. La declaración es como sigue:

class AutomFinDet {public: const char * ExpRegular; const char * * Caracter; unsigned NumCar; const unsigned * Transicion, * EstFinales;};

en donde:

ExpRegular: es una cadena de caracteres en formato C++ que define laexpresión regular reconocida por éste autómata.

Documentación de AFD versión 2.x

88

Page 89: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Caracter: es un vector de cadena de caracteres que contiene los caracteresposibles como caracteres simples o como rangos.

NumCar: es el número de caracteres, que coincide con el tamaño del vectorCaracter y con el número de columnas de la tabla de transición de estados delautómata.

Transicion: es la tabla de transición de estados del autómata finitodeterminístico que reconoce la expresión regular ExpRegular. Para unatransición no definida se debe utilizar TNDEF o el número hexa 0xffff.

EstFinales: es el conjunto de estados finales del AFD. El primer elemento deeste vector indica el número de estados finales, a continuación, en loselementos siguientes, están los estados finales.

El número de estados no se almacena en la estructura debido a que,como la tabla de transición de estados es generada automáticamente, su uso nollevará a transicionar a un estado inexistente. Pero si se almacena el número decaracteres debido a que los mismos deberán pasar por un filtro de caracterespara poder ser atendidos por el autómata. El filtro funciona como unclasificador de caracteres; la clasificación (agrupación por rangos o grupos decaracteres) sirve para minimizar la cantidad de estados necesarios.

Puede ver ejemplos de definición de objetos AutomFinDet en losejemplos dados previamente.

9.6 Consideraciones finales

Los AFD generados por esta versión pueden ser utilizados paraimplementar analizadores lexicográficos. Los analizadores lexicográficosconstan en general de varios autómatas finitos determinísticos. Másinformación sobre la implementación de analizadores lexicográficos usando lasalida de AFD puede encontrar en la documentación de la biblioteca ExpReg.

Luego de usar esta versión de AFD observará la necesidad de tener unasentencia tipo #define del C++ que permita definir macros, para así reducir elesfuerzo de escribir expresiones regulares y hacerlas más legibles. La versión3 de AFD resuelve este problema, para lo cual se cambió la gramática deexpresiones regulares.

Documentación de AFD versión 2.x

89

Page 90: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Esta versión no ha sido realizada para uso de terceros, sólo para uso delautor. Se debe utilizar la versión 3 o siguiente dado que ofrecen másprestaciones.

Documentación de AFD versión 2.x

90

Page 91: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 10: Documentación de AFD versión 3.x

El texto de este capítulo es la documentación de AFD v 3.x, y debe sertomado como un libro aparte. No se hacen referencias a otros capítulos de estetrabajo.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

La documentación que a continuación se presenta, ha sido hecha a partirde la documentación de AFD versión 2.x.

Esta versión de AFD trabaja conjuntamente con SLR1, el generador deanalizadores sintácticos. Los archivos .CMM generados por AFD son usadospor el analizador lexicográfico generado por SLR1.

10.1 Introducción

El programa AFD (por autómata finito determinístico) es un generadorde autómata finito determinístico (dado en tablas y fuente C++) a partir de unaexpresión regular fuente.

A diferencia de la versión 2 de AFD, esta versión incluye la posibilidadde definir macros para simplificar la escritura de expresiones regulares. Semencionará en adelante como AFD v 3 o AFD v 3.x.

Esta documentación describe a las versiones de DOS y Windows delgenerador. La versión de OS/2 es similar a la de Windows y no es mencionadaen este documento.

10.2 Descripción general del funcionamiento

Una versión del programa AFD v 3 funciona bajo DOS. La expresiónregular se da en un archivo de texto. La salida en fuente C++ del autómatafinito determinístico se guarda en un archivo .CMM que tendrá el mismonombre del archivo de entrada. En la salida estándar se muestra el AFD enformato texto.

La sintaxis de llamada al programa es:

Documentación de AFD versión 3.x

91

Page 92: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

AFD ArchExpReg [ PostFijoObj ] [ PostFijoSubobj ]

Donde:

ArchExpReg: es un archivo de texto con la expresión regular

PostFijoObj: es la cadena postfijo a utilizar para los nombres del objeto AutomFinDet. Es opcional, pero si lo especifica el fuente C++ será guardado en ArchExpReg.CMM.

PostFijoSubobj: es la cadena postfijo a utilizar para los nombres de las tablas. Si éste parámetro no es dado se toma el valor de PostFijoObj. Este parámetro también es opcional.

Si utiliza el operador > de redireccionamiento de la salida estándarpuede mandar la misma a un archivo de texto, para luego poder consultarlo endetalle.

Otra versión de este utilitario funciona bajo Windows como un editormultitexto (un editor que incluye la posibilidad de editar muchos textos a lavez) con alta funcionalidad, en donde se incluye en el menú Archivo delmismo la posibilidad de "Generar autómata" que ejecuta todo el proceso detraducción para el texto cuya ventana es la actual. Como salida del proceso segeneran un archivo .CMM y un archivo .TXT con el mismo nombre que el deentrada. El archivo .TXT contiene la versión en formato texto del autómata yel archivo .CMM contiene la versión C++ del mismo.

Las tablas que se generan se presentan en un formato similar utilizadopor la bibliografía que trata sobre AFDs. El fuente se da en C++, lasdeclaraciones importantes las puede encontrar en EXPREG.H, y si usa elfuente C++ debe incluir la biblioteca EXPREG.LIB. El contenido de las tablasy la estructura del fuente C++ se explica más adelante. Puede tambiénconsultar la documentación de la biblioteca ExpReg para más información.

10.3 Sintaxis de una expresión regular

Una expresión regular reconocida por AFD versión 3 quedaperfectamente definida por las siguientes reglas:

1. La cadena nula (lambda) es una expresión regular.

Documentación de AFD versión 3.x

92

Page 93: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2. Si a no es un caracter reservado (operador), a es una expresión regular.

3. Si r y s son expresiones regulares, entonces las siguientes sonexpresiones regulares:

a. r s (concatenación).

b. r | s  (uno u otro).

c. r * (0 o más veces r).

d. r + (1 o más veces r).

e. r ? (0 o 1 vez r).

f. ( r ) (los paréntesis se utilizan para asociar).

La gramática usada por AFD v 3 es la siguiente:

ExpReg ----> Defs DisyExpReg ----> DisyDefs ------> Defs DefDefs ------> DefDef -------> '#' Ident CteCarDef -------> '#' Ident RangoDisy ------> Disy '|' ConcatDisy ------> ConcatConcat ----> Concat UnarioConcat ----> UnarioUnario ----> Par_Car '?'Unario ----> Par_Car '+'Unario ----> Par_Car '*'Unario ----> Par_CarPar_Car ---> '(' Disy ')'Par_Car ---> CaracterCaracter --> IdentCaracter --> CteCarCaracter --> Rango

De la gramática surge que la precedencia de los operadores es la que semuestra en la tabla siguiente:

Documentación de AFD versión 3.x

93

Page 94: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Orden Operador Observaciones

1la más alta

( ) Use para asociar o romperprecedencias.

2Los 3 lamisma.

?+*

0 o 1 vez. 1 o más veces. 0 o más veces.

4 Concatenación. No tiene caracter quelo represente.

5 | Disyunción.

Fig. 18 Precedencia de operadores en una expresión regular.

10.3.1 Símbolos Terminales que pueden aparecer en una Expresión Regular

El analizador lexicográfico de esta versión se realizó con la versión 2 deAFD. Los símbolos léxicos (o terminales) reconocidos son los siguientes:(cuando sea aplicable se usarán expresiones regulares escritas en formato AFDv 3.x; las mismas pueden ser tomadas como ejemplo de especificación)

Operadores: | ? + * ( y )

Numeral: #

El numeral comienza una definición de macro. Para la definición demacros consulte más adelante, en la sección 10.3.2. Ver ejemplos de su uso enla definición de constante de caracter, rango, etc.

Constante de caracter:

# CarEsp [abtnvfr]# Otros [^\'\\\"\n]' ( \ ( \ | ' | " | CarEsp ) | CarEsp | Otros ) '

Se considera constante de caracter a los que están entre comillas. Hayconstantes de caracter que pueden especificarse sin comillas; ejemplo de elloson los que aparecen en la expresión regular dada que son la comilla simple yla \.

Rango:

# CarEsp [abtnvfr]# Otros [^\'\"\\\n]'[' ( \ ( \ | ' | " | CarEsp ) | CarEsp | Otros ) + ']'

Documentación de AFD versión 3.x

94

Page 95: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Cualquier caracter menos nueva línea ('\n'): .

El punto es un caracter reservado de esta versión de AFD, sirve paraidentificar cualquier caracter menos el '\n' (nueva línea). Expande al rango[^\n]. Este caracter debe ser usado con mucho cuidado puesto que puederesultar en un autómata finito no determinístico (por la intersección de rangosde caracteres). En general es conveniente que aparezca al final de la expresiónregular, y, si hay un caracter después de éste, ese caracter debe haber aparecidoantes.

Identificador:

# Letra [a-zA-Z_á-ÑéüÜ]# Dígito [0-9]Letra (Letra | Dígito)+

Observar que se usa +, y esto es porque sino un identificador seconfundiría con un caracter cualquiera que fuera letra o dígito. La longitudresultante de un identificador es de por lo menos 2 caracteres.

Los identificadores se usan en AFD para identificar macros. Unidentificador debe estar previamente definido antes de su uso. Ejemplos dedefiniciones de macros son los que se dan en esta expresión regular deidentificador, en donde Letra y Dígito son los identificadores que se definenpara reemplazar a los rangos.

Comentarios:

/ / .*

Los comentarios son iguales a los que se usan en C++, comienzan conun doble // y terminan al final de la línea, el efecto es ignorar desde el // enadelante. Los comentarios no forman parte de la expresión regular y sonignorados por el analizador léxico de AFD.

Blancos:

[ \n\r\f\t\v] +

Los blancos no forman parte de la expresión regular y son ignorados porel analizador lexicográfico de AFD.

Otros: si un caracter que aparece en la expresión regular no cumple conalguno de los componentes léxicos dados previamente, entonces es tomado

Documentación de AFD versión 3.x

95

Page 96: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

como un simple caracter por el analizador lexicográfico de AFD. Así ustedverá que en las expresiones regulares dadas, si hay una comilla simple queabre y no hay otra que cierra uno o dos caracteres más adelante, entonces esacomilla es tomada como literal. Para más detalle ver los ejemplos siguientes.

10.3.2 Definición de macros

La definición de macros se realiza usando la siguiente sintaxis:

'#' Ident CteCar

o bien

'#' Ident Rango

donde:

Ident: es el identificador que reemplazará a la constante de caracter o rango de la derecha.

CteCar: es una constante de caracter válida.

Rango: es un rango de caracteres válido.

Durante el análisis léxico, cada vez que aparezca Ident en la expresiónregular fuente, el mismo será reemplazado por la constante de caracter o rango.

No hay problemas si define dos macros en una misma línea, elanalizador sintáctico de AFD se las arregla para entenderle. Por ejemplo, lasiguiente son dos definiciones en una misma línea:

# Letra [a-zA-Z] # digito [0-9]

10.4 Ejemplos de funcionamiento del programa

10.4.1 Ejemplo 1

Expresión regular para un rango reconocido por el analizador léxico deAFD.

Documentación de AFD versión 3.x

96

Page 97: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Expresión regular en archivo rango.er:

// Expresión regular para especificación de rangos# CarEsp [abtnvfr] // las secuencias \x tienen x igual a algún // CarEsp# Otros [^\'\"\\\n] // Otros caracteres // expresión:'[' ( \ ( \ | ' | " | CarEsp ) | CarEsp | Otros ) + ']'

Llamada a AFD para DOS: AFD rango.er Rango Rng

Salida de AFD (en salida estándar del DOS o archivo .TXT si bajo Windows):

Expresión regular: // Expresión regular para especificación de rangos# CarEsp [abtnvfr] // las secuencias \x tienen x igual a algún CarEsp// expresión:'[' ( \ ( \ | ' | " | CarEsp ) | CarEsp | [^\'\"\\\n] ) + ']'

Caracteres y/o rangos: (0, "abtnvfr"), (1, "["), (2, "\\"), (3, "\'"), (4,"\""), (5, "^\'\"\\\n"), (6, "]")Tabla de transiciones: 0 1 2 3 4 5 6 0 - 1 - - - - - 1 2 - 3 - - 2 - 2 2 - 3 - - 2 4 3 2 - 2 2 2 - - 4 - - - - - - - Estado final: 4

10.4.2 Ejemplo 2

Expresión regular para identificadores válidos del C++.

Expresión regular en archivo identcmm.er:

# letra [a-zA-Z_] # digito [0-9]letra ( letra | digito ) *

Llamada a AFD para DOS: AFD identcmm.er IdentCMM

Salida de AFD (en salida estándar si bajo DOS o archivo .TXT si bajoWindows):

Expresión regular: # letra [a-zA-Z_] # digito [0-9]letra ( letra | digito ) *Caracteres y/o rangos: (0, "a-zA-Z_"), (1, "0-9")Tabla de transiciones: 0 1 0 1 - 1 1 1 Estado final: 1

Salida de AFD en archivo .CMM:

// AFD generado por la versión 3.4 de ExpReg::Reasignar (Nov 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

Documentación de AFD versión 3.x

97

Page 98: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erIdentCMM[] = "# letra [a-zA-Z_] # digito[0-9]\r\nletra ( letra | digito ) *\r\n\r\n";static const char * vcIdentCMM[] = { "a-zA-Z_", "0-9"};static const Ent16ns tIdentCMM[] = { 1, TNDEF, 1, 1};static const Ent16ns efIdentCMM[] = { 1, 1};AutomFinDet afdIdentCMM = { erIdentCMM, vcIdentCMM, 2, tIdentCMM,efIdentCMM };

10.5 Descripción de la salida de AFD

La salida de AFD v 3 consta de dos partes.

Una parte es un texto explicativo del AFD generado a partir de laexpresión regular, que aparece en formato similar al que se usa en labibliografía. Se mencionará como primera parte. Se da en el archivo .TXT sitrabaja con la versión de Windows o en la salida estándar si trabaja bajo DOS.

La que se muestra en formato C++ en el archivo .CMM es laimplementación del AFD para su uso en un programa. Se mencionará enadelante como la segunda parte o fuente C++.

En ambas partes se muestra primero la expresión regular, en la de C++se usa el prefijo er por expresión regular.

Lo que sigue es la enumeración de los caracteres que aparecen en laexpresión regular. El prefijo usado en el fuente C++ es vc. En la primera partese muestran como una enumeración de pares ordenados en donde la primeracomponente es el número asignado al caracter y la segunda componente es elcaracter. El número asignado al caracter sirve para acceder a la columnacorrespondiente de la tabla de transición de estados del autómata.

Luego se presenta la tabla de transición de estados del autómata finitodeterminístico generado. Por filas están los estados, comenzando por el 0. Porcolumnas están los caracteres que participan en la expresión regular. En laparte de formato texto la primera fila de esta tabla muestra los números decaracter, y la primera columna los números de estado. El número que apareceen la primera fila indica el número de caracter que va allí. Por ejemplo, el 0

Documentación de AFD versión 3.x

98

Page 99: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

indica que esa columna corresponde al primer caracter aparecido en laexpresión regular, que es el primero que aparece en la enumeración decaracteres "Caracteres y/o rangos:". En el fuente C++ la tabla tiene nombrecon prefijo t, se almacena por filas en un vector de enteros sin signo. Eltamaño de este vector es: cantidad de estados por cantidad de caracteres.

Los estados finales son almacenados en el vector de enteros sin signoque tiene prefijo vf. El primer elemento de éste vector indica el número deestados finales, a continuación están los estados finales. En la primera parte semuestran a continuación de la frase "Estado(s) final(es): ".

La implementación del autómata finito determinístico es realizada con laclase AutomFinDet declarada en EXPREG.H. La declaración es como sigue:

class AutomFinDet {public: const char * ExpRegular; const char * * Caracter; Ent16ns NumCar; const Ent16ns * Transicion, * EstFinales;};

en donde:

ExpRegular: es una cadena de caracteres en formato C++ que define laexpresión regular reconocida por éste autómata.

Caracter: es un vector de cadena de caracteres que contiene los caracteresposibles como caracteres simples o como rangos.

NumCar: es el número de caracteres, que coincide con el tamaño del vectorCaracter y con el número de columnas de la tabla de transición de estados delautómata.

Transicion: es la tabla de transición de estados del autómata finitodeterminístico que reconoce la expresión regular ExpRegular. Para unatransición no definida se debe utilizar TNDEF o el número hexa 0xffff.

EstFinales: es el conjunto de estados finales del AFD. El primer elemento deeste vector indica el número de estados finales, a continuación, en loselementos siguientes, están los estados finales.

El número de estados no se almacena en la estructura debido a que,como la tabla de transición de estados es generada automáticamente, su uso nollevará a transicionar a un estado inexistente. Pero si se almacena el número de

Documentación de AFD versión 3.x

99

Page 100: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

caracteres debido a que los mismos deberán pasar por un filtro de caracterespara poder ser atendidos por el autómata. El filtro funciona como unclasificador de caracteres; la clasificación (agrupación por rangos o grupos decaracteres) sirve para minimizar la cantidad de estados necesarios.

El tipo Ent16ns es un typedef definido en TIPOS.H para obtener laportabilidad del código escrito usando compiladores de 16 bits a compiladoresde 32 bits. La definición se hizo de la siguiente manera:

typedef unsigned short int Ent16ns ;

El tipo unsigned short int tiene un tamaño de 2 bytes (16 bits) en todas lasimplementaciones del C++ de la empresa Borland (los usados para eldesarrollo de AFD). Si usted proyecta usar un compilador que no es deBorland, revise la implementación de ese tipo de dato para verificar que sea de2 bytes. Si es de más de 2 bytes ocupará más espacio del necesario; si esmenor, busque un tipo entero no signado que ocupe 2 bytes y cambie eltypedef en TIPOS.H. Al cambiar de compilador no olvide recompilar labiblioteca ExpReg (expreg.lib).

Puede ver ejemplos de definición de objetos AutomFinDet en el ejemplo2 dado previamente, en la sección archivo .CMM generado.

10.6 Consideraciones finales

Los AFD generados por esta versión pueden ser utilizados paraimplementar analizadores lexicográficos. Los analizadores lexicográficosconstan en general de varios autómatas finitos determinísticos. Másinformación sobre la implementación de analizadores lexicográficos usando lasalida de AFD puede encontrar en la documentación de la biblioteca ExpReg.

Esta versión de AFD puede ser usada junto con el generador deanalizadores sintácticos SLR1 para el desarrollo de herramientas de traducción(compiladores, intérpretes, traductor de un idioma a otro, etc.). La versión 2 deSLR1 genera automáticamente un analizador lexicográfico, dejándole comotrabajo al usuario el de procesar todos los archivos .ER con las expresionesregulares. Consulte la documentación de SLR1 v 2 o posterior para másdetalle.

Documentación de AFD versión 3.x

100

Page 101: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 11: Documentación de SLR1 versión 1.x

El texto de este capítulo es la documentación de SLR1 v 1.x, y debe sertomado como un libro aparte. No se hacen referencias a otros capítulos de estetrabajo.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

Aunque esta versión del generador está disponible para el uso deterceros, el autor aconseja usar la versión 2.x o posterior (ver el capítulo 12).

11.1 Introducción

SLR1 es un programa para generar tablas de análisis sintáctico LR(1)simples a partir de la especificación de la gramática del lenguaje. Las tablasgeneradas por este programa serán usadas pasa la realización del análisissintáctico de oraciones de ese lenguaje.

11.2 Descripción general del funcionamiento

SLR1 es un programa que funciona bajo el sistema operativo DOS. Nose prevee el desarrollo de una versión con la funcionalidad de esta versión paraotro sistema operativo. Pero si se prevee una versión nueva de SLR1 paravarios sistemas operativos, cuya sintaxis de entrada es distinta a ésta, y lafuncionalidad altamente superior.

La entrada de SLR1 v 1 es un archivo de texto plano con la gramáticaque se desea tratar.

La salida del programa son 2 archivos: un archivo .CMM con las tablasque serán utilizadas para el análisis sintáctico en formato de fuente de C++ yun archivo .TXT con las tablas de análisis sintáctico en formato similar al quese presenta en la bibliografía, con los estados y con los códigos asignados a lossímbolos terminales y no terminales.

El archivo .CMM es el que luego se utiliza para realizar el análisissintáctico, incluyéndolo en la compilación junto con otros módulos fuentes delproyecto en desarrollo.

Documentación de SLR1 versión 1.x

101

Page 102: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Sintaxis de la especificación de una gramática

La metagramática que a continuación se presenta, describe la sintaxisque se debe usar para especificar una gramática que se usará como entrada deSLR1.

Gramática ---> ReglasReglas ---> Reglas ReglaReglas ---> ReglaRegla ---> IdentIzq Flecha ListaSímbolos FinLíneaListaSímbolos ---> ListaSímbolos SímboloListaSímbolos --->

Las reglas se numeran de arriba a abajo de 1 a N si hay N reglas.

Una gramática está formada por un conjunto de reglas (regla 1) no vacío(regla 3), es decir, al menos debe haber una regla.

Una regla está formada por un identificador, una flecha y una lista desímbolos (regla 4), y cada regla ocupará una y sólo una línea (regla 4). La listade símbolos que aparece entre la flecha y el fin de línea puede ser vacía (regla6).

Los identificadores que no aparecen a la izquierda de alguna regla en lagramática previamente dada son símbolos terminales, y serán explicados acontinuación, como parte de la lexicografía a utilizar para la especificación dela gramática. La sintaxis que se usará es la de expresiones regulares.

Identificador: [_a-zA-Zá-Ñü-Ü] [_a-zA-Zá-Ñü-Ü0-9] *

Flecha: ( - ) + >

Uno o más guiones o signos menos seguido de un signo mayor que.

Símbolo: [^ \t] +

Símbolo es una concatenación no vacía de caracteres distintos al espacio y altabulado.

Documentación de SLR1 versión 1.x

102

Page 103: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11.3 Ejemplos de gramáticas

11.3.1 Ejemplo 1

La gramática dada previamente, usada para explicar la estructura de unagramática (i.e. metagramática), es un ejemplo de gramática que se puede usarcomo entrada para SLR1.

La regla 6 de esta gramática es una regla que deriva en lambda, es decir,ListaSímbolos es anulable.

Archivo .CMM:

unsigned noterm_long_pd[] = { 0x404, 0x101, 0x202, 0x201, 0x304, 0x402, 0x400};

unsigned accion[] = { 0, 1, 0, 0, 0, 0, 0, 5, 0, 0, 16384, 0, 0, 0, 0, 32769, 1, 0, 0, 0, 32771, 32771, 0, 0, 0, 0, 0, 0, 32774, 32774, 32770, 32770, 0, 0, 0, 0, 0, 0, 8, 9, 32772, 32772, 0, 0, 0, 0, 0, 0, 32773, 32773};

unsigned ir_a[] = { 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

Archivo .TXT:

N = { (Gramática, 1), (Reglas, 2), (Regla, 3), (ListaSímbolos, 4) }T = { (IdentIzq, 1), (Flecha, 2), (FinLínea, 3), (Símbolo, 4) }(Gramática, 1) es el símbolo inicial.Seglas:Gramática' ---> Gramática Gramática ---> Reglas Reglas ---> Reglas Regla Reglas ---> Regla Regla ---> IdentIzq Flecha ListaSímbolos FinLínea ListaSímbolos ---> ListaSímbolos Símbolo ListaSímbolos --->

Documentación de SLR1 versión 1.x

103

Page 104: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Estado 0:Gramática' ---> . Gramática Gramática ---> . Reglas Reglas ---> . Reglas Regla Reglas ---> . Regla Regla ---> . IdentIzq Flecha ListaSímbolos FinLínea

Estado 1:Segla ---> IdentIzq . Flecha ListaSímbolos FinLínea

Estado 2:Gramática' ---> Gramática .

Estado 3:Gramática ---> Reglas . Reglas ---> Reglas . Regla Regla ---> . IdentIzq Flecha ListaSímbolos FinLínea

Estado 4:Reglas ---> Regla .

Estado 5:Regla ---> IdentIzq Flecha . ListaSímbolos FinLínea ListaSímbolos ---> . ListaSímbolos Símbolo ListaSímbolos ---> .

Estado 6:Seglas ---> Reglas Regla .

Estado 7:Segla ---> IdentIzq Flecha ListaSímbolos . FinLínea ListaSímbolos ---> ListaSímbolos . Símbolo

Estado 8:Segla ---> IdentIzq Flecha ListaSímbolos FinLínea .

Estado 9:ListaSímbolos ---> ListaSímbolos Símbolo .

Funciones acción(estado, simbolo) e ir_a (estado, símbolo):

IdentIzq Flecha FinLínea Símbolo FA Gramática Reglas Regla ListaSímbolos 0 d1 . . . . 2 3 4 . 1 . d5 . . . . . . . 2 . . . . a . . . . 3 d1 . . . r1 . . 6 . 4 r3 . . . r3 . . . . 5 . . r6 r6 . . . . 7 6 r2 . . . r2 . . . . 7 . . d8 d9 . . . . . 8 r4 . . . r4 . . . . 9 . . r5 r5 . . . . .

11.3.2 Ejemplo 2

La gramática que se da a continuación especifica la sintaxis de unaexpresión aritmética.

E --> E '+' TE --> TT --> T '*' FT --> FF --> '(' E ')'

Documentación de SLR1 versión 1.x

104

Page 105: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

F --> id

Archivo .CMM:

unsigned noterm_long_pd[] = { 0x305, 0x103, 0x101, 0x203, 0x201, 0x303, 0x301};

unsigned accion[] = { 0, 0, 0, 1, 0, 2, 0, 0, 0, 1, 0, 2, 32774, 32774, 32774, 0, 32774, 0, 16384, 7, 0, 0, 0, 0, 32770, 32770, 8, 0, 32770, 0, 32772, 32772, 32772, 0, 32772, 0, 0, 7, 0, 0, 9, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 1, 0, 2, 32773, 32773, 32773, 0, 32773, 0, 32769, 32769, 8, 0, 32769, 0, 32771, 32771, 32771, 0, 32771, 0};

unsigned ir_a[] = { 3, 4, 5, 6, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0};

Archivo .TXT:

N = { (E, 1), (T, 2), (F, 3) }T = { ('+', 1), ('*', 2), ('(', 3), (')', 4), (id, 5) }(E, 1) es el símbolo inicial.Reglas:E' ---> E E ---> E '+' T E ---> T T ---> T '*' F T ---> F F ---> '(' E ')' F ---> id

Estado 0:E' ---> . E E ---> . E '+' T E ---> . T T ---> . T '*' F T ---> . F F ---> . '(' E ')' F ---> . id

Documentación de SLR1 versión 1.x

105

Page 106: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Estado 1:F ---> '(' . E ')' E ---> . E '+' T E ---> . T T ---> . T '*' F T ---> . F F ---> . '(' E ')' F ---> . id

Estado 2:F ---> id .

Estado 3:E' ---> E . E ---> E . '+' T

Estado 4:E ---> T . T ---> T . '*' F

Estado 5:T ---> F .

Estado 6:F ---> '(' E . ')' E ---> E . '+' T

Estado 7:E ---> E '+' . T T ---> . T '*' F T ---> . F F ---> . '(' E ')' F ---> . id

Estado 8:T ---> T '*' . F F ---> . '(' E ')' F ---> . id

Estado 9:F ---> '(' E ')' .

Estado 10:E ---> E '+' T . T ---> T . '*' F

Estado 11:T ---> T '*' F .

Funciones acción(estado, simbolo) e ir_a(estado, símbolo):

'+' '*' '(' ')' id FA E T F 0 . . d1 . d2 . 3 4 5 1 . . d1 . d2 . 6 4 5 2 r6 r6 . r6 . r6 . . . 3 d7 . . . . a . . . 4 r2 d8 . r2 . r2 . . . 5 r4 r4 . r4 . r4 . . . 6 d7 . . d9 . . . . . 7 . . d1 . d2 . . 10 5 8 . . d1 . d2 . . . 11 9 r5 r5 . r5 . r5 . . . 10 r1 d8 . r1 . r1 . . . 11 r3 r3 . r3 . r3 . . .

Documentación de SLR1 versión 1.x

106

Page 107: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11.3.3 Ejemplo 3

La gramática siguiente reconoce expresiones aritméticas similares a ladada en el ejemplo 2, pero tiene el problema de que es ambigua.

La ambigüedad de una gramática hace que la misma no sea LR(1)simple, por lo tanto no es directamente tratable con SLR1 ni con cualquierprograma generador que trabaje con la técnica LR. El programa SLR1, al igualque otros como el YACC, permiten resolver la ambigüedad de la gramáticapermitiendo al usuario decidir qué es lo que el analizador sintáctico deberíahacer en el momento de presentarse un conflicto. A tal efecto, el usuario deesos programas debe tener un conocimiento avanzado del algoritmo de análisisLR, lo que puede consultar en la bibliografía dada al final de este documento.

E -> E '+' EE -> E '*' EE -> id

Archivo .CMM:

unsigned noterm_long_pd[] = { 0x103, 0x103, 0x103, 0x101};

unsigned accion[] = { 0, 0, 0, 1, 32771, 32771, 32771, 0, 16384, 3, 4, 0, 0, 0, 0, 1, 0, 0, 0, 1, 32769, 32769, 4, 0, 32770, 32770, 32770, 0};

unsigned ir_a[] = { 2, 0, 0, 5, 6, 0, 0};

Archivo .TXT:

N = { (E, 1) }T = { ('+', 1), ('*', 2), (id, 3) }(E, 1) es el símbolo inicial.Reglas:E' ---> E

Documentación de SLR1 versión 1.x

107

Page 108: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

E ---> E '+' E E ---> E '*' E E ---> id

Estado 0:E' ---> . E E ---> . E '+' E E ---> . E '*' E E ---> . id

Estado 1:E ---> id .

Estado 2:E' ---> E . E ---> E . '+' E E ---> E . '*' E

Estado 3:E ---> E '+' . E E ---> . E '*' E E ---> . id E ---> . E '+' E

Estado 4:E ---> E '*' . E E ---> . E '+' E E ---> . E '*' E E ---> . id

Estado 5:E ---> E '+' E . E ---> E . '*' E E ---> E . '+' E

Estado 6:E ---> E '*' E . E ---> E . '+' E E ---> E . '*' E

Funciones acción(estado, simbolo) e ir_a(estado, símbolo):

'+' '*' id FA E 0 . . d1 . 2 1 r3 r3 . r3 . 2 d3 d4 . a . 3 . . d1 . 5 4 . . d1 . 6 5 r1 d4 . r1 . 6 r2 r2 . r2 .

En este ejemplo, las reglas 1 y 2 plantean un problema de ambigüedad(dos o más posibles análisis sintáctico para una misma oración). El programaSLR1 emitirá 4 mensajes de errores y dos posibles alternativas de soluciónpasa cada situación de conflicto, a saber:

Mensaje 1: "En el estado 5 se debe elegir entre desplazar '+' y pasar a 3 yreducir por regla 1 con ese símbolo."

Documentación de SLR1 versión 1.x

108

Page 109: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El mensaje significa que en la tabla, en la fila correspondiente al estado5 (la que tiene el 5 a la izquierda), en la columna correspondiente al '+', sedebe elegir entre colocar d5 o r1. De las dos opciones se eligió la segunda.

Mensaje 2: "En el estado 5 se debe elegir entre desplazar '*' y pasar a 4 yreducir por regla 1 con ese símbolo."

Las alternativas aquí son colocar d4 o r1 en la fila del estado 5, columnadel símbolo '*'. En este caso se eligió desplazar y pasar al estado 4.

Mensaje 3: "En el estado 6 se debe elegir entre desplazar '+' y pasar a 3 yreducir por regla 2 con ese símbolo."

Las opciones son d3 o r2 con '+' en el estado 6. Se eligió reducir porregla 2.

Mensaje 4: "En el estado 6 se debe elegir entre desplazar '*' y pasar a 4 yreducir por regla 2 con ese símbolo."

Las opciones son d4 o r2 con '*' en el estado 6. Se eligió reducir porregla 2.

11.4 Consideraciones a tener el cuenta para el uso de gramáticasambiguas

El uso de gramáticas ambiguas puede dar como resultado tablas máspequeñas, lo que reduce el espacio de memoria necesario para almacenarlas.Pero el nivel de conocimiento necesario para poder resolver los conflictos esdemasiado elevado.

En la automatización de la generación de programas el objetivo es queel usuario (en este caso el programador) no pierda tiempo aprendiendo cosasque no hacen falta, ya que el generador hace ese trabajo y lo hace bien. El usode gramáticas ambiguas imposibilita cumplir ese objetivo, y por lo general, elresultado no es "mucho mejor" que el de usar gramáticas no ambiguas. Para elejemplo dado, la diferencia es infinitesimal, dada la disponibilidad de memoriaen las computadoras actuales y la velocidad de procesamiento de las mismas.

Hay gramáticas que no son ambiguas, pero presenta conflictos pasa latécnica LR(1) simple debido a la forma de trabajo del algoritmo (es decir, esambigua para la técnica SLR(1) ). La gramática para la sentenciasi...entonces...sino... es no ambigua pero presenta un conflicto de

Documentación de SLR1 versión 1.x

109

Page 110: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

desplazamiento-reducción con el símbolo sino y la regla SentSi --> si Exprentonces Sent. (Nota: en este caso se elige desplazar sino). El conflicto dedesplazamiento-reducción que provoca esta gramática hace que SLR1 genereun analizador sintáctico para esa gramática que pueda generar 2 posiblesárboles de análisis sintáctico para una oración que tenga la parte sino..., y espor eso que decimos que es ambigua para la técnica LR(1) simple.

11.5 Descripción de la estructura de las tablas generadas

Las tablas del analizador sintáctico están implementadas en vectores enel archivo fuente .CMM generado.

La documentación que aquí se incluye es a los efectos de que cualquierprogramador pueda hacer las modificaciones necesarias al archivoANALIZAR.CMM donde se encuentra la función Analizar que realiza elanálisis sintáctico. O bien, para que escriba una función nueva de análisissintáctico, si la dada no satisface sus necesidades. (El archivoANALIZAR.CMM así como los archivos ELEM.H y SLR1.H se incluyen alfinal de este documento, junto con los módulos fuentes del ejemplo 4.)

Los vectores que se generan son 3.

11.5.1 unsigned noterm_long_pd[ ];

Este vector de enteros sin signo de 2 bytes (para compiladores C++ de16 bits), contiene:

En el elemento 0, el byte alto es el número de símbolos no terminales yel byte bajo es el número de terminales. Por ejemplo, en el ejemplo 2noterm_long_pd[0] tiene el número 0x0305, que significa que hay 3 noterminales y 5 terminales.

Estos números son usados para calcular el número de columnas de lastablas accion e ir_a (ver las tablas en archivos .TXT, las columnas se indexanpor símbolos terminal/no terminal).

En los elementos 1 en adelante, el byte alto es el código del no terminalque se halla a la izquierda de la regla cuyo número es el índice del elementoactual, y el byte bajo de éste elemento especifica el número de símbolos quehay a la derecha de la flecha (las reglas se numeran de 1 en adelante, en elorden en que aparecen en el archivo fuente). Por ejemplo, en el ejemplo 1, el

Documentación de SLR1 versión 1.x

110

Page 111: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

elemento noterm_long_pd[6] que corresponde a la regla 6 "ListaSímbolos ---> " tiene el número 0x0400, que significa que el no terminal de la izquierda enla regla 6 es el que tiene el código 4 (ListaSímbolos, ver conjunto N delarchivo .TXT de salida), y que el número de elementos a retirar de la pila delanalizador al hacer una reducción por regla 6 es 0 (ver que la regla deriva enlambda, esto es, ListaSímbolos es anulable).

En el momento de ejecutar una reducción, se necesita la informacióncontenida en estos elementos, para desapilar la cantidad adecuada deelementos y poder indexar la columna de la tabla ir_a que requiere el códigodel no terminal de la izquierda.

11.5.2 unsigned accion[ ];

Este vector de enteros sin signo de 2 bytes (para compiladores C++ de16 bits), es la transcripción de la tabla acción que se muestra en el archivo.TXT en formato más legible. La tabla acción mostrada en ese archivocomienza en el primer terminal y termina en el símbolo FA, que también esconsiderado terminal. Por filas se indexa por estado, y por columna se indexapor símbolo terminal.

En este vector los elementos se codifican de la siguiente manera, lo quese muestra en formato C++:

class Accion { // estructura de una acciónpublic: unsigned n : 14; unsigned cod : 2;};

La clase Accion es una estructura de 16 bits, en los cuales los 14 bitsmenos significativos son los números que aparecen luego de la letra d o r en latabla accion, y se acceden usando el campo n de esta estructura. El campo codcontiene el código de acción a ejecutar: 00 para desplazar, 01 para aceptar y 10para reducir. El 11 no se utiliza. En el vector observará que: el elemento quetiene el 16384 es el que corresponde a aceptar, todos los elementos menoresque ese número son los de desplazamiento (aparecen con la letra d en la tablaen el archivo .TXT) y todos los mayores que ese número son los de reducción(aparecen con la letra r en la tabla en el archivo .TXT).

Documentación de SLR1 versión 1.x

111

Page 112: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11.5.3 unsigned ir_a[ ];

Este vector implementa la tabla ir_a, que en el archivo .TXT se muestraa la par de la tabla accion a continuación del símbolo FA. Las columnas deesta tabla se indexan por símbolos no terminales y las filas por estados.

La tabla se almacena en el vector por filas (fila mayor). Cada elementocontiene directamente el número que se muestra en la tabla ir_a del archivo.TXT.

11.6 Descripción de la función Analizar

La función Analizar que se encuentra en el archivo ANALIZAR.CMM ycuyo prototipo se da en el archivo SLR1.H a efectos de ser incluidos en elarchivo que realizará el análisis sintáctico.

El prototipo de la función es el siguiente:

int Analizar( unsigned * ntlpd, unsigned * accion, unsigned * ir_a, unsigned char ( * analex)(), void (* accion_sem)( unsigned NumRegla ), void (* fver)( char * mensaje ) );

La función recibe 6 parámetros. Los tres primeros son las tres tablas quedevuelve el programa SLR1 v 1. ntlpd es noterm_long_pd, accion es accion

del .CMM e ir_a es ir_a, que ya fueron documentados. Los demás parámetrosse documentan a continuación.

1. analex

El parámetro analex es una función cuyo prototipo es similar a:

unsigned char AnalizadorLexico();

es decir, una función que no recibe parámetros y que devuelve un unsigned

char (entre 0 y 255). Esta función debe ser dada ya que es la que realiza elanálisis léxico. Los dispositivos de E/S para obtener el fuente a esta funcióndeben ser elegidos por el usuario de SLR1.

Los códigos que debe devolver la función son:

a. 0 para fin de archivo fuente.

Documentación de SLR1 versión 1.x

112

Page 113: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

b. 1 a N donde N es el número de símbolos terminales de la gramática.Los códigos a devolver deben coincidir con los dados en el conjuntoT que se muestra en el archivo .TXT de salida, según corresponda.

c. Un número mayor que N si el símbolo que aparece a continuación esun símbolo desconocido.

2. accion_sem

El parámetro accion_sem es la función que realizará las accionessemánticas para cada reducción de regla. El prototipo de la función es similar ala siguiente:

void AccionSemantica( unsigned NumRegla );

En NumRegla viene el número de regla que se está por reducir. La función nodevuelve nada. La intercomunicación entre esta función y la que realiza elanálisis lexicográfico puede ser realizada usando variables globales, pero lamejor técnica es la del uso de la pila del analizador.

En algunos casos es necesario modificar el prototipo de esta función aefectos de poder modificar los elementos de la pila del analizador. En estecaso, el prototipo podría ser como sigue:

void AccionSemantica( unsigned NumRegla, ElemPila * Pila, unsigned PuntPila );

Debe modificar el prototipo de Analizar en SLR1.H y en ANALIZAR.CMM (agregar los dos parámetros a la declaración del parámetroaccion_sem). También debe pasar los parámetros nuevos en la llamada a esafunción, dentro del código de Analizar; en el código figura:

if (accion_sem != 0) (*accion_sem)(a.n);

y luego de modificarla debe figurar:

if (accion_sem != 0) (*accion_sem)(a.n, pila, pp);

en donde pila y pp son variables internas de la función Analizar.

Documentación de SLR1 versión 1.x

113

Page 114: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Al ser llamada la función accion_sem, los elementos de la regla figuranen la pila de la siguiente manera: sea la regla que se está por reducir (cuyonúmero viene en el parámetro NumRegla) la siguiente:

A --> B C D

entonces:

A y B se encuentran en pila[pp + 1].

C se encuentra en pila[pp + 2].

D se encuentra en pila[pp + 3].

y así sucesivamente, para reglas de mayor número de símbolos. Observar queel no terminal de la izquierda de la regla y el primer símbolo de la derechacomparten la misma posición de la pila.

El parámetro accion_sem puede ser ignorado en caso de no sernecesario.

3. fver

El parámetro fver es una función que sirve para depurar analizadoressintácticos generados por medio de SLR1. Permite ver la pila y muestra lasacciones que se van realizando en cada paso. El prototipo de la función essimilar a la siguiente:

void FuncionVer( char * ExplicacionDelPaso );

ExplicacionDelPaso es una cadena de caracteres en donde se explica la acciónejecutada o se muestra el estado de la pila del analizador sintáctico. Dentro dela FuncionVer usted puede incluir código que imprima esa cadena en pantalla,para ir viendo el progreso del análisis sintáctico.

El parámetro fver puede ser ignorado.

La función Analizar devuelve 0 si hay problemas en las tablas o error desintaxis, y 1 si la oración analizada es sintácticamente correcta.

Documentación de SLR1 versión 1.x

114

Page 115: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La función no modifica las tablas, y puede ser llamada las cantidades deveces que desee en el programa que se la incluya, inclusive puede usar variosjuegos de tablas, las que podrían ser leídos desde un archivo binario.

11.7 La pila del analizador sintáctico SLR1

La pila del analizador sintáctico SLR1 está implementada en un vector,y se declara dentro de la función Analizar. La estructura de los elementos deesta pila es por defecto la que define la clase ElemPila declarada en ELEM.H,declaración que se transcribe:

class ElemPila {public: Simbolo s; unsigned e; ElemPila( ) { s.cod = s.noterminal = 0; e = 0; }};

El campo s sirve para identificar el símbolo que se encuentra en eseelemento de la pila. El campo e sirve para identificar el estado correspondientea esa posición; bajo ningún concepto debe modificar este campo. Esta claseusa la clase Simbolo que también se declara en ELEM.H.

No es aconsejable eliminar esos campos de la clase ElemPila, así comotampoco la implementación de la misma (la pila está implementada comovector). Pero si es necesario, puede agregar elementos en la declaración de laclase según necesite para las acciones semánticas. La siguiente es unadeclaración ejemplo:

class ElemPila { // estructura de un elemento de la pila del analizadorpublic: Simbolo s; unsigned e;

char Cadena[30]; // a efectos de guardar la cadena de texto que // devuelve el analizador lexicográfico

ElemPila( ) { s.cod = s.noterminal = 0; e = 0; }};

El acceso al campo Cadena en la función de acciones semánticas sería:pila[pp + X].Cadena, donde X es el número del símbolo de la izquierda de laregla que se desea acceder.

Documentación de SLR1 versión 1.x

115

Page 116: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11.8 Uso del programa SLR1 v 1

Para iniciar SLR1 debe ejecutar el programa SLR1.EXE, desdecualquier directorio usando sintaxis de posicionamiento de archivo absoluta obien desde el directorio donde éste se encuentra.

El menú que se muestra luego de cargar el programa tiene dos opciones:cargar gramática y salir.

Al elegir cargar gramática, en una ventana de diálogo se pide el nombredel archivo donde se encuentra la gramática. Debe ingresar cualquier nombrede archivo válido para el DOS, y, si no incluye extensión, se asumirá que laextensión es .GLC (por gramática libre de contexto). Los archivos de salida.CMM y .TXT serán generados en el mismo directorio donde se encuentra elarchivo de entrada, para facilitar su localización.

En el menú que se muestra luego de aceptar el nombre del archivo deentrada, la opción proceder realiza la traducción, la opción volver atrás cancelala operación sin hacer nada, y las demás opciones son banderas que controlanla salida del programa.

La gramática, los estados, las tablas y los códigos de los símbolos semuestran en el archivo .TXT, y el código fuente en el archivo .CMM. Si porejemplo desactiva la impresión del código fuente, no se generará el archivo.CMM. Para que no se genere el archivo .TXT debe desactivar las opciones detoda la información que se imprime en ese archivo (debe desactivar todas lasopciones menos la de imprimir fuente).

En el caso de que se presente un conflicto, la información se presenta enuna ventana de diálogo, y el usuario deberá elegir entre dos opciones pararesolver el conflicto. Para la resolución de conflictos debe consultar labibliografía.

Al finalizar la generación de las tablas, el programa vuelve al menúprincipal a efectos de proceder con otro archivo, si es que así lo desea.

11.9 Ejemplo 4: Desarrollo de un proyecto.

El proyecto a desarrollar es un sistema para la verificación de la validezde un esquema deductivo del cálculo proposicional.

Documentación de SLR1 versión 1.x

116

Page 117: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Para que un esquema deductivo sea válido debe primero sersintácticamente correcto. Luego, la validez puede ser demostrada de dosmaneras: utilizando la teoría de la demostración o utilizando la teoríasemántica del cálculo proposicional. En este ejemplo se utilizará la teoríasemántica del cálculo proposicional.

En la teoría semántica del cálculo proposicional, un sistema deductivoes válido cuando la implicación asociada a éste es tautología.

Entonces, para verificar la validez de un esquema deductivo seejecutarán las siguientes operaciones:

1. Primero se realizará el análisis sintáctico del esquema deductivo fuente,a efectos de detectar errores sintácticos.

2. Luego se traducirá el esquema deductivo a su implicación asociada, laque será internamente almacenada en un vector en notación postfijo, aefectos de facilitar su posterior evaluación. Al traducir se generará unatabla con todas las variables que figuran en la fórmula.

3. A continuación se comprueba si la implicación asociada es unatautología, para lo cual se van generando las interpretaciones posiblespara las variables que aparecen en la fórmula, y para cada una secomprueba el valor de verdad de la fórmula. Si para algunainterpretación la fórmula da falso, la misma no es tautología. Si ocurreque la fórmula si es tautología, el esquema deductivo es válido.

4. Se informa el resultado del paso 3.

Los archivos importantes que componen el proyecto son los que seenumeran a continuación, y son independientes del sistema operativo en el quese implemente la aplicación:

ED.GLC: entrada para SLR1 v 1. La salida de SLR1 son los archivosED.CMM que debe ser compilado y encadenado con el proyecto y elarchivo ED.TXT en donde se encuentran los comentarios.

ED.CMM: salida de SLR1 al especificar como entrada a ED.GLC. Estearchivo contiene la gramática en formato C++.

EVALUAR.CMM: en este módulo se dan las funciones para evaluar unafórmula bien formada del cálculo proposicional dada en notación postfijo.

Documentación de SLR1 versión 1.x

117

Page 118: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ASIGINT.CMM: en este módulo se da una función que traduce unainterpretación codificada en binario, cargando en cada variable de la tablade símbolos dada el valor de verdad correspondiente.

TAUTO.CMM: en este módulo se da una función que verifica si unafórmula dada en notación postfijo es o no tautología.

VESQDED.CMM: en este módulo se da una función que verifica unesquema deductivo dado como entrada. Se podría considerar a este módulocomo el principal.

ALED.CMM: en este módulo están el analizador lexicográfico y la funciónde acciones semánticas que realizan la traducción.

ANALIZAR.CMM: este módulo viene provisto junto con SLR1 v 1, ycontiene la función Analizar que realiza el análisis sintáctico usando lastablas generadas por SLR1 a partir de la gramática.

ESQDED.H: este es un archivo cabecera en donde se declaran las clases yprototipos de las funciones desarrolladas, a los efectos de poder reusarfácilmente los módulos fuentes escritos.

SLR1.H: declaración (prototipo) de la función Analizar. Viene provistojunto con SLR1 v 1.

ELEM.H: declaración de las clases usadas para manejar las estructuras dedatos utilizadas durante el análisis sintáctico. Viene provisto junto conSLR1 v 1.

La interfase con el usuario final de la aplicación ha sido generada con elApplication Expert (AppExpert) del Turbo C++ 4.5 para Windows; laaplicación correrá sin problemas en Windows 3.1 en adelante, incluyendo aWindows NT. El código generado puede ser recompilado sin problemasusando el Borland C++ 2.0 para OS/2, y obtener así una versión que correrá enOS/2 2.1 y OS/2 Warp, pero se debe tener cuidado con ese C++ puesto que esde 32 bits (en C++ no se dan especificaciones sobre la implementación de lostipos de datos fundamentales, la misma queda a elección del fabricante delcompilador; por ejemplo, en C++ para Win16 el tamaño del tipo int es de 16bits y en C++ para OS/2 y Win32 es de 32 bits).

La aplicación generada es un editor multitexto (se pueden editar variostextos a la vez) con todas las funciones de un editor de textos, y en el menúarchivo se agregó una opción para "Verificar validez" del esquema deductivoque se encuentra en la ventana de texto actual (la que se encuentre activa). Lageneración de la aplicación es en realidad más simple de lo que se pueda

Documentación de SLR1 versión 1.x

118

Page 119: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

entender a partir de la lectura de este documento (fue muy fácil), y es esa larazón por la que se eligió AppExpert para diseñar la interfase.

Los archivos generados son:

EDAPP.CMM: módulo principal.

EDEDITVW.CMM: clase que maneja un objeto editor de texto. A estemódulo se lo modificó para procesar la opción "Verificar validez".

EDMDICLN.CMM: clase para manejar un objeto cliente de un objeto MDI.

EDMDICHL.CMM: clase para manejar un objeto hijo de un objeto MDI.

APXPREV.CPP: presentación preliminar de un documento editado.

APXPRINT.CPP: objeto para imprimir un documento.

EDABTDLG.CPP: ventana Acerca de... de la aplicación.

APXPREV.H: cabecera de APXPREV.CPP.

APXPRINT.H: cabecera de APXPRINT.CPP.

EDABTDLG.H: cabecera de EDABTDLG.CPP

EDAPP.H: cabecera de EDAPP.CMM.

EDEDITVW.H: cabecera de EDEDITVW.CMM.

EDMDICLN.H: cabecera de EDMDICLN.CMM.

EDMDICHL.H: cabecera de EDMDICHL.CMM.

Además se utilizó la biblioteca de clases BCE, la que se encuentradisponible para DOS, Windows y OS/2 (para modo caracter y PresentationManager). Los módulos no se enumeran por ser un producto comercial. Seusaron únicamente la clase Ascii0 (en EDEDITVW.CMM para almacenar eltexto) y la función SimbSig en el analizador lexicográfico (en ALED.CMM,para simplificar el mismo).

La clase EDEditView, cuya definición está en EDEDITVW.CMM, yque sirve para manejar una vista de un documento de texto (el generadorAppExpert da soporte al modelo documento/vista introducido por Borland ensus C++ desde la versión 4.0 para Windows y 2.0 para OS/2), fue modificadapara manejar el evento CM_VERIFICAR que se genera al seleccionar laopción "Verificar validez". La función agregada es la VerificarValidez de esta

Documentación de SLR1 versión 1.x

119

Page 120: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

clase, cuya declaración y prototipado inicial fue realizado por ClassExpert, eladministrador de clases de AppExpert. La función se transcribe acontinuación, y el código agregado es el que está después del comentario //INSERT>>... y termina en la llamada a MessageBox final. (Se aclaranuevamente que el resto del código, salvo dos líneas que se encuentran alcomienzo de éste módulo, no ha sido escrito por el autor).

void EDEditView::VerificarValidez (){ // INSERT>> Your code here. // Primero sacar el texto del EditView de Windows Ent16ns tam = GetTextLen() + 1; Ascii0 cad(tam); if (! GetText(cad, tam)) return; // si no hay texto editado

// Luego llamar a la función que verifica validez: int r = ValidarEsqDed(cad);

// y finalmente se informa el resultado: const char * msj = "CODIGO DESCONOCIDO"; uint icono = MB_OK; switch (r) { case EDVAL: msj = "El esquema deductivo es VALIDO."; icono |= MB_ICONINFORMATION; break; case EDINVAL: msj = "El esquema deductivo es INVALIDO."; icono |= MB_ICONEXCLAMATION; break; case EDERROR: msj = "Error sintáctico en el fuente."; icono |= MB_ICONQUESTION; break; } MessageBox(msj, "Resultado del análisis", icono);}

La única sentencia importante en esta función es la llamada aValidarEsqDed, que es la función que actualmente ejecuta toda la operaciónde validación. Todas las sentencias antes de ésta sirven para extraer el textodel objeto ventana editor del Windows (a través de la clase TEdit, clase basede TEditView y EDEditView). El código siguiente a la llamada aValidarEsqDed es el que presenta el resultado en una ventana de mensajes. Elproblema de obtener el texto de entrada e informar el resultado de lavalidación es un problema aparte, y se puede realizar como uno quiera y en elsistema operativo que desee.

También se agregaron dos líneas más al comienzo del móduloEDEDITVW.CMM, que son las siguientes:

# include <ascii0.h> // de BCE# include "esqded.h" // de esta aplicación

Documentación de SLR1 versión 1.x

120

Page 121: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Los .h incluidos hacen posible la utilización de la clase Ascii0 (paraobtener el texto) y de la función ValidarEsqDed (que no está definida en estemódulo).

El código restante (enumerado en el primer grupo de módulos fuentes)es el que realiza todo el trabajo de validación. No contempla la forma deobtener el texto ni la forma de emitir mensajes (ambas dependientes delsistema operativo). Este conjunto de módulos fuentes son independientes delsistema operativo, inclusive son independiente de si trabaja con código ANSIu OEM (los editores de Windows trabajan con OEM, los de DOS y algunos deOS/2 con ANSI).

La gramática que se dará de entrada a SLR1 en el archivo de texto planoED.GLC es la siguiente:

E --> Prem '#' FPrem --> Prem ',' FPrem --> FF --> F '<==>' IF --> II --> I '==>' DI --> DD --> D '+' CD --> CC --> C '*' PropC --> PropProp --> cProp --> vProp --> '(' F ')'Prop --> - Prop

En esta gramática, el símbolo # sirve para decir que a continuaciónviene la conclusión, la coma separa a las premisas (debe haber por lo menosuna). Cada premisa debe ser una fórmula bien formada del cálculoproposicional. El símbolo <==> se utiliza para la doble implicación, el ==> seutiliza para el la implicación, el + para la disyunción, el * para la conjunción,el - para la negación y los ( ) para la asociatividad y ruptura de precedencia.Los tres siguientes son ejemplos de esquemas deductivos reconocibles por lagramática dada:

Ejemplo 1:

p ==> q, p # q

Ejemplo 2:

Documentación de SLR1 versión 1.x

121

Page 122: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

-p + q, p # q

Ejemplo 3:

- ( p * r ), q ==> r, q # -p

Los esquemas dados le pueden ser familiares. Los puede encontrar enalgún libro de lógica.

La forma en que se escriban las fórmulas no debe ser importante,inclusive los espacios que se dejan entre ellas. Este problema será resuelto porel analizador lexicográfico que se da en el archivo ALED.CMM. El prototipodel analizador lexicográfico es similar al dado en páginas anteriores. Loscódigos que devuelven coinciden con los indicados por SLR1 v 1 en elconjunto T de símbolos terminales, el cual se transcribe:

T = { ('#', 1), (',', 2), ('<==>', 3), ('==>', 4), ('+', 5), ('*', 6), (c, 7), (v, 8), ('(', 9), (')', 10), (-, 11) }

En el conjunto se muestra cada terminal como un par ordenado en dondeel primer componente es la cadena de caracteres usado en la gramática fuente yel número dado en el segundo componente es el código asignado.

Debido a que los códigos que se le asignan a los terminales puedencambiar con sólo cambiar el orden de las reglas, se #definen macros para tenerindependencia entre código fuente y los códigos asignados (ver ALED.CMM).

El analizador lexicográfico mantiene el último identificador de variableo constante en la variable global ult_c_v definida en ALED.CMM a losefectos de no tener que modificar la estructura de los elementos de la pila paraacceder a la cadena de caracteres usada en el fuente, durante el análisissintáctico.

La entrada al analizador sintáctico es una cadena de caracteres que sefija con la función FijarFuente definida en ALED.CMM. La función deanálisis lexicográfico será llamada por la función Analizar a medida que senecesite un símbolo de entrada.

La función de acciones semánticas cuyo nombre es AccSemEsqDed yestá definida en ALED.CMM, traduce el esquema deductivo en notaciónentrefijo del fuente a notación postfijo. La fórmula resultante se guarda en elvector fnp, desde el elemento 0 en adelante; la variable global ifnp tiene el

Documentación de SLR1 versión 1.x

122

Page 123: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

tamaño de fnp. En una tabla de símbolos que se implementa en un vector connombre tds y tamaño itds se almacenan las variables que aparecen en lafórmula, una copia por variable. Esta tabla de símbolos se utiliza para asignarla interpretación a las variables y poder luego evaluar la fórmula.

Observar en el código de AccSemEsqDed que al reducir por regla 1(E---> Prem # F ) o 6 ( I --> I '==>' D ), a los operadores '#' y '==>' se lostraduce a '==>'. En este caso, el '#' puede interpretarse como un '==>' de menorprecedencia. Lo mismo ocurre con la reducción por reglas 2 ( Prem --> Prem ','F ) o 10 ( C --> C '*' Prop ), en donde los operadores ',' y '*' se traducen a '*',esto es, ',' tiene el mismo significado (semántica) que '*', sólo que es unoperador de menor precedencia. (Como ejercicio para el lector se proponehacer la tabla de precedencia de operadores para la gramática dada.)

Observar también que en la reducción de las reglas 12 y 13, el símboloque nos interesa es exactamente el anterior al actual, y se usa la variableult_c_v para accederlo.

La función que verifica si la fórmula proposicional en notación postfijoes tautología se llama Tautologia y se encuentra definida en el móduloTAUTO.CMM. La misma genera interpretaciones de las variables queaparecen en la fórmula hasta encontrar alguna interpretación para la que lafórmula dé falso. La interpretación (un juego de valores de verdad asignado alas variables de la fórmula) se codifica en un número binario de 16 bits, endonde el bit 0 tiene el valor de verdad de la variable tds[0], el bit 1 a tds[1], yasí sucesivamente. Como el número tiene 16 bits, a lo sumo pueden haber 16variables distintas posibles. El pasaje de binario a la tabla de símbolos de unainterpretación lo realiza la función AsigInterp definida en ASIGINT.CMM.La función Evaluar realiza la evaluación de una fórmula proposicional dadaen postfijo para una interpretación dada.

Más documentación puede encontrar en los archivos fuente. Acontinuación se transcriben los módulos fuentes enumerados en el primergrupo de módulos fuentes, que son los que realmente se escribieron para estaaplicación. Los demás módulos fueron generados automáticamente, y sólo sonimportantes las líneas transcriptas a éste documento, y por tal razón no seincluyen aquí.

Documentación de SLR1 versión 1.x

123

Page 124: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11.10 Módulos fuentes escritos para el ejemplo 4

11.10.1 ED.GLC

E --> Prem '#' FPrem --> Prem ',' FPrem --> FF --> F '<==>' IF --> II --> I '==>' DI --> DD --> D '+' CD --> CC --> C '*' PropC --> PropProp --> cProp --> vProp --> '(' F ')'Prop --> - Prop

11.10.2 ED.CMM

?????????

No se incluye por ser salida de SLR1 v 1 y generable a partir deED.GLC.

11.10.3 EVALUAR.CMM

// evaluar.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"# include <string.h>

// int ValorDe( const char * s, const SimbFormProp * tds, unsigned ttds );// Esta función busca el símbolo cuya cadena es s en el vector tds cuyo// tamaño es ttds.// Debido a que para la comparación de cadenas se usa strcmp, se hace// diferencia entre mayúsculas y minúsculas.// La función devuelve el valor de verdad asignado a la variable.

static int ValorDe( const char * s, const SimbFormProp * tds, unsigned ttds ) { register int i; for (i = 0; i < ttds; ++i) if (! strcmp(s, tds[i].var)) break; if (i == ttds) return 0; else return tds[i].valor;}

Documentación de SLR1 versión 1.x

124

Page 125: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// int Evaluar( char p, char q, int operacion );// Evaluar evalúa la operacion pasada como parámetro a partir de los// operandos p y q.// En p y q debe venir 0 si es falso o distinto a 0 si es verdadero.// La función devuelve 0 si el resultado de la operación es falso y// distinto a 0 si el resultado de la operación es verdadero.// La operación se codifica con la enumeración dada en simbolo.h dentro// de la clase SimbFormProp, y se acceden desde cualquier lugar usando el// operador :: para romper ámbitos. Ellos son:// DOBLEIMPL: <==> doble implicación, binario, p <==> q// IMPLIC: ==> implicación, binario, p ===> q// DISYUN: + disyunción, binario, p + q// CONJUN: * conjunción, binario, p * q// NEGAR: - negación, unario, - p

int Evaluar( char p, char q, int operacion ) { p = p ? 1 : 0; // llevar a 0 o 1 q = q ? 1 : 0; register int r = 0; switch (operacion) { case SimbFormProp::DOBLEIMPL: // <==> r = ! (p ^ q); break;

case SimbFormProp::IMPLIC: // ==> r = ! p | q; break;

case SimbFormProp::DISYUN: // + (disyunción) r = p | q; break;

case SimbFormProp::CONJUN: // * (conjunción) r = p & q; break;

case SimbFormProp::NEGAR: // - (negación) r = ! p; break; } return r;}

// int Evaluar( const SimbFormProp * fnp, unsigned tfnp,// const SimbFormProp * tds, unsigned ttds );// Evaluar evalúa la expresión en postfijo pasado en el vector fnp, cuyo// tamaño es tfnp.// La interpretación a utilizar es la que viene en la tabla de símbolostds,// cuyo tamaño es ttds.// La función devuelve 0 si la fórmula bien formada en notación postfijofnp// es falsa para la interpretación dada, y distinto a 0 si es verdadera.// El algoritmo que se usa para evaluar la expresión en notación postfijo// puede ser encontrado en cualquier libro de Estructuras de datos y// Algoritmos.

int Evaluar( const SimbFormProp * fnp, unsigned tfnp, const SimbFormProp * tds, unsigned ttds ) { char pila[20], pp = 0; register unsigned ifnp; for (ifnp = 0; ifnp < tfnp; ++ifnp) { if (fnp[ifnp].cod > SimbFormProp::MAXVAR &&

Documentación de SLR1 versión 1.x

125

Page 126: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

fnp[ifnp].cod < SimbFormProp::ULTIMOOPERADOR) { // efectuaroperación if (fnp[ifnp].cod == SimbFormProp::NEGAR) { // operación unaria, desapila 1 y apila el resultado pila[pp - 1] = Evaluar(pila[pp-1], 0, fnp[ifnp].cod); } else { // operación binaria, desapila 2 y apila el resultado pila[pp - 2] = Evaluar(pila[pp-2], pila[pp-1], fnp[ifnp].cod); --pp; } } else pila[pp++] = ! fnp[ifnp].cod ? fnp[ifnp].valor : ValorDe(fnp[ifnp].var, tds, ttds); } return pila[pp-1];}

11.10.4 ASIGINT.CMM

// asigint.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"

// void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv );// AsigInterp asigna a la tabla de símbolos la interpretación que viene// codificada en vv.// Si numeramos los bits de vv de 0 a 15, el bit 0 corresponde a tds[0],// el bit 1 a tds[1], ..., y el bit 15 a tds[15].// El valor de verdad de cada variable se asigna al campo valor de cada// elemento de tds.

void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv ) { register int i, bit; for (i = 0, bit = 1; i < ttds; ++i, bit <<= 1) tds[i].valor = vv & bit;}

11.10.5 TAUTO.CMM

// tauto.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"

// int Tautologia( const SimbFormProp * fnp, unsigned tfnp,// SimbFormProp * tds, unsigned ttds );// Tautologia chequea si la fórmula bien formada del cálculo proposicional// que viene en fnp en formato notación postfijo es una tautología.// El tamaño de la fórmula es tfnp (número de elementos del vector).// La tabla de símbolos que se recibe como parámetros es a los efectos de// poder generar las interpretaciones posibles. El tamaño de la tabla de// símbolos (vector) viene dado en ttds.

Documentación de SLR1 versión 1.x

126

Page 127: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// La función devuelve 0 si no es tautología y distinto a 0 si lo es.

int Tautologia( const SimbFormProp * fnp, unsigned tfnp, SimbFormProp * tds, unsigned ttds ) { int i, t; t = (1 << ttds) - 1; // 2 elevado a la número de variables menos 1 for (i = 0; i <= t; ++i) { AsigInterp(tds, ttds, i); if (! Evaluar(fnp, tfnp, tds, ttds)) // si alguno es falso break; // entonces no es tautología } return i > t; // si se probaron todas las interpretaciones} // entonces es tautología

11.10.6 VESQDED.CMM

// vesqded.cmm validación de esquemas deductivos.

// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"# include "slr1.h" // función Analizar

// Variables definidas en aled.cmmextern SimbFormProp fnp[ ], tds[ ];extern unsigned ifnp, itds;

// Los siguientes se encuentan en ed.cmm (generado por SLR1 v 1)extern unsigned noterm_long_pd[ ], accion[ ], ir_a[ ];

// AccSemEsqDed son las acciones semánticas que traducen a postfijo a la// fórmula. Ver documentación en aled.cmm.void AccSemEsqDed( unsigned numregla );

int ValidarEsqDed( const char * EsqDed ) { FijarFuente(EsqDed); if ( Analizar(noterm_long_pd, accion, ir_a, AnaLexEsqDed, AccSemEsqDed)) return Tautologia(fnp, ifnp, tds, itds) ? EDVAL : EDINVAL; else return EDERROR;}

11.10.7 ALED.CMM

// aled.cmm// Funciones para el analizador lexicográfico.// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"# include <string.h># include <fvarias.h> // de la biblioteca BCE se usa SimbSig

const char * cadena = 0, * psimb = 0;

Documentación de SLR1 versión 1.x

127

Page 128: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

SimbFormProp fnp[50], // fórmula en notación postfijo tds[16]; // tabla de símbolos

unsigned ifnp = 0, itds = 0;

// void FijarFuente( const char * cad );// FijarFuente fija a cad como el texto fuente a analizar.// El texto puede ser cargado por una simple lectura binaria a un archivo// de texto, pidiendo que lea tantos bytes como la longitud del archivo y// recibirlo en un bloque de caracteres de ese tamaño más uno. Al último// elemento le debe poner un 0.

void FijarFuente( const char * cad ) { psimb = (char *) ( cadena = cad ); ifnp = itds = 0;}

// int AgregarTDS( const char * s );// Agrega s a la tabla de símbolo. s es la cadena que identifica alsímbolo.// Si la variable ya existe en la tabla entonces no lo agrega.// Siempre devuelve el código asignado a la variable, que es un número// entre 1 y 16.

int AgregarTDS( const char * s ) { register int i; for (i = 0; i < itds; ++i) if (! strcmp(tds[i].var, s)) break; if (i == itds) { strncpy(tds[itds].var, s, 10); tds[itds].valor = 0; ++itds; tds[itds].cod = itds; return itds; // devuelve el código que se le asigna } return tds[i].cod; // dev. el cód. asignado anteriormente}

// Las cadenas de caracteres siguientes sirven para trabajar con SimbSig.// El ^ del comienzo significa cualquier caracter menos los que seenumeran// a la derecha. La sintaxis de las cadenas dadas es la misma que usa LEX// de UNIX para la especificación de rangos de caracteres.// Puede consultar la documentación de la función SimbSig de BCE o la// documentación del LEX en cualquier manual de UNIX, XENIX o LINUX.

static char * blanco = "^ \n\r\t", * ident = "^0-9_a-zA-ZáéíóúñÑüÜ", * cons = "^01", // 0 falso, 1 verdadero * neg = "^-", * disy = "^+", * conj = "^*", * impl = "^=>", * doblimp = "^<=>", * a_par = "^(", * c_par = "^)", * coma = "^,", * conclu = "^#";

// SLR1 v1 informó en el archivo ed.txt (luego de procesar a ed.glc) que// los símbolos terminales deben tener asignados los siguientes códigos:// T = { ('#', 1), (',', 2), ('<==>', 3), ('==>', 4), ('+', 5),// ('*', 6), (c, 7), (v, 8), ('(', 9), (')', 10), (-, 11) }// Se utilizan sentencias #define para trabajar independientemente de

Documentación de SLR1 versión 1.x

128

Page 129: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// los códigos que asigne SLR1 v1 (puede cambiarlos si cambiamos lagramática).

# define IDENT 8# define CONS 7# define NEG 11# define DISY 5# define CONJ 6# define IMPL 4# define DOBLIMP 3# define A_PAR 9# define C_PAR 10# define COMA 2# define CONCLU 1# define NO_SE 12

char simbolo[100], // aquí devuelve el analizador léxico la cadenaencontrada ult_c_v[100]; // último constante o variable. Se usa para lasacciones // a efectos de no implementar una pila especial.

// unsigned char AnaLexEsqDed();// Realiza el análisis lexicográfico de un esquema deductivo del cálculo// proposicional.// El prototipo de esta función coincide con el requerido por la SLR1 v 1.// Devuelve el código del símbolo léxico encontrado, 0 si es fin dearchivo.// Previo al uso de la función, las variables internas deben ser// inicializadas llamando a la función FijarFuente y pasando comoparámetro// la cadena de texto a analizar (la que contiene el esquema deductivo).

unsigned char AnaLexEsqDed() { psimb = SimbSig(psimb, simbolo, blanco); // saltear blancos if (psimb = SimbSig(psimb, simbolo, cons), *simbolo) { strcpy(ult_c_v, simbolo); return CONS; } if (psimb = SimbSig(psimb, simbolo, ident), *simbolo) { strcpy(ult_c_v, simbolo); return IDENT; } if (psimb = SimbSig(psimb, simbolo, neg), *simbolo) return NEG; if (psimb = SimbSig(psimb, simbolo, disy), *simbolo) return DISY; if (psimb = SimbSig(psimb, simbolo, conj), *simbolo) return CONJ; if (psimb = SimbSig(psimb, simbolo, impl), *simbolo) return IMPL; if (psimb = SimbSig(psimb, simbolo, doblimp), *simbolo) return DOBLIMP; if (psimb = SimbSig(psimb, simbolo, a_par), *simbolo) return A_PAR; if (psimb = SimbSig(psimb, simbolo, c_par), *simbolo) return C_PAR; if (psimb = SimbSig(psimb, simbolo, coma), *simbolo) return COMA; if (psimb = SimbSig(psimb, simbolo, conclu), *simbolo) return CONCLU; if (psimb != 0 && *psimb) return NO_SE; else return 0;}

// void AccSemEsqDed( unsigned numregla );// Esta función realiza las acciones semánticas durante el análisissintáctico.// La forma de trabajo de estas acciones semánticas se basa en latraducción// a postfijo de la expresión fuente. Es similar a la que se hace como// ejercicio en los cursos de compiladores y la puede encontrar en la// bibliografía de construcción de compiladores e intérpretes.// Fundamentos de las acciones semánticas dadas:// - Un esquema deductivo puede ser traducido a una fórmula bien formada

Documentación de SLR1 versión 1.x

129

Page 130: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// del cálculo proposicional, concatenando las premisas con conjunciones// y hacer que la fórmula resultante implique la conclusión.// - A tal efecto, el # se considera como un ==> con precedencia muchomenor// que todos los demás operadores, y la coma (,) como el * (conjunción)// pero con precedencia mayor que el # y menor que el resto de los// operadores.// - A partir de los dos puntos previos, el esquema deductivo ya viene con// la forma de la implicación asociada, y el único trabajo que queda// es traducirla a notación postfijo para poder evaluarla.

void AccSemEsqDed( unsigned numregla ) { switch (numregla) { case 1: // E ---> Prem '#' F case 6: // I ---> I '==>' D fnp[ifnp].cod = SimbFormProp::IMPLIC; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "==>"); ++ifnp; break;

case 2: // Prem ---> Prem ',' F case 10: // C ---> C '*' Prop fnp[ifnp].cod = SimbFormProp::CONJUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "*"); ++ifnp; break;

case 4: // F ---> F '<==>' I fnp[ifnp].cod = SimbFormProp::DOBLEIMPL; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "<==>"); ++ifnp; break;

case 8: // D ---> D '+' C fnp[ifnp].cod = SimbFormProp::DISYUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "+"); ++ifnp; break;

case 12: // Prop ---> c fnp[ifnp].cod = SimbFormProp::CONSTANTE; fnp[ifnp].valor = *ult_c_v == '0' ? 0 : 1; strncpy(fnp[ifnp].var, ult_c_v, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; break;

case 13: // Prop ---> v // Escribir en la expresión en notación postfijo fnp[ifnp].cod = AgregarTDS(ult_c_v); // agrega a tds y asigna elcódigo fnp[ifnp].valor = 0; strncpy(fnp[ifnp].var, ult_c_v, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; break;

case 15: // Prop ---> - Prop fnp[ifnp].cod = SimbFormProp::NEGAR; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "-");

Documentación de SLR1 versión 1.x

130

Page 131: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

++ifnp; break;

}}

11.10.8 ANALIZAR.CMM

Este módulo viene provisto con SLR1 v 1. Se lo incluye a modo deilustración.

// Analizar()

# include "slr1.h"# include "elem.h"# include <ascii0.h>

void MostrarPila( void (* fver)( char * mensaje ), ElemPila * p, unsigned pp ) { if (fver == 0) return; (*fver)("Pila: "); Ascii0 cad; unsigned c = 0; while (c <= pp) { cad.printf("%u%c,%u ", p[c].s.cod, p[c].s.noterminal ? 'n' : 't', p[c].e); (*fver)(cad); ++c; } (*fver)("\n");}

int Analizar( unsigned * ntlpd, unsigned * accion, unsigned * ir_a, unsigned char (* analex)(), void (* accion_sem)( unsigned numregla ), void (* fver)( char * mensaje ) ) { if (analex == 0) return 0; ElemPila pila[100]; Accion a; unsigned x1,x2,x3; // variables auxiliares unsigned numiter; unsigned pp = 0; // puntero de pila pila[0].e = 0; // estado inicial. Ascii0 msj; unsigned char s, nt = ntlpd[0] >> 8, t = ntlpd[0] + 1;

// pila[pp].e es el estado actual. int salir = 0, cumple; s = (*analex)(); // pide un s¡mbolo de entrada if (s > t) return 0; // s¡mbolo inesperado numiter = 0; while ( ! salir ) { if (fver != 0) { msj.printf("Iter: %4u ", ++numiter); (*fver)(msj); MostrarPila(fver, pila, pp); msj.printf("Est: %u, S¡mb: %u, ", pila[pp].e, (unsigned) s); (*fver)(msj); }

Documentación de SLR1 versión 1.x

131

Page 132: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

a = x1 = accion[pila[pp].e * t + s]; if (! x1) { // error salir = 1; cumple = 0; if (fver != 0) (*fver)("ERROR.\n"); } else { switch (a.cod) { case 0: // desplazar s e ir a a.n pila[++pp].s.cod = s; pila[pp].s.noterminal = 0; pila[pp].e = a.n; if (fver != 0) { msj.printf("d%u\n", a.n); (*fver)(msj); } s = (*analex)(); // pide otro s¡mbolo de entrada if (s > t) { // s¡mbolo inesperado salir = 1; cumple = 0; } break;

case 1: // aceptar salir = cumple = 1; if (fver != 0) (*fver)("Aceptar.\n"); break;

case 2: // reducir por a.n x1 = ntlpd[a.n]; x2 = x1 & 0x00FF; // apaga el byte alto pp = x2 > pp ? 0 : pp - x2; // desapila x2 elementos x1 >>= 8; // c¢d del no terminal x3 = ir_a[ pila[pp].e * nt + x1 - 1 ]; if (accion_sem != 0) (*accion_sem)(a.n); pila[++pp].s.cod = x1; pila[pp].s.noterminal = 1; pila[pp].e = x3; if (fver != 0) { msj.printf("r%u, lpdr: %u, EstExp: %u, NT: %u\n", a.n, x2, pila[pp-1].e, x1); (*fver)(msj); } break;

default: // problemas salir = 1; cumple = 0; if (fver != 0) (*fver)("PROBLEMAS EN LAS TABLAS.\n"); } } // else } // while

return cumple;}

11.10.9 ESQDED.H

# ifndef __ESQDED_H# define __ESQDED_H

// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93

Documentación de SLR1 versión 1.x

132

Page 133: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Ult Mod: 01 Nov 95

// clase SimbFormProp: implementa un símbolo de una fórmula del cálculo// proposicional. Un símbolo puede ser una constante (V o F), una variable// o un operador lógico.

class SimbFormProp {public: unsigned cod; char valor; char var[10];

enum { CONSTANTE = 0, MAXVAR = 999, DOBLEIMPL, IMPLIC, DISYUN, CONJUN, NEGAR, ULTIMOOPERADOR };};

// Funciónes de operaciones lógicas:

// Evaluación de una fórmula con 1 o 2 operandos:int Evaluar( char p, char q, int operacion );

// Evaluación de una fórmula compleja dada en notación postfijo.// fnp es la fórmula (en vector), tfnp el número de elementos.// tds es la tabla de variables de la fórmula de ttds elementos.// En el campo valor de cada elemento de tds está el valor de verdad// asignado a la variable (==0 falso, !=0 verdadero).

int Evaluar( const SimbFormProp * fnp, unsigned tfnp, const SimbFormProp * tds, unsigned ttds );

// Asignación de una interpretación (ver doc en asigint.cmm):void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv );

// Verificación de si una fórmula es tautología o no:// La fórmula a comprobar viene en notación postfijo en fnp, representado// como vector de tamaño tfnp. La tabla de variables viene en tds, unvector// de tamaño ttds. El campo valor de los elementos de tds son modificados.

int Tautologia( const SimbFormProp * fnp, unsigned tfnp, SimbFormProp * tds, unsigned ttds );

// Funciones para el análisis léxico y traducción del esquema deductivo a// implicación asociada:

// FijarFuente debe ser llamado previo a llamar a la función Analizar.// El parámetro es una cadena de caracteres con el esquema deductivo.// Ver documentación en aled.cmm.

void FijarFuente( const char * cad );

// AgregarTDS agrega a s como variable en la tabla de símbolos interna.// Devuelve el código asignado a la variable.

int AgregarTDS( const char * s );

// AnaLexEsqDed es la función que realizará el análisis lexicográfico// del esquema deductivo. Se pasa como parámetro a la función Analizar.

unsigned char AnaLexEsqDed();

// Validar un esquema deductivo dado en formato texto:// la función devuelve:// EDVAL si es válido.

Documentación de SLR1 versión 1.x

133

Page 134: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// EDINVAL si es inválido.// EDERROR si hay error léxico o de sintaxis.

int ValidarEsqDed( const char * EsqDed );# define EDVAL 0# define EDINVAL 1# define EDERROR 2

# endif

11.10.10SLR1.H

Este módulo viene provisto con SLR1 v 1. Se lo incluye a modo deilustración.

#ifndef __SLR1_H#define __SLR1_H

// slr1.h: declaraci¢n de la funci¢n que realiza el an lisis sint ctico.//// Copyright (c) 1992 by Domingo Becker.// All rights reserved.

int Analizar( unsigned * ntlpd, unsigned * accion, unsigned * ir_a, unsigned char (* analex)(), void (* accion_sem)( unsigned numregla ) = 0, void (* fver)( char * mensaje ) = 0 );

#endif

11.10.11ELEM.H

Este módulo viene provisto con SLR1 v 1. Se lo incluye a modo deilustración.

#ifndef __ELEM_H#define __ELEM_H

// elem.h: definici¢n de las clases para las tablas que maneja elanalizador// sint ctico slr(1)//// Copyright (c) 1992 by Domingo E. Becker.// All rights reserved.

#ifndef __ASCII0_H#include "ascii0.h"#endif

class Simbolo {public: unsigned char cod; unsigned char noterminal;};

class SimbCad : public Simbolo {public: Ascii0 cad;

Documentación de SLR1 versión 1.x

134

Page 135: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

};

class ElemPila { // estructura de un elemento de la pila del analizadorpublic: Simbolo s; unsigned e; ElemPila() { s.cod = s.noterminal = 0; e = 0; }};

class Accion { // estructura de una acci¢npublic: unsigned n : 14; unsigned cod : 2; // 00=d, 01=a, 10=r Accion() { *(unsigned *) this = 0; } Accion( unsigned a ) { *(unsigned *) this = a; } Accion & operator = ( unsigned a ); int operator == ( unsigned a ) { return *(unsigned *) this == a; }};

inline Accion & Accion::operator = ( unsigned a ) { *(unsigned *) this = a; return *this;}

#endif // #ifndef __ELEM_H

Documentación de SLR1 versión 1.x

135

Page 136: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 12: Documentación de SLR1 versión 2.x

El texto de este capítulo es la documentación de SLR1 v 2.x, y debe sertomado como un libro aparte. No se hacen referencias a otros capítulos de estetrabajo.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

12.1 Introducción

SLR1 es un programa para generar tablas de análisis sintáctico LR(1)Simples a partir de la especificación de la gramática del lenguaje. Las tablasgeneradas por este programa serán usadas para la realización del análisissintáctico de oraciones de ese lenguaje.

Este documento es la guía del usuario y manual de referencia delgenerador SLR1 v 2.x. Su lectura presupone conocimientos básicos de laTeoría de los Lenguajes Formales. Además se aconseja leer la documentaciónde AFD v 3.x.

Lo que más adelante se menciona como metagramática tiene unsignificado análogo al término metalenguaje en lingüística. En lingüística,metalenguaje significa un lenguaje para hablar de lenguajes. Aquí,metagramática significa una gramática para hablar de gramáticas.

12.2 Descripción general del funcionamiento

Se desarrollaron 3 implementaciones de SLR1 v 2, una para DOS, otrapara Windows y otra para OS/2 (Presentation Manager).

La entrada de SLR1 v 2 es un archivo de texto plano con la gramáticaque se desea tratar, en donde se incluyen las acciones semánticas(opcionalmente) para las reglas, entre otras cosas.

La salida del programa son 3 archivos: un archivo .CMM con lasacciones semánticas y el analizador léxico (en C++), un archivo .TAB con lastablas en formato C++ que serán utilizadas para el análisis sintáctico, y unarchivo .EST con las tablas de análisis sintáctico en formato similar al que se

Documentación de SLR1 versión 2.x

136

Page 137: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

presenta en la bibliografía, con los estados y con los códigos asignados a lossímbolos terminales y no terminales.

Los archivos .CMM y .TAB son los que luego se utilizan para realizar elanálisis sintáctico, incluyéndolo en la compilación junto con otros módulosfuentes del proyecto en desarrollo.

12.3 Especificación de una gramática

La gramática debe ser escrita usando un archivo de texto plano con uneditor adecuado para el sistema operativo con el que se trabaja (al archivo quecontiene la gramática de entrada se lo mencionará en adelante como archivo.GLC). El editor debe trabajar con código ANSI si es de Windows y con OEMsi es de DOS u OS/2. Si usa un editor que trabaja con OEM y procesa lagramática con la versión de Windows entonces tendrá problemas con losacentos y la ñ.

12.3.1 Especificación 2.0 de la metagramática

La metagramática que a continuación se presenta, describe la sintaxisque se debe usar para especificar una gramática que se usará como entrada deSLR1. La puede encontrar en el archivo GRAM.GLC, en donde además seespecifican las acciones semánticas para cada regla.

Gram ---> Fuentes Directivas Reglas ;Fuentes ---> BlqCod ;Fuentes ---> ;Directivas ---> Directivas Directiva ;Directivas ---> ;Directiva ---> '#' 'ACCSEM' Ident BlqCod ;Directiva ---> '#' 'TERMINAL' Ident ':' Ident ;Directiva ---> '#' 'TERMINAL' Ident ;Directiva ---> '#' 'IGNORAR' Ident ':' Ident ;Directiva ---> '#' 'IGNORAR' Ident ;Directiva ---> '#' 'ELEMPILA' Ident ;Reglas ---> Reglas Regla ;Reglas ---> Regla ;Regla ---> ParteIzq SimbSep ListaAltern ';' ;ParteIzq ---> Ident ;SimbSep ---> Flecha ;SimbSep ---> ':' ;ListaAltern ---> ListaAltern '|' Altern ;ListaAltern ---> Altern ;Altern ---> ListaSimb CodAccSem ;ListaSimb ---> ListaSimb Simb ;ListaSimb ---> ;CodAccSem ---> '*' Ident ;CodAccSem ---> BlqCod ;CodAccSem ---> ;Simb ---> Ident ;

Documentación de SLR1 versión 2.x

137

Page 138: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Simb ---> Cadena ;

Las reglas se numeran de arriba a abajo de 1 a N, si hay N reglas.

Una gramática está formada por un conjunto no vacío de reglas, es decir,al menos debe haber una regla.

12.3.2 Lexicografía del lenguaje de especificación de gramáticas v 2.0

A continuación se documentarán los componentes léxicos que puedenusarse en la escritura de una gramática según la especificación 2.0 de lametagramática (ver GRAM.GLC o página anterior). El analizadorlexicográfico fue construido usando la versión 3 de AFD, junto con labiblioteca expreg.lib de soporte.

El analizador lexicográfico busca todas las especificaciones léxicas quereconocen al símbolo léxico actual (la expresión regular es un ejemplo deespecificación léxica, una palabra clave es otro ejemplo). Si hay más de unaespecificación léxica que reconoce al símbolo léxico actual se procede segúnlas siguientes reglas:

1. Si hay una especificación que reconoce una secuencia de caracteres máslarga que el resto de las especificaciones entonces se elige ésa. En casode empate entre dos o más especificaciones se procede según las reglassiguientes.

2. Si el grupo de especificaciones son expresiones regulares, se elige la quefue listada primero en el analizador léxico (ver más adelante).

3. Si en el grupo hay una palabra clave o un caracter reservado, se eligeéste. Así, TERMINAL puede ser un identificador, pero el analizadorléxico da prioridad a la palabra clave y lo reconoce como tal.

A continuación se enumeran los componentes léxicos. Los que fueronespecificados por medio de expresiones regulares aparecen en el orden en elque fueron dados en el analizador léxico (a efectos de poder aplicar las 3reglas anteriores para la resolución de conflictos).

Palabras claves: únicamente en mayúsculas, se reservan las siguientespalabras: ACCSEM, TERMINAL, IGNORAR y ELEMPILA. No es posiblemezclar mayúsculas con minúsculas.

Documentación de SLR1 versión 2.x

138

Page 139: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Caracteres reservados: se reserva el uso de los siguientes caracteres:

# para escritura de directivas al generador

: para escritura de las directivas TERMINAL, IGNORAR y como reemplazo de la flecha

; para finalizar una o más reglas.

| para la especificación de alternativas

* para referenciar a un bloque de código definido previamente con ACCSEM.

Bloque de código: un bloque de código es una porción de texto (de una o máslíneas) que comienza con el par de caracteres %{ y termina con }%.

Identificador: según la siguiente expresión regular:

# Letra [a-zA-Z_áéíóúñÑüÜ]# Digito [0-9]Letra (Letra | Digito)*

Flecha: uno o más guiones o signos menos seguido de un signo mayor que:

- + >

Cadena: según la siguiente expresión regular:

# CarEsp [abtnvfr]# Otros [^\'\\\"\n]'\'' ( ( '\\' ( '\\' | '\'' | '\"' | CarEsp ) ) | CarEsp | Otros ) + '\''|'\"' ( ( '\\' ( '\\' | '\'' | '\"' | CarEsp ) ) | CarEsp | Otros ) + '\"'

Una cadena de caracteres es similar a las que se dan en C++, a excepción deque como delimitadores pueden usarse las comillas simples además de lasdobles. Las secuencias de escape son las mismas que las del C++ (\a, \b, \t, \n,\v, \f, \r, \', \" y \\).

Blancos: los blancos se ignoran:

[ \n\r\f\t\v] +

Comentarios: los comentarios se ignoran. Son similares a los // del C++:

/ / .*

Documentación de SLR1 versión 2.x

139

Page 140: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.3.3 Semántica subyacente en la especificación 2.0 de la Metagramática

La sintaxis a usar en la escritura de una gramática es la definida por lametagramática dada previamente. La semántica se documenta a continuación.

La estructura de un archivo que contiene una gramática según laespecificación 2.0 se define por:

1. Partes del archivo .GLC

El archivo de gramática consta de tres partes a saber:

Bloque de código fuente previo a las acciones semánticas.

Directivas al generador de analizadores sintácticos.

Conjunto de reglas con sus correspondientes acciones semánticas.

2. Bloques de código previo a las acciones semánticas

Al comienzo del archivo .GLC se puede incluir un bloque de códigofuente C++ que será transcripto literalmente al archivo .CMM (el bloque esopcional, ver en páginas previas cómo se escribe un bloque de código).

3. Directivas al generador de analizadores sintácticos.

Las directivas al generador son sentencias similares a las del C++ quecomienzan con # (en el C++ están el #define, #include, #pragma, etc.). Lasdirectivas tienen como objetivo dar información adicional al generador ysimplificar la escritura de la gramática. Son opcionales.

En total son 4 las directivas disponibles en esta versión del generador:

ACCSEM

'#' 'ACCSEM' Ident BlqCod

Ejemplo:

# ACCSEM Bloque1 %{ // hacer algo aquí}%

El Ident que se define aquí puede servir posteriormente para referenciaral bloque de código definido. Se debe usar *Ident para referenciar al bloque,

Documentación de SLR1 versión 2.x

140

Page 141: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

caso contrario Ident será tomado como un símbolo (terminal o no terminal,según corresponda).

El objetivo de esta directiva es ahorrar escribir varias veces el mismobloque de acciones semánticas en distintas reglas, ahorrando espacio y tiempode escritura; el fuente .CMM generado es también más pequeño.

TERMINAL

dos posibilidades:

'#' 'TERMINAL' Ident ':' Ident

ó

'#' 'TERMINAL' Ident

Esta directiva define a Ident como un símbolo terminal. Si se usa laprimera versión (la que tiene ':') entonces el Ident de más a la derecha es elnombre del archivo que contiene la expresión regular que lo define, el cualdeberá ser procesado por AFD v 3.x. Si se usa la segunda versión, el archivotiene nombre Ident. Ejemplo:

# TERMINAL Cadena // archivo con expresión regular: cadena.er# TERMINAL BloqueDeCodigo : BlqCod // archivo con expr reg: blqcod.er

Al generar el analizador lexicográfico, se agregarán líneas que#incluirán al archivo .CMM generado por AFD. Para los ejemplos dados segenera:

# include "Cadena.cmm" // afdCadena# include "BlqCod.cmm" // afdBloqueDeCodigo

Si usa acentos o ñ en el primer Ident entonces luego tendrá problemas alcompilar el C++ generado.

IGNORAR

dos posibilidades:

'#' 'IGNORAR' Ident ':' Ident

ó

'#' 'IGNORAR' Ident

Esta directiva define a Ident como un componente léxico que puedeaparecer en el archivo fuente que analizará el analizador sintáctico generado,

Documentación de SLR1 versión 2.x

141

Page 142: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

pero que deberá ser ignorado por el analizador lexicográfico que utilizará éseanalizador sintáctico. Si se usa la primera versión (la que tiene ':') entonces elIdent de más a la derecha es el nombre del archivo que contiene la expresiónregular que lo define, el cual deberá ser procesado por AFD v 3.x. Si se usa lasegunda versión, el archivo tiene nombre Ident. Ejemplo:

# IGNORAR Cadena // archivo con expresión regular: cadena.er# IGNORAR BloqueDeCodigo : BlqCod // archivo con expr reg: blqcod.er

Al generar el analizador lexicográfico, se agregarán líneas que#incluirán al archivo .CMM generado por AFD. Para los ejemplos dados segenerará:

# include "Cadena.cmm" // afdCadena# include "BlqCod.cmm" // afdBloqueDeCodigo

Si usa acentos o ñ en el primer Ident entonces luego tendrá problemas alcompilar el C++ generado.

ELEMPILA

'#' 'ELEMPILA' Ident

Esta directiva define a Ident como la clase que implementará elelemento de la pila del analizador sintáctico generado. Por ejemplo, si en elarchivo .GLC se define:

# ELEMPILA ClaseElementoDeLaPila

En el archivo .CMM generado, en el prototipo de la función que realizalas acciones semánticas se cambiará el parámetro Pila así:

void AccSem( Ent16ns NumRegla, ClaseElementoDeLaPila * Pila, Ent16ns PP )

Debe recordar #incluir la declaración de la ClaseElementoDeLaPila alcomienzo del archivo .CMM, ya sea a través del bloque previo a las accionessemánticas o bien a través de un #include del archivo .H agregado a mano enel archivo .CMM. En teoría, el #include o la definición de la clase debe estaren el bloque de código previo a las acciones semánticas.

4. Conjunto de reglas con sus correspondientes acciones semánticas.

Las reglas dadas en la metagramática son ejemplos de escritura de lasmismas, comienzan con un identificador a la izquierda y terminan con unpunto y coma. Si hay varias reglas que tienen el mismo identificador a la

Documentación de SLR1 versión 2.x

142

Page 143: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

izquierda, pueden ser agrupadas usando el símbolo | de separación dealternativa. Por ejemplo, el grupo de reglas siguiente:

CodAccSem ---> '*' Ident ;CodAccSem ---> BlqCod ;CodAccSem ---> ;

puede ser agrupado así:

CodAccSem ---> '*' Ident | BlqCod | ;

que son tres reglas escritas de manera simplificada.

Las acciones semánticas se especifican usando bloques de códigos o*IdentBlqCod donde IdentBlqCod es un identificador definido con lasentencia #ACCSEM. Como ejemplo se incluye una porción del archivoGRAM.GLC:

Directiva ---> '#' 'ACCSEM' Ident BlqCod %{ NodoLSE<DescrAccSem> * p; p = new NodoLSE<DescrAccSem>; if (p == 0) return; p->Dato.Ident << $3.CadTerm; // inicializa nodo descriptor p->Dato.TxtAccSem << $4.CadTerm; p->pSig = pGram->TablaAccSem.Entrada; // engancha al comienzo pGram->TablaAccSem.Entrada = p; }% | '#' 'TERMINAL' Ident ':' Ident *ExpRegIdNom | '#' 'TERMINAL' Ident *ExpRegId | '#' 'IGNORAR' Ident ':' Ident *ExpRegIdNom | '#' 'IGNORAR' Ident *ExpRegId | '#' 'ELEMPILA' Ident %{ pGram->ClaseElemPila << $3.CadTerm; }%;

En el ejemplo dado hay 6 reglas resumidas usando el símbolo |. Hay bloquesde códigos (entre %{ y }%) que especifican acciones semánticas que debenejecutarse al reducir por esa regla, también se usa *Ident, donde Ident fuedefinido previamente usando la sentencia #ACCSEM (ver archivoGRAM.GLC).

Para el acceso a los símbolos actuales de la regla se debe utilizar elsímbolo $ dentro del bloque de código. Por ejemplo, para la primera regla delejemplo:

Directiva ---> '#' 'ACCSEM' Ident BlqCod

$$ referencia Directiva,

$3 referencia a Ident, y

Documentación de SLR1 versión 2.x

143

Page 144: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

$4 referencia a BlqCod.

En general, $N, con 1 <= N <= Longitud de la regla, referencia alsímbolo que está en la posición N de la parte derecha de la regla. No seefectúan chequeos de contorno, por lo que debe tener cuidado de que N no seamayor que la longitud de la regla. En particular, $$ referencia a la parteizquierda de la regla, posición que es compartida con $1.

La expansión de $X a código C++ es como sigue:

$$ expande a Pila[PP+1] dentro de la función AccSemXXX.

$N expande a Pila[PP+N] dentro de la función AccSemXXX.

Vea como ejemplo el archivo GRAM.GLC, donde se ilustra la escriturade una gramática.

12.4 Descripción del archivo .CMM generado

El archivo .CMM generado consta de 3 partes:

Bloque de código previo a las acciones semánticas.

Función de acciones semánticas.

Definición del analizador léxico.

El bloque de código previo a las acciones semánticas es unatranscripción literal del que se especificó en la gramática fuente (archivo.GLC), sólo que se quitaron los %{ y }%.

La función de acciones semánticas agrupa las acciones semánticasdefinidas en el archivo .GLC. El prototipo es el siguiente:

void AccSemXXX( Ent16ns NumRegla, ElemPila * Pila, Ent16ns PP );

donde:

XXX: es el sufijo usado durante la generación.

Ent16ns: es un typedef que corresponde a un tipo entero no signado de 16 bits. Se define en TIPOS.H que se incluye más adelante.

Documentación de SLR1 versión 2.x

144

Page 145: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

NumRegla: es el número de regla por la que se va a reducir.

ElemPila: es el tipo de elementos de la pila del analizador sintáctico.

Pila: es la pila, implementada en vector.

PP: es el puntero de pila, índice para acceder al vector Pila.

La función consta de una sola sentencia switch, que pregunta por elnúmero de regla por la que se va a reducir. Dentro del mismo verá cases con elnúmero de regla, y a la par, como comentario, la regla en formato texto paraque cualquiera lo pueda leer sin necesidad de conocimientos profundos. En elcaso de que se haya usado la sentencia ACCSEM, verá varios cases seguidos(uno en cada línea), que significa que todas esas reglas tienen la misma acciónsemántica. Los $X dentro de las acciones semánticas se expandieron aPila[PP+X]; ya fueron documentados más atrás.

Esta función será usada en la construcción del analizador sintáctico.

Para la definición del analizador lexicográfico, se generan #includes

para los símbolos terminales que serán reconocidos por autómatas finitosdeterminísticos (obtenidos a partir de expresiones regulares).

A continuación se define un vector de reconocedores de símbolos quedefine al analizador lexicográfico. Cada reconocedor de símbolo ocupa unalínea de la declaración, la que comienza con "static RecSimb vrs[ ] = {". Elobjeto vrs es estático (conocido sólo en éste módulo). Los reconocedores desímbolos son cuádruplas ordenadas, en donde:

a. La primera componente es el código asignado a ése símbolo terminal,0 si el símbolo léxico debe ser ignorado. El código no debe ser tocadoya que es asignado por SLR1 y de su valor depende el correcto uso delas tablas generadas.

b. La segunda componente es un entero. Si tiene un 0 significa que elsímbolo léxico es un literal, será tratado por el analizador léxico conuna simple comparación de cadena de caracteres. Si tiene un 1significa que hay un autómata finito determinístico que reconoce alsímbolo léxico, el que será usado por el analizador lexicográfico.

c. La tercera componente es un puntero al analizador lexicográfico, quese supone fue generado por AFD v 3.x o posterior. La definición decada autómata se encuentra en el archivo .CMM que genera AFD ycuyos include se dieron previamente en éste archivo. Usted puede

Documentación de SLR1 versión 2.x

145

Page 146: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

construir sus propios autómatas finitos determinísticos, pero debetener cuidado de no producir errores. Si la segunda componente tenía0, esta componente tendrá 0.

d. La cuarta componente es una cadena de caracteres C++ que contieneel literal del símbolo léxico. Si la segunda componente tenía 1entonces encontrará un 0 en esta componente. Si tenía un 0 entoncesencontrará una cadena. En el caso de que un terminal no haya sidocorrectamente definido usando la sentencia #TERMINAL, apareceráluego de ésta componente un mensaje que le indicará que debeconstruir/modificar éste reconocedor de símbolo para que no se tomea ése terminal como palabra clave.

Una vez definido el conjunto de reconocedores de símbolos se define elnúmero de elementos del mismo (NUMRECSIMB) y seguidamente elanalizador léxico a usar durante el análisis sintáctico. El mismo se construyeusando la biblioteca ExpReg de soporte de AFD v 3.x .

12.5 Descripción del archivo .EST generado

El archivo .EST generado es un archivo de texto que contiene unaversión legible de las tablas generadas. En él se muestran en ese orden losiguiente:

1. El conjunto de símbolos no terminales junto con sus respectivos códigosde uso interno del analizador sintáctico.

2. El conjunto de símbolos terminales junto con sus respectivos códigos deuso interno del analizador sintáctico. Observe que los códigos coincidencon los que aparecen como primera componente de cada elemento delvector de reconocedores de símbolos definido en el archivo .CMM.

3. A continuación se escribe la gramática. (Aparecerá sin los ';' de fin deregla).

4. Luego el conjunto de estados a partir de los cuales se construyen lastablas.

5. Finalmente las funciones acción(estado, símbolo) e ir_a(estado,

símbolo), una a la par de la otra, en formato similar el que se usa en labibliografía. Si desea imprimir la tabla bajo Windows u OS/2 utilice una

Documentación de SLR1 versión 2.x

146

Page 147: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

fuente en la que el ancho de todos los caracteres es el mismo, porejemplo Courier.

12.6 Descripción del archivo .TAB generado

El archivo .TAB es un archivo C++ que contiene las tablas de análisissintáctico LR(1) Simple. Debe ser #incluido en el módulo en donde se realizala definición del analizador sintáctico.

El archivo contiene 3 vectores. Los mismos pueden tener un sufijo XXXque es el mismo usado durante la generación del analizador sintáctico.

12.6.1 Ent16ns ntlpdXXX[ ];

Este vector de enteros sin signo de 2 bytes, contiene:

1. En el elemento 0, el byte alto es el número de símbolos no terminales yel byte bajo es el número de terminales.Estos números son usados para calcular el número de columnas de lastablas accion e ir_a (ver las tablas en archivos .EST, las columnas seindexan por símbolos terminal/no terminal).

2. En los elementos 1 en adelante, el byte alto es el código del no terminalque se halla a la izquierda de la regla cuyo número es el índice delelemento actual, y el byte bajo de éste elemento especifica el número desímbolos que hay a la derecha de la flecha (las reglas se numeran de 1 enadelante, en el orden en que aparecen en el archivo fuente .GLC).En el momento de ejecutar una reducción, se necesita la informacióncontenida en estos elementos, para desapilar la cantidad adecuada deelementos y poder indexar la columna de la tabla ir_a que requiere elcódigo del no terminal de la izquierda.

12.6.2 Ent16ns accionXXX[ ];

Este vector de enteros sin signo de 2 bytes, es la transcripción de la tablaacción que se muestra en el archivo .EST en formato más legible. La tablaacción mostrada en ese archivo comienza en el primer terminal y termina en elsímbolo FA, que también es considerado terminal. Las filas se indexan porestado, y las columnas se indexan por símbolo terminal.

Documentación de SLR1 versión 2.x

147

Page 148: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

En este vector los elementos se codifican de la siguiente manera, lo quese muestra en formato C++:

class Accion { // estructura de una acciónpublic: unsigned n : 14; unsigned cod : 2;};

La clase Accion es una estructura de 16 bits, en los cuales los 14 bitsmenos significativos son los números que aparecen luego de la letra d o r en latabla accion, y se acceden usando el campo n de esta estructura. El campo codcontiene el código de acción a ejecutar (en binario): 00 para desplazar, 01 paraaceptar y 10 para reducir. El 11 no se utiliza. En el vector observará que: elelemento que tiene el 16384 es el que corresponde a aceptar, todos loselementos menores que ese número son los de desplazamiento (aparecen conla letra d en la tabla en el archivo .EST) y todos los mayores que ese númeroson los de reducción (aparecen con la letra r en la tabla en el archivo .EST).

12.6.3 Ent16ns ir_aXXX[ ];

Este vector implementa la tabla ir_a, que en el archivo .EST se muestraa la par de la tabla acción a continuación del símbolo FA. Las columnas deesta tabla se indexan por símbolos no terminales y las filas por estados.

La tabla se almacena en el vector por filas (fila mayor). Cada elementocontiene directamente el número que se muestra en la tabla ir_a del archivo.EST.

12.7 Definición de un analizador sintáctico

Si la versión de SLR1 disponible es menor que 2.3, entonces ladefinición del analizador sintáctico se debe realizar a mano, si es igual omayor entonces la definición la realiza el mismo generador en el archivo.CMM generado.

Documentación de SLR1 versión 2.x

148

Page 149: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.7.1 Definición a mano del objeto Analizador Sintáctico

Definición en C++ significa que el objeto es declarado y reside en elámbito del lugar donde se declara.

Para definir el objeto analizador sintáctico debe #incluir el archivo.TAB con las tablas y el archivo .CMM, ambos generados por SLR1. Ejemplo:suponga que el archivo fuente con la gramática se llamaba gram.glc y que elsufijo usado fue Gram, entonces, en el módulo donde se necesite el analizadorsintáctico se hará:

// código previo del usuario...// inclusión de los módulos generados por SLR1 v 2# include "gram.cmm" // acciones semánticas y analizador lexicográfico# include "gram.tab" // tablas del analizador sintáctico SLR(1)

// más código del usuario...

// función donde se requiere el analizador:

int f( const char * TxtFuente ) { // ... // definición del analizador sintáctico: AnalSLR1<ElemPila> analizador(ntlpdGram, accionGram, ir_aGram, AccSemGram); alGram.Reiniciar(TxtFuente); Ascii0 CadPosErr; if (! analizador.Analizar(alGram, CadPosErr)) { return CODIGO_DE_ERROR; }

// ...} // fin de la función f

// más código del usuario....

El parámetro TxtFuente de la función f es una cadena de caracteresválida del C++, puede ser obtenida de la manera que se desee. Es tratada por elanalizador lexicográfico generado, que se encuentra en el archivo .CMMgenerado por SLR1 v 2.

El uso de cadenas C++ para la especificación de la entrada al analizadorsintáctico no impone obligaciones sobre el esquema de E/S a usar, que no es elcaso del YACC, el cual impone la entrada/salida estándar (stdin y stdout en C,su redireccionamiento es criptográfico y difícil de tratar).

Dado que la clase que implementa al analizador sintáctico es una clasetemplate, el parámetro ElemPila que se da entre < > es el que implementa eltipo de elemento de la pila del analizador sintáctico. Si usted usó la sentencia

Documentación de SLR1 versión 2.x

149

Page 150: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

#ELEMPILA entonces debe usar el mismo Ident allí indicado dentro de los <> en la definición del objeto analizador.

Ver el ejemplo que se incluye en este documento para más detalle deuna implementación adecuada.

12.7.2 Definición automática por versiones 2.3 o posterior

Si se usa las versiones 2.3 o posterior, la definición del analizadorsintáctico es realizada por el generador. Sólo si su aplicación lo requiere,deberá mover la definición del objeto a otro ámbito.

En estas versiones sólo se debe #incluir el archivo .CMM generado yusar los analizadores.

12.8 La clase template AnalSLR1

La clase template AnalSLR1 implementa el analizador sintáctico. Elargumento template de la clase es el tipo del elemento de la pila delanalizador. Esta clase está declarada en SLR1.H.

Lo que caracteriza al analizador sintáctico son las tablas, las que debenser dadas en el momento de la construcción del objeto analizador. Elanalizador lexicográfico no caracteriza al analizador sintáctico, por lo que selo da como parámetro al momento de realizar un análisis sintáctico, llamando ala función Analizar de esta clase.

12.8.1 Funciones miembro públicas:

AnalSLR1( Ent16ns * ntlpd, Ent16ns * accion, Ent16ns * ir_a, void (* fAccSem)( Ent16ns numregla, ELEMPILA * pila, Ent16ns pp ) = 0, void (* fLimPila)( ELEMPILA * pila, Ent16ns pp, Ent8 cumple ) = 0, void (* fVer)( const char * mensaje ) = 0 );

Este es el único constructor de la clase. Los tres primeros parámetros(ntlpd, accion e ir_a) son los objetos que aparecen en el archivo .TABgenerado. Si se especificó un sufijo al procesar la gramática, el prefijoutilizado es exactamente igual a éstos (por ejemplo, si el sufijo era Expr

entonces tenemos ntlpdExpr, accionExpr e ir_aExpr, respectivamente).

El parámetro fAccSem es la función que realizará el análisis semántico,debe especificar aquí la función que fue generada en el archivo .CMM

Documentación de SLR1 versión 2.x

150

Page 151: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

generado. Por defecto este parámetro vale 0, lo que significa que no hayacciones semánticas. Puede no especificarlo.

fLimPila es una función que limpia la pila del analizador sintáctico. SiELEMPILA es una clase distinta de ElemPila entonces puede ser necesarioefectuar ciertas acciones especiales para la correcta destrucción de loselementos de la pila. Esas acciones especiales lo puede realizar esta función,aunque siempre es preferible que el trabajo de la correcta destrucción de loselementos sea hecho por el destructor de su clase. El parámetro cumple tiene 0si la cadena analizada sintácticamente no cumple con la estructura definida porla gramática del lenguaje, y distinto a 0 si es sintácticamente correcta.

fVer esta función sirve para mostrar las distintas acciones que se vanejecutando durante el análisis sintáctico. La función recibe un parámetro quees una cadena de texto con la descripción de la acción.

Ent8 Analizar( AnaLex & analex, Ascii0 & CadErr, Ent16ns MaxPila = 50 );

Esta función es la que realiza el análisis sintáctico. El parámetro analexes el analizador lexicográfico, el cual debe estar previamente inicializado.

El analizador lexicográfico puede ser cambiado en tiempo de ejecución,pero debe tener cuidado de que los códigos de símbolos que devuelva lafunción AnaLex::Examinar sean los que espera este analizador sintáctico.

CadErr es el objeto donde se devuelve la cadena con la posición dondese produjo el error léxico. Debido a que el acceso al objeto pasado en analexes posible en éste ámbito, se puede tener un completo informe de la posicióndonde se produjo el error a través del mismo. Consulte la documentación de labiblioteca ExpReg.

TamPila es el tamaño de la pila del analizador sintáctico LR(1) simple.Por defecto es 50, si hace falta una más grande o más chica entoncesespecifique un valor nuevo.

La función devuelve 1 si la oración es sintácticamente correcta, 0 si essintácticamente incorrecta. En el miembro dato CodError devuelve un códigode error. Los códigos son los siguientes (acceder desde otro ámbito usando lasintaxis AnalSLR1<ELEMPILA>:: ):

0: no hay problemas.

Documentación de SLR1 versión 2.x

151

Page 152: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ERRORLEX: error léxico, puede utilizar el analizador lexicográfico paraobtener mayor información.

TERMINESP: terminal inesperado. El terminal siguiente es válido pero está enuna posición sintácticamente incorrecta.

PILACHICA: el tamaño de la pila del analizador sintáctico especificado porTamPila es chico. Pruebe pasar un valor mayor que el que fue especificado.

ERRORENTABLAS: hay un problema en las tablas (puede haber sidoprovocado por una modificación manual de las mismas).

12.8.2 Campos dato públicos:

Ent16ns CodError;

En este campo se devuelve el código de error devuelto luego de realizarel análisis sintáctico, un valor entero sin signo.

12.8.3 Campos dato protegidos:

Ent16ns * ntlpd, Ent16ns * accion, Ent16ns * ir_a;void (* fAccSem)( Ent16ns numregla, ELEMPILA * pila, Ent16ns pp );void (* fLimPila)( ELEMPILA * pila, Ent16ns pp, Ent8 cumple );void (* fVer)( const char * mensaje );

ntlpd, accion, e ir_a son las tablas del analizador sintáctico que fuerongeneradas en el archivo .CMM.

fAccSem es un puntero a la función que realiza las acciones semánticas.

fLimPila es un puntero a una función auxiliar que ayuda a una correctalimpieza de los elementos de la pila.

fVer es una función que sirve para seguir paso a paso el trabajoefectuado por el analizador sintáctico.

Documentación de SLR1 versión 2.x

152

Page 153: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.9 Clase SimboloSLR1

Esta clase está declarada en SLR1.H. Implementa un símbolo de unagramática. La declaración es muy pequeña y se transcribe a efectos desimplificar la documentación:

class SimboloSLR1 {public: Ent8ns Id; Ent8ns NoTerminal; SimboloSLR1() { Id = NoTerminal = 0; }};

El campo Id es el código asignado al símbolo terminal/no terminal. Loscódigos son asignados por SLR1.

El campo NoTerminal tiene 0 si el símbolo es terminal, distinto a 0 sies no terminal.

Por defecto ambos campos valen 0, valores reservados para el símboloterminal Fin de Archivo.

12.10 Clase ElemPila

Esta clase define la estructura por defecto del elemento de la pila delanalizador sintáctico SLR(1). Está declarada en SLR1.H y su declaración setranscribe:

class ElemPila { public: SimboloSLR1 Simb; Ent16ns Estado; Ascii0 CadTerm; ElemPila( ) { Estado = 0; }};

Simb es el símbolo que se encuentra en esta posición de la pila.

Estado es el estado del analizador en esta posición de la pila.

CadTerm es la cadena de caracteres del terminal apilado (sólo si elsímbolo de ésta posición de la pila era terminal). Al hacer un desplazamientose guarda en este campo una copia de la cadena de caracteres devuelta por elanalizador lexicográfico. Debido a que el destructor de Ascii0 hace la correctadevolución de la memoria dinámica usada por la cadena es que no hace faltautilizar la función fLimPila para la limpieza de la pila.

Documentación de SLR1 versión 2.x

153

Page 154: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Si va a usar una definición alternativa de la clase que implementa elelemento de la pila del analizador, recuerde que:

1. el símbolo debe ser implementado por una clase derivada deSimboloSLR1 y el nombre del campo debe ser Simb.

2. el campo Estado debe ser declarado exactamente igual a como se declaraen esta clase.

3. el campo CadTerm debe ser declarado exactamente igual a como sedeclara en esta clase.

4. incluir SLR1.H, no modificar este archivo.

12.11 Consideraciones a tener el cuenta para el uso de gramáticasambiguas

El uso de gramáticas ambiguas puede dar como resultado tablas máspequeñas, lo que reduce el espacio de memoria necesario para almacenarlas.Pero el nivel de conocimiento necesario para poder resolver los conflictos esdemasiado elevado.

En la automatización de la generación de programas el objetivo es queel usuario (en este caso el programador) no pierda tiempo aprendiendo cosasque no hacen falta, ya que el generador hace ese trabajo y lo hace bien. El usode gramáticas ambiguas imposibilita cumplir ese objetivo, y por lo general, elresultado no es "mucho mejor" que el de usar gramáticas no ambiguas. Engeneral, la diferencia obtenida es infinitesimal y no justifica perder el tiempodada la disponibilidad de memoria en las computadoras actuales y la velocidadde procesamiento de las mismas.

Hay gramáticas que no son ambiguas, pero presentan conflictos pasa latécnica de análisis LR(1) Simple debido a la forma de trabajo del algoritmo (esdecir, es ambigua para la técnica SLR(1) ). La gramática para la sentenciasi...entonces...sino... es no ambigua pero presenta un conflicto dedesplazamiento/reducción con el símbolo sino y la regla SentSi --> si Expr

entonces Sent. (Nota: en este caso se debe elegir desplazar sino). El conflictode desplazamiento/reducción que provoca esta gramática hace que SLR1genere un analizador sintáctico para esa gramática que pueda construir 2posibles árboles de análisis sintáctico para una oración que tenga la partesino..., y es por eso que decimos que es ambigua para la técnica LR(1) Simple.

Documentación de SLR1 versión 2.x

154

Page 155: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.12 Desarrollo de un proyecto de programación con SLR1 v 2.x

El proyecto a desarrollar es un sistema para la verificación de la validezde un esquema deductivo del cálculo proposicional.

Para que un esquema deductivo sea válido debe primero sersintácticamente correcto (aquí usaremos SLR1). Luego, la validez puede serdemostrada de dos maneras: utilizando la Teoría de la Demostración outilizando la Teoría Semántica del Cálculo Proposicional. En este ejemplo seutilizará la Teoría Semántica del Cálculo Proposicional.

En la Teoría Semántica del Cálculo Proposicional, un sistema deductivoes válido cuando la implicación asociada a éste es tautología.

Entonces, para verificar la validez de un esquema deductivo seejecutarán las siguientes operaciones:

1. Primero se realizará el análisis sintáctico del esquema deductivo fuente,a efectos de detectar errores sintácticos.

2. Luego se traducirá el esquema deductivo a su implicación asociada, laque será internamente almacenada en un vector en notación postfijo, aefectos de facilitar su posterior evaluación. Al traducir se generará unatabla con todas las variables que figuran en la fórmula.

3. A continuación se comprueba si la implicación asociada es unatautología, para lo cual se van generando las interpretaciones posiblespara las variables que aparecen en la fórmula, y para cada una secomprueba el valor de verdad de la fórmula. Si para algunainterpretación la fórmula da falso, la misma no es tautología. Si ocurreque la fórmula si es tautología, el esquema deductivo es válido.

4. Se informa el resultado del paso 3.

La secuencia de pasos que se siguieron para la escritura y utilización dela gramática fue:

a. Primero se escribe el archivo ED.GLC que tiene la gramática con lascorrespondientes acciones semánticas en cada regla y con lasespecificaciones necesarias para la construcción automática delanalizador lexicográfico.

b. Se procesa ED.GLC con SLR1 v 2 usando "EsqDed" como sufijo y seobtienen así los archivos ED.CMM y ED.TAB. En ED.CMM están

Documentación de SLR1 versión 2.x

155

Page 156: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

las acciones semánticas y el analizador lexicográfico. En ED.TABestán las tablas a incluir.

c. Se procesan los archivos .ER con las expresiones regulares paraobtener los correspondientes .CMM, cuyos #includes están enED.CMM y fueron automáticamente escritos por SLR1 v 2.

d. Se escribe el archivo VESQDED.CMM que valida un esquemadeductivo. En ese archivo se incluyen las líneas que se indicaronanteriormente para el correcto compilamiento.

e. Se compila VESQDED.CMM y, eureka, eso es todo.

Los archivos importantes que componen el proyecto son los que seenumeran a continuación, y son independientes del sistema operativo en el quese implemente la aplicación:

ED.GLC: entrada para SLR1 v 2.x. La salida de SLR1 son los archivosED.CMM y ED.TAB que deben ser incluidos en el módulo donde seráutilizado el analizador sintáctico (VESQDED.CMM).

ED.CMM: salida de SLR1 al especificar como entrada a ED.GLC.

ED.TAB: salida de SLR1 al especificar como entrada a ED.GLC.

EVALUAR.CMM: en este módulo se dan las funciones para evaluar unafórmula bien formada del cálculo proposicional dada en notación postfijo.

ASIGINT.CMM: en este módulo se da una función que traduce unainterpretación codificada en binario, cargando en cada variable de la tablade símbolos dada el valor de verdad correspondiente.

TAUTO.CMM: en este módulo se da una función que verifica si unafórmula dada en notación postfijo es o no tautología.

VESQDED.CMM: en este módulo se da una función que verifica unesquema deductivo dado como entrada. Se podría considerar a este módulocomo el principal.

ESQDED.H: este es un archivo cabecera en donde se declaran las clases yprototipos de las funciones desarrolladas, a los efectos de poder reusarfácilmente los módulos fuentes escritos.

SLR1.H: declaración las clases necesarias para realizar el análisis sintáctico.Viene provisto junto con SLR1 v 2.x.

Documentación de SLR1 versión 2.x

156

Page 157: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

EXPREG.H: declaración de las clases necesarias para realizar el análisislexicográfico. Viene provisto junto con AFD v 3.x.

EXPREG.LIB: biblioteca de soporte de AFD v 3.x.

BCE.LIB: biblioteca auxiliar. Se usa la clase Ascii0 únicamente. Suinclusión es además requerida por EXPREG.LIB.

La interfase con el usuario final de la aplicación ha sido generada con elApplication Expert (AppExpert) del Turbo C++ 4.5 para Windows; laaplicación correrá sin problemas en Windows 3.1 en adelante, incluyendo aWindows NT. El código generado puede ser recompilado sin problemasusando el Borland C++ 2.0 para OS/2, y obtener así una versión que correrá enOS/2 2.1 y OS/2 Warp, pero se debe tener cuidado con ese C++ puesto que esde 32 bits (en C++ no se dan especificaciones sobre la implementación de lostipos de datos fundamentales, la misma queda a elección del fabricante delcompilador; por ejemplo, en C++ para Win16 el tamaño del tipo int es de 16bits y en C++ para OS/2 y Win32 es de 32 bits).

La aplicación generada es un editor multitexto (se pueden editar variostextos a la vez) con todas las funciones de un editor de textos, y en el menúarchivo se agregó una opción para "Verificar validez" del esquema deductivoque se encuentra en la ventana de texto actual (la que se encuentre activa). Lageneración de la aplicación es en realidad más simple de lo que se puedaentender a partir de la lectura de este documento (fue muy fácil), y es esa larazón por la que se eligió AppExpert para diseñar la interfase.

Los archivos generados son:

EDAPP.CMM: módulo principal.

EDEDITVW.CMM: clase que maneja un objeto editor de texto. A estemódulo se lo modificó para procesar la opción "Verificar validez".

EDMDICLN.CMM: clase para manejar un objeto cliente de un objeto MDI.

EDMDICHL.CMM: clase para manejar un objeto hijo de un objeto MDI.

APXPREV.CPP: presentación preliminar de un documento editado.

APXPRINT.CPP: objeto para imprimir un documento.

EDABTDLG.CPP: ventana Acerca de... de la aplicación.

APXPREV.H: cabecera de APXPREV.CPP.

Documentación de SLR1 versión 2.x

157

Page 158: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

APXPRINT.H: cabecera de APXPRINT.CPP.

EDABTDLG.H: cabecera de EDABTDLG.CPP

EDAPP.H: cabecera de EDAPP.CMM.

EDEDITVW.H: cabecera de EDEDITVW.CMM.

EDMDICLN.H: cabecera de EDMDICLN.CMM.

EDMDICHL.H: cabecera de EDMDICHL.CMM.

La clase EDEditView, cuya definición está en EDEDITVW.CMM, yque sirve para manejar una vista de un documento de texto (el generadorAppExpert da soporte al modelo documento/vista introducido por Borland ensus C++ desde la versión 4.0 para Windows y 2.0 para OS/2), fue modificadapara manejar el evento CM_VERIFICAR que se genera al seleccionar laopción "Verificar validez". La función agregada es la VerificarValidez de estaclase, cuya declaración y prototipado inicial fue realizado por ClassExpert, eladministrador de clases de AppExpert. La función se transcribe acontinuación, y el código agregado es el que está después del comentario //INSERT>>... y termina en la llamada a MessageBox final. (Se aclaranuevamente que el resto del código, salvo dos líneas que se encuentran alcomienzo de éste módulo, no ha sido escrito por el autor).

void EDEditView::VerificarValidez (){ // INSERT>> Your code here. // Primero sacar el texto del EditView de Windows Ent16ns tam = GetTextLen() + 1; Ascii0 cad(tam); if (! GetText(cad, tam)) return; // si no hay texto editado

// Luego llamar a la función que verifica validez: int r = ValidarEsqDed(cad);

// y finalmente se informa el resultado: const char * msj = "CODIGO DESCONOCIDO"; uint icono = MB_OK; switch (r) { case EDVAL: msj = "El esquema deductivo es VALIDO."; icono |= MB_ICONINFORMATION; break; case EDINVAL: msj = "El esquema deductivo es INVALIDO."; icono |= MB_ICONEXCLAMATION; break; case EDERROR: msj = "Error sintáctico en el fuente."; icono |= MB_ICONQUESTION; break; } MessageBox(msj, "Resultado del análisis", icono);}

Documentación de SLR1 versión 2.x

158

Page 159: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La única sentencia importante en esta función es la llamada aValidarEsqDed, que es la función que actualmente ejecuta toda la operaciónde validación. Todas las sentencias antes de ésta sirven para extraer el textodel objeto ventana editor del Windows (a través de la clase TEdit, clase basede TEditView y EDEditView). El código siguiente a la llamada aValidarEsqDed es el que presenta el resultado en una ventana de mensajes. Elproblema de obtener el texto de entrada e informar el resultado de lavalidación es un problema aparte, y se puede realizar como uno quiera y en elsistema operativo que desee.

También se agregaron dos líneas más al comienzo del móduloEDEDITVW.CMM, que son las siguientes:

# include <ascii0.h> // de BCE# include "esqded.h" // de esta aplicación

Los .h incluidos hacen posible la utilización de la clase Ascii0 (paraobtener el texto) y de la función ValidarEsqDed (que no está definida en estemódulo).

El código restante (enumerado en el primer grupo de módulos fuentes)es el que realiza todo el trabajo de validación. No contempla la forma deobtener el texto ni la forma de emitir mensajes (ambas dependientes delsistema operativo). Este conjunto de módulos fuentes son independientes delsistema operativo, inclusive son independiente de si trabaja con código ANSIu OEM (los editores de Windows trabajan con OEM, los de DOS y algunos deOS/2 con ANSI).

En el lenguaje de entrada cuya gramática está dada en ED.GLC, elsímbolo # sirve para indicar que a continuación viene la conclusión, la comasepara a las premisas (debe haber por lo menos una). Cada premisa debe seruna fórmula bien formada del cálculo proposicional. El símbolo <==> seutiliza para la doble implicación, el ==> se utiliza para el la implicación, el +para la disyunción, el * para la conjunción, el - para la negación y los ( ) parala asociatividad y ruptura de precedencia. Los tres siguientes son ejemplos deesquemas deductivos reconocibles por la gramática dada:

Ejemplo 1:

p ==> q, p # q

Documentación de SLR1 versión 2.x

159

Page 160: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ejemplo 2:

-p + q, p # q

Ejemplo 3:

- ( p * r ), q ==> r, q # -p

Los esquemas dados le pueden ser familiares. Los puede encontrar encualquier libro de lógica.

La forma en que se escriban las fórmulas no debe ser importante,inclusive los espacios que se dejan entre ellas. Este problema será resuelto porel analizador lexicográfico generado.

La función que verifica si la fórmula proposicional en notación postfijoes tautología se llama Tautologia y se encuentra definida en el móduloTAUTO.CMM. La misma genera interpretaciones de las variables queaparecen en la fórmula hasta encontrar alguna interpretación para la que lafórmula dé falso. La interpretación (un juego de valores de verdad asignado alas variables de la fórmula) se codifica en un número binario de 16 bits, endonde el bit 0 tiene el valor de verdad de la variable tds[0], el bit 1 a tds[1], yasí sucesivamente. Como el número tiene 16 bits, a lo sumo pueden haber 16variables posibles. El pasaje de binario a la tabla de símbolos de unainterpretación lo realiza la función AsigInterp definida en ASIGINT.CMM.La función Evaluar realiza la evaluación de una fórmula proposicional dadaen postfijo para una interpretación dada.

Más documentación puede encontrar en los archivos fuente. Acontinuación se transcriben los módulos fuentes enumerados en el primergrupo de módulos fuentes, que son los que realmente se escribieron para estaaplicación. Los demás módulos fueron generados automáticamente, y sólo sonimportantes las líneas transcriptas a éste documento, y por tal razón no seincluyen aquí.

Documentación de SLR1 versión 2.x

160

Page 161: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.13 Módulos fuentes escritos para el proyecto

12.13.1 ED.GLC

// Gramática para la carga en memoria en notación postfijo de// un esquema deductivo del cálculo proposicional.// Creación: 04 Dic 95 - Versión 2 - Para SLR1 v 2.x// Especificar EsqDed como sufijo en SLR1.

%{# include <string.h>

# ifndef __ESQDED_H# include "esqded.h"# endif

SimbFormProp fnp[50], // fórmula en notación postfijo tds[16]; // tabla de símbolosunsigned ifnp = 0, itds = 0; // primer elemento libre en fnp y tdsrespectivamente.

// int AgregarTDS( const char * s );// Agrega s a la tabla de símbolo. s es la cadena que identifica alsímbolo.// Si la variable ya existe en la tabla entonces no lo agrega.// Siempre devuelve el código asignado a la variable, que es un número// entre 1 y 16.

int AgregarTDS( const char * s ) { register int i; for (i = 0; i < itds; ++i) if (! strcmp(tds[i].var, s)) break; if (i == itds) { strncpy(tds[itds].var, s, 10); tds[itds].valor = 0; ++itds; tds[itds].cod = itds; return itds; // devuelve el código que se le asigna } return tds[i].cod; // dev. el cód. asignado anteriormente}

}%

# TERMINAL Variable : Var // Expr regular en var.er# TERMINAL DobleImpl : DImpl // Expr regular en dimpl.er# TERMINAL Implica : Impl // Expr regular en impl.er# IGNORAR Blancos : Blanco // Expr regular en blanco.er# IGNORAR Comentarios : Coment // Expr regular en coment.er

// Para las reglas// E --> Prem '#' F ;// I --> I Implica D ;# ACCSEM ACImplicación %{ fnp[ifnp].cod = SimbFormProp::IMPLIC; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "==>"); ++ifnp; }%

// Para las reglas// Prem --> Prem ',' F ;

Documentación de SLR1 versión 2.x

161

Page 162: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// C --> C '*' Prop ;# ACCSEM ACConjunción %{ fnp[ifnp].cod = SimbFormProp::CONJUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "*"); ++ifnp; }%

E --> Prem '#' F *ACImplicación;

Prem --> Prem ',' F *ACConjunción;

Prem --> F ;

F --> F DobleImpl I %{ fnp[ifnp].cod = SimbFormProp::DOBLEIMPL; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "<==>"); ++ifnp; }%;

F --> I ;

I --> I Implica D *ACImplicación;

I --> D ;

D --> D '+' C %{ fnp[ifnp].cod = SimbFormProp::DISYUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "+"); ++ifnp; }%;

D --> C ;C --> C '*' Prop *ACConjunción;

C --> Prop ;

Prop --> Constante %{ fnp[ifnp].cod = SimbFormProp::CONSTANTE; fnp[ifnp].valor = strcmp($1.CadTerm, "0"); strncpy(fnp[ifnp].var, $1.CadTerm, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; }%;

Prop --> Variable %{ // Escribir en la expresión en notación postfijo fnp[ifnp].cod = AgregarTDS($1.CadTerm); // agrega a tds y asigna elcódigo fnp[ifnp].valor = 0; strncpy(fnp[ifnp].var, $1.CadTerm, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; }%;

Prop --> '(' F ')' ;

Prop --> '-' Prop %{ fnp[ifnp].cod = SimbFormProp::NEGAR; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "-"); ++ifnp; }%;

Documentación de SLR1 versión 2.x

162

Page 163: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Constante --> '0' | '1';

12.13.2 ED.CMM

// Código fuente generado por SLR1 versión 2.1 (Nov 95)// Domingo Eduardo Becker, Sgo. del Estero, Tel (085) 22-2488

// Código de acciones semánticas.// Código generado por Gramatica::ImprAccSem versión 2.// Domingo Eduardo Becker.

# ifndef __SLR1_H# include "slr1.h"# endif

// Código fuente previo a las acciones semánticas.# include <string.h># ifndef __ESQDED_H# include "esqded.h"# endif

SimbFormProp fnp[50], // fórmula en notación postfijo tds[16];// tabla de símbolosunsigned ifnp = 0, itds = 0; // primer elemento libre en fnp y tdsrespectivamente.

// int AgregarTDS( const char * s );// Agrega s a la tabla de símbolo. ses la cadena que identifica al símbolo.// Si la variable ya existe en la tabla entonces no lo agrega.// Siempre devuelve el código asignado a la variable, que es un número// entre 1 y 16.

int AgregarTDS( const char * s ) { register int i; for (i = 0; i < itds; ++i) if (! strcmp(tds[i].var, s)) break; if (i == itds) { strncpy(tds[itds].var, s, 10); tds[itds].valor = 0; ++itds; tds[itds].cod = itds; return itds; // devuelve el código que se le asigna } return tds[i].cod; // dev. el cód. asignado anteriormente}

// Fin del código fuente previo ...

void AccSemEsqDed( Ent16ns NumRegla, ElemPila * Pila, Ent16ns PP ) { switch (NumRegla) { case 4: // F ---> F DobleImpl I { fnp[ifnp].cod = SimbFormProp::DOBLEIMPL; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "<==>"); ++ifnp; } break;

case 8: // D ---> D '+' C { fnp[ifnp].cod = SimbFormProp::DISYUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "+"); ++ifnp; } break;

Documentación de SLR1 versión 2.x

163

Page 164: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case 12: // Prop ---> Constante { fnp[ifnp].cod = SimbFormProp::CONSTANTE; fnp[ifnp].valor = strcmp(Pila[PP+1].CadTerm, "0"); strncpy(fnp[ifnp].var, Pila[PP+1].CadTerm, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; } break;

case 13: // Prop ---> Variable { // Escribir en la expresión en notación postfijo fnp[ifnp].cod = AgregarTDS(Pila[PP+1].CadTerm); // agrega a tds yasigna el código fnp[ifnp].valor = 0; strncpy(fnp[ifnp].var, Pila[PP+1].CadTerm, 10); fnp[ifnp].var[9] = 0; // asegura terminación en 0 ++ifnp; } break;

case 15: // Prop ---> '-' Prop { fnp[ifnp].cod = SimbFormProp::NEGAR; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "-"); ++ifnp; } break;

case 2: // Prem ---> Prem ',' F case 10: // C ---> C '*' Prop { fnp[ifnp].cod = SimbFormProp::CONJUN; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "*"); ++ifnp; } break;

case 1: // E ---> Prem '#' F case 6: // I ---> I Implica D { fnp[ifnp].cod = SimbFormProp::IMPLIC; fnp[ifnp].valor = 0; strcpy(fnp[ifnp].var, "==>"); ++ifnp; } break; } // switch (NumRegla)} // Fin de AccSemEsqDed

// Fin del código de acciones semánticas.

// Analizador lexicográfico para la gramática.// Generado por Gramatica::ImprAnaLex versión 2.// Domingo Eduardo Becker.

# ifndef __EXPREG_H# include "expreg.h"# endif

# include "Coment.cmm" // afdComentarios# include "Blanco.cmm" // afdBlancos# include "Impl.cmm" // afdImplica# include "DImpl.cmm" // afdDobleImpl# include "Var.cmm" // afdVariable

static RecSimb vrs[] = { 1, 0, 0, "#", 2, 0, 0, ",", 3, 1, & afdDobleImpl, 0, 4, 1, & afdImplica, 0, 5, 0, 0, "+",

Documentación de SLR1 versión 2.x

164

Page 165: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

6, 0, 0, "*", 7, 1, & afdVariable, 0, 8, 0, 0, "(", 9, 0, 0, ")", 10, 0, 0, "-", 11, 0, 0, "0", 12, 0, 0, "1", 0, 1, & afdComentarios, 0, 0, 1, & afdBlancos, 0};

# define NUMRECSIMB 14

AnaLex alEsqDed(vrs, NUMRECSIMB);

12.13.3 ED.TAB

No se incluye porque su lectura es complicada y es un archivo generablea partir de ED.GLC listado previamente.

12.13.4 EVALUAR.CMM

// evaluar.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"# include <string.h>

// int ValorDe( const char * s, const SimbFormProp * tds, unsigned ttds );// Esta función busca el símbolo cuya cadena es s en el vector tds cuyo// tamaño es ttds.// Debido a que para la comparación de cadenas se usa strcmp, se hace// diferencia entre mayúsculas y minúsculas.// La función devuelve el valor de verdad asignado a la variable.

static int ValorDe( const char * s, const SimbFormProp * tds, unsigned ttds ) { register int i; for (i = 0; i < ttds; ++i) if (! strcmp(s, tds[i].var)) break; if (i == ttds) return 0; else return tds[i].valor;}

// int Evaluar( char p, char q, int operacion );// Evaluar evalúa la operacion pasada como parámetro a partir de los// operandos p y q.// En p y q debe venir 0 si es falso o distinto a 0 si es verdadero.// La función devuelve 0 si el resultado de la operación es falso y// distinto a 0 si el resultado de la operación es verdadero.// La operación se codifica con la enumeración dada en simbolo.h dentro// de la clase SimbFormProp, y se acceden desde cualquier lugar usando el// operador :: para romper ámbitos. Ellos son:// DOBLEIMPL: <==> doble implicación, binario, p <==> q

Documentación de SLR1 versión 2.x

165

Page 166: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// IMPLIC: ==> implicación, binario, p ===> q// DISYUN: + disyunción, binario, p + q// CONJUN: * conjunción, binario, p * q// NEGAR: - negación, unario, - p

int Evaluar( char p, char q, int operacion ) { p = p ? 1 : 0; // llevar a 0 o 1 q = q ? 1 : 0; register int r = 0; switch (operacion) { case SimbFormProp::DOBLEIMPL: // <==> r = ! (p ^ q); break;

case SimbFormProp::IMPLIC: // ==> r = ! p | q; break;

case SimbFormProp::DISYUN: // + (disyunción) r = p | q; break;

case SimbFormProp::CONJUN: // * (conjunción) r = p & q; break;

case SimbFormProp::NEGAR: // - (negación) r = ! p; break; } return r;}

// int Evaluar( const SimbFormProp * fnp, unsigned tfnp,// const SimbFormProp * tds, unsigned ttds );// Evaluar evalúa la expresión en postfijo pasado en el vector fnp, cuyo// tamaño es tfnp.// La interpretación a utilizar es la que viene en la tabla de símbolostds,// cuyo tamaño es ttds.// La función devuelve 0 si la fórmula bien formada en notación postfijofnp// es falsa para la interpretación dada, y distinto a 0 si es verdadera.// El algoritmo que se usa para evaluar la expresión en notación postfijo// puede ser encontrado en cualquier libro de Estructuras de datos y// Algoritmos.

int Evaluar( const SimbFormProp * fnp, unsigned tfnp, const SimbFormProp * tds, unsigned ttds ) { char pila[20], pp = 0; register unsigned ifnp; for (ifnp = 0; ifnp < tfnp; ++ifnp) { if (fnp[ifnp].cod > SimbFormProp::MAXVAR && fnp[ifnp].cod < SimbFormProp::ULTIMOOPERADOR) { // efectuaroperación if (fnp[ifnp].cod == SimbFormProp::NEGAR) { // operación unaria, desapila 1 y apila el resultado pila[pp - 1] = Evaluar(pila[pp-1], 0, fnp[ifnp].cod); } else { // operación binaria, desapila 2 y apila el resultado pila[pp - 2] = Evaluar(pila[pp-2], pila[pp-1], fnp[ifnp].cod); --pp; } } else pila[pp++] = ! fnp[ifnp].cod ? fnp[ifnp].valor

Documentación de SLR1 versión 2.x

166

Page 167: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

: ValorDe(fnp[ifnp].var, tds, ttds); } return pila[pp-1];}

12.13.5 ASIGINT.CMM

// asigint.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"

// void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv );// AsigInterp asigna a la tabla de símbolos la interpretación que viene// codificada en vv.// Si numeramos los bits de vv de 0 a 15, el bit 0 corresponde a tds[0],// el bit 1 a tds[1], ..., y el bit 15 a tds[15].// El valor de verdad de cada variable se asigna al campo valor de cada// elemento de tds.

void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv ) { register int i, bit; for (i = 0, bit = 1; i < ttds; ++i, bit <<= 1) tds[i].valor = vv & bit;}

12.13.6 TAUTO.CMM

// tauto.cmm// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 01 Nov 95

# include "esqded.h"

// int Tautologia( const SimbFormProp * fnp, unsigned tfnp,// SimbFormProp * tds, unsigned ttds );// Tautologia chequea si la fórmula bien formada del cálculo proposicional// que viene en fnp en formato notación postfijo es una tautología.// El tamaño de la fórmula es tfnp (número de elementos del vector).// La tabla de símbolos que se recibe como parámetros es a los efectos de// poder generar las interpretaciones posibles. El tamaño de la tabla de// símbolos (vector) viene dado en ttds.// La función devuelve 0 si no es tautología y distinto a 0 si lo es.

int Tautologia( const SimbFormProp * fnp, unsigned tfnp, SimbFormProp * tds, unsigned ttds ) { int i, t; t = (1 << ttds) - 1; // 2 elevado a la número de variables menos 1 for (i = 0; i <= t; ++i) { AsigInterp(tds, ttds, i); if (! Evaluar(fnp, tfnp, tds, ttds)) // si alguno es falso break; // entonces no es tautología } return i > t; // si se probaron todas las interpretaciones} // entonces es tautología

Documentación de SLR1 versión 2.x

167

Page 168: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.13.7 VESQDED.CMM

// vesqded.cmm validación de esquemas deductivos.

// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 04 Dic 95

# include "ed.cmm"# include "ed.tab"

int ValidarEsqDed( const char * EsqDed ) { alEsqDed.Reiniciar(EsqDed); ifnp = itds = 0; // variables globales AnalSLR1<ElemPila> analizador(ntlpdEsqDed, accionEsqDed, ir_aEsqDed,AccSemEsqDed); Ascii0 CadPosErr; if (analizador.Analizar(alEsqDed, CadPosErr)) return Tautologia(fnp, ifnp, tds, itds) ? EDVAL : EDINVAL; else return EDERROR;}

12.13.8 ESQDED.H

# ifndef __ESQDED_H# define __ESQDED_H

// Copyright © 1993 by Domingo Eduardo Becker.// All rights reserved.// Creación: 26 May 93// Ult Mod: 04 Dic 95

// clase SimbFormProp: implementa un símbolo de una fórmula del cálculo// proposicional. Un símbolo puede ser una constante (V o F), una variable// o un operador lógico.

class SimbFormProp {public: unsigned cod; char valor; char var[10];

enum { CONSTANTE = 0, MAXVAR = 999, DOBLEIMPL, IMPLIC, DISYUN, CONJUN, NEGAR, ULTIMOOPERADOR };};

// Funciónes de operaciones lógicas:

// Evaluación de una fórmula con 1 o 2 operandos:int Evaluar( char p, char q, int operacion );

// Evaluación de una fórmula compleja dada en notación postfijo.// fnp es la fórmula (en vector), tfnp el número de elementos.// tds es la tabla de variables de la fórmula de ttds elementos.// En el campo valor de cada elemento de tds está el valor de verdad// asignado a la variable (==0 falso, !=0 verdadero).

Documentación de SLR1 versión 2.x

168

Page 169: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

int Evaluar( const SimbFormProp * fnp, unsigned tfnp, const SimbFormProp * tds, unsigned ttds );

// Asignación de una interpretación (ver doc en asigint.cmm):void AsigInterp( SimbFormProp * tds, unsigned ttds, int vv );

// Verificación de si una fórmula es tautología o no:// La fórmula a comprobar viene en notación postfijo en fnp, representado// como vector de tamaño tfnp. La tabla de variables viene en tds, unvector// de tamaño ttds. El campo valor de los elementos de tds son modificados.

int Tautologia( const SimbFormProp * fnp, unsigned tfnp, SimbFormProp * tds, unsigned ttds );

// Funciones para el análisis léxico y traducción del esquema deductivo a// implicación asociada:

// AgregarTDS agrega a s como variable en la tabla de símbolos interna.// Devuelve el código asignado a la variable.

int AgregarTDS( const char * s );

// AnaLexEsqDed es la función que realizará el análisis lexicográfico// del esquema deductivo. Se pasa como parámetro a la función Analizar.

unsigned char AnaLexEsqDed();

// Validar un esquema deductivo dado en formato texto:// la función devuelve:// EDVAL si es válido.// EDINVAL si es inválido.// EDERROR si hay error léxico o de sintaxis.

int ValidarEsqDed( const char * EsqDed );# define EDVAL 0# define EDINVAL 1# define EDERROR 2

# endif

12.13.9 SLR1.H

Este módulo viene provisto con SLR1 v 2.x. Se lo incluye más adelanteen este mismo documento (en la sección 12.14).

12.13.10EXPREG.H

Este módulo viene provisto con AFD v 3.x. Se lo incluye más adelanteen este mismo documento a modo de ilustración (en la sección 12.14).

Documentación de SLR1 versión 2.x

169

Page 170: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

12.14 Archivos provistos con SLR1 v 2.x

12.14.1 SLR1.H

# ifndef __SLR1_H# define __SLR1_H

// slr1.h: definición de las clases para las tablas que maneja elanalizador// sintáctico SLR(1)

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# ifndef __TIPOS_H# include "tipos.h"# endif

# ifndef __ASCII0_H# include "ascii0.h"# endif

# ifndef __EXPREG_H# include "expreg.h"# endif

// Clase SimboloSLR1: es una versión simplificada de la clase SimboloSLR1// declarada en gramlc.h. Aquí Codigo tiene 8 bits en vez de 15 yNoTerminal// tiene 8 bits en vez de 1. Esto hace que el código funcione más rápido.

class SimboloSLR1 {public: Ent8ns Id; Ent8ns NoTerminal; SimboloSLR1() { Id = NoTerminal = 0; }};

class SimbCad : public SimboloSLR1 {public: Ascii0 cad;};

class ElemPila { // estructura de un elemento de la pila del analizadorpublic: SimboloSLR1 Simb; Ent16ns Estado; Ascii0 CadTerm; ElemPila() { Estado = 0; }};

class Accion { // estructura de una acciónpublic: Ent16ns n : 14; // puede tener el número de regla o número deestado Ent16ns Codigo : 2; // 00=d, 01=a, 10=r Accion() { *(Ent16ns *) this = 0; } Accion( Ent16ns a ) { *(Ent16ns *) this = a; } Accion & operator = ( Ent16ns a ); Ent8 operator == ( Ent16ns a ) { return *(Ent16ns *) this == a; }};

Documentación de SLR1 versión 2.x

170

Page 171: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inline Accion & Accion::operator = ( Ent16ns a ) { *(Ent16ns *) this = a; return *this;}

template <class ELEMPILA>class AnalSLR1 {protected: Ent16ns * ntlpd, * accion, * ir_a; void (* fAccSem)( Ent16ns numregla, ELEMPILA * pila, Ent16ns pp ); void (* fLimPila)( ELEMPILA * pila, Ent16ns pp, Ent8 cumple ); void (* fVer)( const char * mensaje );public: AnalSLR1( Ent16ns * ntlpd, Ent16ns * accion, Ent16ns * ir_a, void (* fAccSem)( Ent16ns numregla, ELEMPILA * pila, Ent16ns pp ) = 0, void (* fLimPila)( ELEMPILA * pila, Ent16ns pp, Ent8 cumple ) = 0, void (* fVer)( const char * mensaje ) = 0 ); ~AnalSLR1() { }

Ent8 Analizar( AnaLex & analex, Ascii0 & CadErr, Ent16ns MaxPila = 50 ); Ent16ns CodError; enum { ERRORLEX = 1, TERMINESP, PILACHICA, ERRORENTABLAS };};

template <class ELEMPILA>AnalSLR1<ELEMPILA>::AnalSLR1( Ent16ns * _ntlpd, Ent16ns * _accion, Ent16ns * _ir_a, void (* _fAccSem)( Ent16ns numregla, ELEMPILA * pila, Ent16ns pp ), void (* _fLimPila)( ELEMPILA * pila, Ent16ns pp, Ent8 cumple), void (* _fVer)( const char * mensaje ) ) { ntlpd = _ntlpd; accion = _accion; ir_a = _ir_a; fAccSem = _fAccSem; fLimPila = _fLimPila; fVer = _fVer;}

template <class ELEMPILA>Ent8 AnalSLR1<ELEMPILA>::Analizar( AnaLex & analex, Ascii0 & CadErr, Ent16ns MaxPila ) { Ent16ns idTerm; Ascii0 cadTerm; Accion a; Ent16ns x1,x2,x3; // variables auxiliares Ent16ns numiter; Ascii0 msj; Ent8ns nt = ntlpd[0] >> 8, t = ntlpd[0] + 1;

// pila[pp].Estado es el estado actual. Ent8 salir = 0, cumple; idTerm = analex.Examinar(cadTerm); // pide un símbolo de entrada if (idTerm > t) { // error léxico analex.CadError(CadErr); CodError = ERRORLEX; return 0; // carácter o símbolo inesperado }

ELEMPILA * pila;

Documentación de SLR1 versión 2.x

171

Page 172: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

pila = new ELEMPILA[MaxPila]; // se def aquí para que el constructor nose // ejecute si no va a ser usado. if (pila == 0) return 0; // falta memoria

Ent16ns pp; pp = 0; // puntero de pila pila[0].Estado = 0; // estado inicial.

numiter = 0; while ( ! salir ) { if (fVer != 0) { msj.printf("Iter: %4u ", ++numiter); (*fVer)(msj); // MostrarPila(fVer, pila, pp); msj.printf("Est: %u, Símb: %u, ", pila[pp].Estado, (Ent16ns)idTerm); (*fVer)(msj); }

a = x1 = accion[pila[pp].Estado * t + idTerm]; if (! x1) { // error sintáctico, terminal inesperado salir = 1; cumple = 0; analex.CadError(CadErr); CodError = TERMINESP; if (fVer != 0) (*fVer)("ERROR.\n"); } else { switch (a.Codigo) { case 0: // desplazar terminal actual e ir a a.n if (++pp == MaxPila) { msj.printf("Sobreflujo en la pila, intente con MaxPila >%u.\n", MaxPila); if (fVer != 0) (*fVer)(msj); salir = 1; cumple = 0; CodError = PILACHICA; break; } pila[pp].Simb.Id = idTerm; pila[pp].Simb.NoTerminal = 0; pila[pp].CadTerm << cadTerm; pila[pp].Estado = a.n; if (fVer != 0) { msj.printf("d%u\n", a.n); (*fVer)(msj); } idTerm = analex.Examinar(cadTerm); // pide otro símbolo deentrada if (idTerm > t) { // error léxico analex.CadError(CadErr); salir = 1; cumple = 0; CodError = ERRORLEX; // símbolo inesperado } break;

case 1: // aceptar salir = cumple = 1; CodError = 0; if (fVer != 0) (*fVer)("Aceptar.\n"); break;

case 2: // reducir por a.n

Documentación de SLR1 versión 2.x

172

Page 173: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

x1 = ntlpd[a.n]; x2 = x1 & 0x00FF; // apaga el byte alto pp = x2 > pp ? 0 : pp - x2; // desapila x2 elementos x1 >>= 8; // cód del no terminal x3 = ir_a[ pila[pp].Estado * nt + x1 - 1 ]; if (fAccSem != 0) (*fAccSem)(a.n, pila, pp); pila[++pp].Simb.Id = x1; pila[pp].Simb.NoTerminal = 1; pila[pp].Estado = x3; if (fVer != 0) { msj.printf("r%u, lpdr: %u, EstExp: %u, NT: %u\n", a.n, x2, pila[pp-1].Estado, x1); (*fVer)(msj); } break;

default: // problemas salir = 1; cumple = 0; CodError = ERRORENTABLAS; if (fVer != 0) (*fVer)("PROBLEMAS EN LAS TABLAS.\n"); } } // else } // while

if (fLimPila != 0) (*fLimPila)(pila, pp, cumple); delete [] pila;

return cumple;}

# endif // # ifndef __SLR1_H

12.14.2 EXPREG.H

# ifndef __EXPREG_H# define __EXPREG_H

// expreg.h: definición de una clase para el manejo de// expresiones regulares.// Creación: Lun 09 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# ifndef __TIPOS_H# include <tipos.h># endif

class AutomFinDet {public: const char * ExpRegular; const char * * Caracter; Ent16ns NumCar; const Ent16ns * Transicion, * EstFinales;};

# define TNDEF 0xffff

// ExpRegular: cadena de la Expresión Regular que define el lenguaje.// Caracter: vector de const char *, contiene los caracteres posibles como

Documentación de SLR1 versión 2.x

173

Page 174: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// caracteres simples o como rangos (para rangos ver doc).// NumCar: número de caracteres, número de columnas de la tablaTransición.// Transicion: tabla de transición de estados del autómata finito deter-// minístico (AFD) que reconoce el lenguaje de la expr.regular.// Los elementos se enumeran por filas. Si una transici¢n no// est  definida se debe utilizar TNDEF o el número 0xffff.// EstFinales: vector de estados finales del AFD. El elemento 0 de este// vector contiene el número de elementos, a continuación se// enumeran los estados finales. El vector no necesita estar// ordenado porque se utiliza búsqueda secuencial.

// Ejemplo de definición est tica de AutomFinDet:// (Los objetos static pueden no serlo. Se los hace estáticos para que// sus nombres sean sólo conocidos en el módulo donde se define al// objeto AutomFinDet.)/*static const char ExpRegular[] = "a+(b|c)*d+";static const char * Caracteres[] = { "a", "b", "c", "d" };static const Ent16ns Transiciones[] = { 1, TNDEF, TNDEF, TNDEF, 1, 2, 2, 3, TNDEF, 2, 2, 3, TNDEF, TNDEF, TNDEF, 3};static const Ent16ns EstFinales[] = { 1, // elemento 0 para indicar la cantidad de estados finales. 3};

AutomFinDet automata = { ExpRegular, Caracteres, 4, Transiciones,EstFinales };

// La tabla de Transiciones del ejemplo es:// a b c d// 0 1 - - -// 1 1 2 2 3// 2 - 2 2 3// 3 - - - 3*/

class Archivo;

const char * CadSecEscape( char c );char CarSecEscape( const char * pCad );int ImprCaracter( Archivo & arch, char c );int ImprCadena( Archivo & arch, const char * cad );int CambSecEsc( char * pCad );

int ImprimirAFD( Archivo & arch, const AutomFinDet & afd );int ImprFuenteAFD( Archivo & arch, const AutomFinDet & afd, const char * NomObj = 0, const char * NomSubobj = 0 );// Los nombres ser n los siguientes:// erXXX: expresi¢n regular// vcXXX: vector de caracteres o rangos// tXXX: tabla de transiciones// efXXX: vector con los estados finales// afdYYY: variable AutomFinDet (aut¢mata finito determin¡stico)// XXX corresponde al valor NomSubobj y YYY a NomObj. Si NomSubobj == 0// entonces se usa el valor de NomObj como NomSubobj. Si ambos son nulos// entonces aparecer  el/los caracteres iniciales, por ejemplo, si// NomObj == 0 o == "" entonces el nombre de la variable AutomFinDet// ser  'afd'.// Si no especifica al menos NomObj, y agrupa varios AutomFinDet generados

Documentación de SLR1 versión 2.x

174

Page 175: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// por ExpReg en un solo m¢dulo fuente entonces tendr  colisi¢n de nombres// al compilar.

class Ascii0;

class ExpReg {protected: AutomFinDet * afd; char apu;public: ExpReg() { afd = 0; apu = 0; } ExpReg( const AutomFinDet & _afd ) { afd = 0; apu = 0; Reasignar(_afd);} ExpReg( const char * er, Ascii0 & CadPosErr ); ~ExpReg() { Vaciar(); }

int Reasignar( const AutomFinDet & afd ); int Reasignar( const char * CadExpReg, Ascii0 & CadPosErr ); void Vaciar(); int Imprimir( Archivo & arch ) const; int ImprFuente( Archivo & arch, const char * NomObj = 0, const char * NomSubobj = 0 ) const; int ImprFuente( const char * NomArch, const char * NomObj = 0, const char * NomSubobj = 0 ) const; int Examinar( const char * Cadena, unsigned Inicio, unsigned & Tam )const; int Buscar( const char * Cadena, unsigned & Inicio, unsigned & Tam, unsigned BuscarDesde = 0 ) const; enum { AFDNDEF = 1, AFDERR, CADNULA, CARINESP, TRANSNDEF }; // paraBuscar};

inline ExpReg::ExpReg( const char * er, Ascii0 & CadPosErr ) { afd = 0; apu = 0; Reasignar(er, CadPosErr);}

inline int ExpReg::Reasignar( const AutomFinDet & Afd ) { Vaciar(); afd = (AutomFinDet *) & Afd; apu = 1; return 1;}

inline int ExpReg::Imprimir( Archivo & arch ) const { return afd != 0 ? ImprimirAFD(arch, *afd) : 0;}

inline int ExpReg::ImprFuente( Archivo & arch, const char * NomObj, const char * NomSubobj ) const { return afd != 0 ? ImprFuenteAFD(arch, *afd, NomObj, NomSubobj) : 0;}

// Clase RecSimb: Reconocedor de Símbolo, esta clase contiene un puntero a// una cadena donde está la cadena del símbolo léxico (si es constante) o// bien un puntero al autómata finito determinístico (AFD) que reconoce al// símbolo léxico. También contiene el identificador léxico del símbolo.

class RecSimb {public: unsigned Id; char EsAFD;

Documentación de SLR1 versión 2.x

175

Page 176: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

const AutomFinDet * pAFD; const char * pCad;};

// Id: número identificador del símbolo léxico. No puede usar 0xffffporque// est  reservado para error léxico. Si usa 0 el símbolo léxico ser // ignorado por un objeto AnaLex, ‚ste lo saltear  y buscar  el// siguiente. La clase AnaLex reserva el 0 para el fin de archivo(FA).// No hay problemas acerca de Id repetidos en un vector de RecSimb a// ser usado por un objeto AnaLex.// EsAFD: si == 0 entonces el símbolo es constante y est  descripto porpCad,// en este caso pAFD == 0. Si != 0 entonces el reconocedor delsímbolo// es un Autómata Finito Determinístico apuntado por pAFD, pCad ==0// en este caso.// pAFD: apunta a un AutomFinDet creado a mano o con un generador de AFD.// pCad: apunta a la cadena que describe al símbolo. Por ejemplo, si el// símbolo es '>=' entonces no hace falta un AFD, es más eficiente// especificar ">=". Para el caso de los Naturales con el 0, estamos// hablando de una familia de símbolos similares, y ya no podemosusar// este campo sino pAFD con un autómata que reconozca "[0-9]+".

// Clase AnaLex: Analizador Lexicográfico, esta clase encapsula unanalizador// lexicográfico. Se implementa mediante un vector de RecSimb(reconocedores// de símbolos) creado previamente. Informa sobre el estado del analizadory// los errores encontrados.

class AnaLex {protected: const RecSimb * vrs; unsigned tvrs; const char * pTxt; unsigned Inic, Tama, NumLin; unsigned (* fErrorLex) ( int MayIgualMin, AnaLex & analex, Ascii0 & Cad); AnaLex(); // no se puede crear objetos sin vrs.public: unsigned CodError; // usado por función Examinar unsigned ComLin; // índice del comienzo de línea AnaLex( const RecSimb * pvrs, unsigned n, unsigned (* fSiHayErrorLex) ( int, AnaLex &, Ascii0 & ) = 0 ); ~AnaLex() { vrs = 0; pTxt = 0; fErrorLex = 0; }

void Reiniciar( const char * Texto ); unsigned Examinar( Ascii0 & CadSimb, int MayIgualMin = 0 ); unsigned Inicio() const { return Inic; } unsigned Tam() const { return Tama; } unsigned NumLinea() const { return NumLin + 1; } unsigned Simbolo( Ascii0 & CadSimb ) const; char Saltear(); unsigned Saltear( unsigned tam ); unsigned CadError( Ascii0 & Cad ) const;};

inline AnaLex::AnaLex() { vrs = 0; pTxt = 0;

Documentación de SLR1 versión 2.x

176

Page 177: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Inic = Tama = CodError = NumLin = ComLin = 0; fErrorLex = 0;}

inline AnaLex::AnaLex( const RecSimb * pvrs, unsigned n, unsigned (* fSiHayErrorLex) ( int , AnaLex &, Ascii0 & ) ) { vrs = pvrs; tvrs = n; pTxt = 0; Inic = Tama = CodError = NumLin = ComLin = 0; fErrorLex = fSiHayErrorLex;}

inline void AnaLex::Reiniciar( const char * Texto ) { pTxt = Texto; Inic = Tama = CodError = NumLin = ComLin = 0;}

inline char AnaLex::Saltear() { if (! Tama && pTxt != 0 && pTxt[Inic]) Tama = 1; return pTxt[Inic];}

// El siguiente objeto es global y lo puede usar cualquiera.// Es usado por ExpReg::Reasignar( const char * CadExpReg ) para// analizar CadExpReg en busca de símbolos léxicos.// Recuerde siempre Reiniciar antes de usarlo por primera vez.extern AnaLex AnaLexExpReg;

// Al llamar a AnaLex::Examinar con AnaLexExpReg, Examinar devuelve alguno// de los siguientes códigos o 0 si hay fin de texto. No devuelve error// léxico porque reconoce cualquier caracter excepto el 0 de fin de cadena// al cual lo toma como fin de texto.

# define _id_Numeral 1# define _id_Ident 2# define _id_CteCar 3# define _id_Rango 4# define _id_Disyuncion 5# define _id_Opcional 6# define _id_Uno_o_Mas 7# define _id_Cero_o_Mas 8# define _id_Abre_Paren 9# define _id_Cierra_Paren 10

# endif // # ifndef __EXPREG_H

Documentación de SLR1 versión 2.x

177

Page 178: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 13: Documentación de la Biblioteca ExpReg v 1.x

El texto de este capítulo es la documentación de ExpReg v 1.x, y debeser tomado como un libro aparte. No se hacen referencias a otros capítulos deeste trabajo.

En el capítulo 18, donde se comenta la historia del desarrollo de lasherramientas presentadas en este trabajo, se puede encontrar informacióninteresante acerca de esta implementación.

13.1 Introducción

La biblioteca ExpReg para C++ es un conjunto de clases y rutinas paramanejar expresiones regulares, autómatas finitos determinísticos yanalizadores lexicográficos.

El objetivo principal de esta biblioteca es la de servir como soporte paralas aplicaciones AFD y SLR1. AFD utiliza la implementación de autómatasfinitos determinísticos y la implementación de expresiones regulares de ésta.SLR1 utiliza además a la implementación de analizadores lexicográficos.

Esta biblioteca ha sido definida independiente del sistema operativo enel que se trabaje. Saca provecho además de la implementación que loscompiladores hagan del tipo de dato fundamental int del C++.

Cuando use EXPREG.LIB recuerde incluir en su proyecto la bibliotecaBCE, ya que esta biblioteca usa a la clase Ascii0 de BCE.

13.2 Autómatas finitos determinísticos - Clase AutomFinDet

La clase AutomFinDet implementa un autómata finito determinístico.La teoría sobre los autómatas finitos determinísticos debe ser consultada en labibliografía de compiladores.

La declaración de la clase se realiza en el archivo EXPREG.H y es comosigue:

class AutomFinDet {

Documentación de la Biblioteca ExpReg v 1.x

178

Page 179: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

public: const char * ExpRegular; const char * * Caracter; Ent16ns NumCar; const Ent16ns * Transicion, * EstFinales;};

en donde:

ExpRegular: cadena de la Expresión Regular que define el lenguaje. Puede obviar darle valor a este campo pasando un 0.

Caracter: vector de const char *, contiene los caracteres posibles como caracteres simples o como rangos.

NumCar: número de caracteres, número de columnas de la tabla Transición.

Transicion: tabla de transición de estados del autómata finito determinístico (AFD) que reconoce el lenguaje de la expr. regular. Loselementos se enumeran por filas. Si una transición no está definida se debe utilizar TNDEF o el número 0xffff.

EstFinales: vector de estados finales del AFD. El elemento 0 de este vector contiene el número de elementos, a continuación se enumeran los estados finales. El vector no necesita estar ordenado porque se utiliza búsqueda secuencial.

La clase se define de esa manera a efectos de poder realizar definicionesestáticas de objetos de la misma. Por ejemplo, la siguiente es una definiciónválida de un autómata finito determinístico:

// (Los objetos static pueden no serlo. Se los hace estáticos para que// sus nombres sean sólo conocidos en el módulo donde se define al// objeto AutomFinDet.)static const char ExpRegular[ ] = "a+(b|c)*d+";static const char * Caracteres[ ] = { "a", "b", "c", "d" };static const Ent16ns Transiciones[ ] = { 1, TNDEF, TNDEF, TNDEF, 1, 2, 2, 3, TNDEF, 2, 2, 3, TNDEF, TNDEF, TNDEF, 3};static const Ent16ns EstFinales[ ] = { 1, // elemento 0 para indicar la cantidad de estados finales. 3};

AutomFinDet automata = { ExpRegular, Caracteres, 4, Transiciones,EstFinales };

Documentación de la Biblioteca ExpReg v 1.x

179

Page 180: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

13.3 Funciones globales para el tratamiento de AutomFinDet

13.3.1 ImprimirAFD

int ImprimirAFD( Archivo & arch, const AutomFinDet & afd );

Esta función imprime afd en arch en formato texto. El formato texto essimilar al utilizado por la bibliografía que trata sobre autómatas.

Archivo es una clase de la biblioteca BCE que sirve de soporte para estabiblioteca.

La función devuelve 0 si no pudo imprimir, 1 si pudo imprimir.

13.3.2 ImprFuenteAFD

int ImprFuenteAFD( Archivo & arch, const AutomFinDet & afd, const char * NomObj = 0, const char * NomSubobj = 0 );

Imprime afd en arch en formato C++ (como texto plano). La salida essimilar a la que se muestra como ejemplo de definición de un objeto de la claseAutomFinDet.

La clase Archivo pertenece a la biblioteca BCE que sirve de soporte aesta biblioteca.

NomObj es el sufijo utilizado para el nombre del objeto AutomFinDet.El nombre del mismo será afdNomObj. Si pasa 0 (valor por defecto) entoncesno se usa sufijo.

NomSubobj es el sufijo utilizado para la definición de los subobjetoscomponentes del autómata finito determinístico. El campo ExpRegular serádefinido como erNomSubobj, el campo Caracter será definido comovcNomSubobj, Transicion como tNomSubobj y EstFinales comoefNomSubobj. En el caso de que se especifique 0 se utiliza NomObj comoNomSubobj, y, si este último era 0 entonces no se usa sufijo para los nombresde los subobjetos. Los subobjetos serán definidos como static.

NomObj y NomSubobj se deben utilizar para evitar la duplicación denombres de objetos en un proyecto.

La función devuelve 0 si hay problemas con el autómata o no se pudoimprimir, 1 si pudo imprimir.

Documentación de la Biblioteca ExpReg v 1.x

180

Page 181: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

13.4 Expresiones regulares - Clase ExpReg

La clase ExpReg declarada en EXPREG.H implementa el uso de unaexpresión regular, la cual deberá ser especificada por medio de una cadena decaracteres válida del C++, la que puede ser obtenida por lectura directa ycompleta de un archivo de texto plano.

A partir de la expresión regular especificada como parámetro, esta claseconstruye un autómata finito determinístico que reconoce el lenguaje definidopor esa expresión regular, a efectos de posterior consulta usando la expresiónregular.

También se puede armar un objeto a partir de un autómata finitodeterminístico definido previamente.

13.4.1 Campos dato de la clase ExpReg

Los miembros dato protegidos de la clase son:

AutomFinDet * afd;

Es el autómata finito determinístico que reconoce el lenguaje definidopor la expresión regular.

char apu;

Tiene 1 si éste objeto fue construido a partir de un AutomFinDet, y 0 siel campo afd fue construido por la función local Reasignar.

13.4.2 Funciones miembro de la clase ExpReg

Las funciones miembro públicas de esta clase son:

ExpReg::ExpReg( );

Construye un objeto ExpReg por defecto (nulo).

ExpReg::ExpReg( const AutomFinDet & _afd );

Documentación de la Biblioteca ExpReg v 1.x

181

Page 182: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Construye un objeto ExpReg a partir del autómata finito determinísticopasado como parámetro.

ExpReg::ExpReg( const char * er, Ascii0 & CadPosErr );

Construye un objeto ExpReg a partir de la expresión regular pasada enel parámetro er. Si hay error de sintaxis o léxico en el texto de entrada (er)entonces se devuelve una cadena con la posición del error en CadPosErr.

Este constructor utiliza la función local Reasignar para efectuar estetrabajo.

int ExpReg::Reasignar( const AutomFinDet & afd );int ExpReg::Reasignar( const char * CadExpReg,

Ascii0 & CadPosErr );

La primera versión reasigna el campo afd de éste objeto.

La segunda versión construye un objeto AutomFinDet a partir de laexpresión regular CadExpReg. Se realiza un análisis lexicográfico y sintácticode la expresión regular y luego se procede a la construcción del autómatafinito determinístico a partir de esa expresión regular. Si hay error léxico o desintaxis, en CadPosErr se devuelve la cadena de texto con la línea donde seprodujo el error.

Ambas funciones devuelven 0 si no se pudo reasignar, distinto a 0 si nohubo ningún problema.

void ExpReg::Vaciar();

Vacía este objeto. Vaciar significa hacer nulo. Si el objeto construyó elAutomFinDet afd entonces lo destruye devolviendo correctamente la memoriausada.

int ExpReg::Imprimir( Archivo & arch ) const;

Imprime éste objeto en arch. Se utiliza la función globalImprimirAFD, y se devuelven los mismos códigos de error.

Documentación de la Biblioteca ExpReg v 1.x

182

Page 183: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

int ExpReg::ImprFuente( Archivo & arch, const char * NomObj = 0, const char * NomSubobj = 0 ) const;int ExpReg::ImprFuente( const char * NomArch, const char * NomObj = 0, const char * NomSubobj = 0 ) const;

Estas funciones imprimen el objeto afd en el archivo especificado. Laprimera versión espera que arch sea un archivo abierto y que se pueda escribiren él. La segunda crea un archivo con nombre NomArch eliminando laversión previa del mismo si es que existía.

Se utiliza la función global ImprFuenteAFD. Consulte en sudocumentación el uso de NomObj y NomSubobj.

Las funciones devuelven 0 si hay error, distinto a 0 si no hay problemas.

int ExpReg::Examinar( const char * Cadena, unsigned Inicio, unsigned & Tam ) const;

Esta función examina la Cadena desde la posición Inicio (Cadena[Inicio] ) para ver si la secuencia siguiente de caracteres cumple conésta expresión regular.

Si cumple entonces la función devuelve 0 y en Tam el número decaracteres del símbolo del lenguaje. El símbolo comienza en Cadena[Inicio] ytermina en Cadena[Inicio + Tam - 1], y no incluye un 0 de fin de cadena enCadena[Inicio + Tam]. Se puede usar la función estándar del C++ strncpy

para sacar una copia del símbolo, se debe indicar como fuente a Cadena +

Inicio, y como n a Tam; la cadena destino debe ser lo suficientemente grandecomo para contener al símbolo (Tam + 1 de largo); luego del llamado astrncpy debe hacer "Simbolo[Inicio + Tam] = 0;" para asegurar laterminación en 0 de la cadena.

Si no cumple devuelve un valor distinto de 0 que es el código de error.Debe utilizar el enum definido dentro de ésta clase para ver qué error seprodujo. Utilice la sintaxis ExpReg::XXX donde XXX es el id del código.Los códigos son los siguientes:

AFDNDEF: el autómata finito determinístico es nulo (no definido).

AFDERR: el autómata finito determinístico está mal definido.

Documentación de la Biblioteca ExpReg v 1.x

183

Page 184: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

CADNULA: la Cadena pasada es nula (== 0 o Inicio > Longitud(Cadena)).

CARINESP: el caracter que sigue (el de Cadena[Inicio + Tam - 1]) es inesperado. No se lo encuentra dentro del vector this->afd.Caracter.

TRANSNDEF: para el caracter que sigue no hay transición definida desde el estado actual.

Debido a que esta función no hace movimiento de datos, es muyconveniente su utilización en analizadores lexicográficos, ya que nodesperdicia tiempo en movimientos de datos innecesarios.

int ExpReg::Buscar( const char * Cadena, unsigned & Inicio, unsigned & Tam, unsigned BuscarDesde = 0 ) const;

Esta función Examina la Cadena desde la posición BuscarDesde

(Cadena[BuscarDesde] ) para ver si desde esa posición hasta el primercaracter 0 siguiente hay una secuencia de caracteres que pertenece al lenguajedefinido por ésta expresión regular.

Esta función utiliza la función Examinar para la búsqueda de la primeraocurrencia de un símbolo perteneciente al lenguaje.

Si no hay problemas devuelve 0. En Inicio devuelve la posición inicialde la primera ocurrencia. En Tam devuelve el tamaño de la cadena. Si Tam== 0 entonces puede que no haya una ocurrencia de algún símbolo dellenguaje (si la expresión regular es anulable entonces Tam puede venir con 0sin que haya error, esto es, lambda (λ) pertenece al lenguaje; λ es la cadenanula). Si Tam es mayor que 0, la cadena comienza en la posición Inicio

(Cadena[Inicio]) y termina en Tam - 1 (Cadena[Inicio + Tam - 1] ).

Devuelve ExpReg::CADNULA si Cadena == 0 o si BuscarDesde >Longitud(Cadena).

13.5 Reconocedores de símbolos - Clase RecSimb

Denominaremos reconocedor de símbolo al objeto que describe cómo sedebe realizar la búsqueda de un símbolo de un lenguaje dado. El lenguaje dadopuede ser especificado por una expresión regular, y en este caso se usaría unautómata finito determinístico para reconocer un símbolo. La otra forma

Documentación de la Biblioteca ExpReg v 1.x

184

Page 185: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

posible es la de usar una simple comparación de cadena, como la que se usaríapara reconocer palabras claves u operadores de un lenguaje.

Esta clase contempla las dos posibilidades. La declaración se la realizócomo sigue:

class RecSimb {public: unsigned Id; char EsAFD; const AutomFinDet * pAFD; const char * pCad;};

Id: número identificador del símbolo léxico. No puede usar 0xffff porque estáreservado para error léxico. Si usa 0 el símbolo léxico será ignorado por unobjeto AnaLex, éste lo salteará y buscará el siguiente. No hay problemasacerca de Ids repetidos en un vector de RecSimb a ser usado por un objetoAnaLex.

EsAFD: si == 0 entonces el símbolo es constante y está descripto por pCad

(pCad apuntará a una cadena que es una copia del símbolo), en este casopAFD == 0. Si != 0 entonces el reconocedor del símbolo es un AutómataFinito Determinístico apuntado por pAFD, pCad == 0 en este caso.

pAFD: apunta a un AutomFinDet creado a mano o con un generador de AFD.Este campo debe valer 0 si EsAFD == 0.

pCad: apunta a la cadena que describe al símbolo si EsAFD == 0. Porejemplo, si el símbolo es '>=' entonces no hace falta un AFD, es más eficienteespecificar ">=". Para el caso de los Naturales con el 0, estamos hablando deuna familia de símbolos similares, y ya no podemos usar este campo sino quedebemos usar pAFD con un autómata que reconozca "[0-9]+".

El siguiente es un ejemplo de definición de un vector de reconocedoresde símbolos que puede servir para la construcción de un analizadorlexicográfico a través de la clase AnaLex:

static RecSimb vrs[] = { 1, 1, & afdBlqCod, 0, 2, 0, 0, "#", 3, 0, 0, "ACCSEM", 4, 1, & afdIdent, 0, 5, 0, 0, "TERMINAL", 6, 0, 0, ":", 7, 0, 0, "IGNORAR", 8, 0, 0, "ELEMPILA", 9, 0, 0, ";", 10, 1, & afdFlecha, 0,

Documentación de la Biblioteca ExpReg v 1.x

185

Page 186: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

11, 0, 0, "|", 12, 0, 0, "*", 13, 1, & afdCadena, 0, 0, 1, & afdBlancos, 0, 0, 1, & afdComentario, 0};

Este ejemplo ha sido extraído del módulo donde se define el analizadorlexicográfico de SLR1 v 2.x. Los afdXXX han sido generados por AFD v 3.xy residen en sus respectivos archivos .CMM; no fueron transcriptos. Lascadenas de caracteres (entre comillas) son palabras claves y operadores dellenguaje. Los dos últimos reconocedores indican que se deben ignorar blancosy comentarios.

Debe evitarse la utilización directa de esta clase. En su lugar permitaque SLR1 v 2.x o posterior, junto con AFD v 3.x o posterior sean los queconstruyan el analizador lexicográfico por usted. A tal efecto consulte ladocumentación de SLR1 y de AFD.

13.6 Analizadores lexicográficos - Clase AnaLex

La clase AnaLex implementa los analizadores lexicográficos. Unanalizador lexicográfico se concibe como un conjunto no vacío dereconocedores de símbolos que se utilizan para el análisis de un texto deentrada. El lenguaje que reconoce el analizador lexicográfico es la unión de loslenguajes reconocidos por cada reconocedor de símbolo que componen elanalizador.

Esta clase ha sido definida inicialmente para servir de soporte a losanalizadores sintácticos generados por SLR1 v 2.x y posteriores. De hecho,SLR1 v 2.x genera definiciones de analizadores lexicográficos implementadoscon esta clase de manera automática (en el archivo .CMM generado incluyeuna instancia de esta clase, la que posteriormente será utilizada como elanalizador lexicográfico para el lenguaje a analizar).

Se aconseja consultar los archivos .CMM de salida de SLR1 v 2.x oposterior a los efectos de ver la mejor forma de definir objetos AnaLex.

13.6.1 Campos dato de la clase AnaLex

Los miembros dato públicos de esta clase son:

unsigned ComLin;

Documentación de la Biblioteca ExpReg v 1.x

186

Page 187: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Indice del comienzo de línea actual.

unsigned CodError;

Usado por función local Examinar para almacenar el código de error.No es usado por la implementación actual de esta clase. Su declaración esagregada a efectos de que sea usada por la función que corrige erroreslexicográficos.

Miembros dato protegidos:

const RecSimb * vrs;

Vector de reconocedores de símbolos léxicos. Tiene tamaño tvrs.

unsigned tvrs;

Tamaño del vector vrs. Número de elementos del conjunto dereconocedores de símbolos de este analizador lexicográfico.

const char * pTxt;

Puntero al inicio del texto de entrada que se está analizando.

unsigned Inic;

Indice del inicio para la siguiente posición a Examinar.

unsigned Tama;

Tamaño del último símbolo léxico reconocido.

unsigned NumLin;

Número de línea actual.

unsigned (* fErrorLex) ( int MayIgualMin, AnaLex & analex, Ascii0 & Cad );

Puntero a una función especificada por el programador en la creación deéste objeto.

La función debe resolver el error léxico que se acaba de producir, ydevolver un número que indica el código del símbolo terminal siguiente o0xffff si es que hay realmente un error léxico. En caso de que no haya errorléxico, debe devolver en Cad el símbolo reconocido y modificar el analizador

Documentación de la Biblioteca ExpReg v 1.x

187

Page 188: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

lexicográfico analex que se le pasa como parámetro a efectos de que ésteúltimo saltee los caracteres que se acaban de reconocer. El parámetroMayIgualMin indica si se debe hacer distinción entre mayúsculas yminúsculas.

13.6.2 Funciones miembro de la clase AnaLex

Funciones miembro protegidas de esta clase:

AnaLex::AnaLex();

El constructor por defecto de esta clase fue declarado protegido aefectos que nadie pueda construir un objeto sin especificar un conjunto dereconocedores de símbolos.

Funciones miembro públicas de esta clase:

AnaLex::AnaLex( const RecSimb * pvrs, unsigned n, unsigned (* fSiHayErrorLex) ( int, AnaLex &, Ascii0 & ) = 0 );

Este constructor construye un AnaLex a partir del vector dereconocedores de símbolos pvrs de tamaño n. La función fSiHayErrorLex esuna función que corrige un error léxico encontrado por éste analizador; suespecificación es opcional, por defecto no hay función para corregir erroresléxicos.

void AnaLex::Reiniciar( const char * Texto );

Asigna a Texto como el texto fuente a analizar lexicográficamente. Estees una cadena válida C++, la que puede ser obtenida por lectura directa de unarchivo de texto plano, de un objeto editor de Windows u OS/2, etc.

Llamar a esta función pasando 0 como Texto no tiene sentido niproduce ningún efecto.

Documentación de la Biblioteca ExpReg v 1.x

188

Page 189: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Si no hay problemas, se reinician todas las variables de este analizadorlexicográfico de manera que el mismo comience a Examinar desde la posición0 del Texto fuente.

unsigned AnaLex::Examinar( Ascii0 & CadSimb, int MayIgualMin = 0 );

Esta función Examina desde la posición actual al texto fuenteespecificado en un llamado previo a Reiniciar, para ver si desde esa posiciónhay un símbolo que cumple con algún reconocedor de símbolo de esteanalizador lexicográfico.

Si hay alguno devuelve el código del símbolo encontrado, si es fin dearchivo (no hay más texto a partir de la posición de actual, se llegó al 0 de finde cadena de C++) devuelve un 0. Si hay un error léxico entonces devuelve0xffff (65535) y en el campo CodError de éste objeto el número 1.

Si hay 2 o más reconocedores de símbolos que reconocen a una cadenade caracteres que comienza desde la posición actual, el conflicto se resuelve deacuerdo a las siguientes reglas:

1. Si hay un reconocedor que reconoce una secuencia de caracteres máslarga que el resto de los reconocedores entonces se elige ése. En caso deempate entre dos o más reconocedores se procede según las reglassiguientes.

2. Si el grupo de reconocedores para los que se produjo el empate sonautómatas finitos determinísticos (posiblemente construidos a partir deexpresiones regulares), se elige el que fue listado primero en el vector dereconocedores de símbolos que se especificó como parámetro alconstruir éste objeto.

3. Si en el grupo hay una palabra clave o un caracter o secuencia decaracteres reservados, se elige éste. Así, por ejemplo, TERMINALpuede ser un identificador, pero si fue incluido como una cadena decaracteres dentro de un reconocedor de símbolo el analizador léxicodará prioridad a la palabra clave y lo reconocerá como tal.

El comportamiento del analizador léxico que definen las tres reglasprecedentes hacen que el mismo funcione exactamente igual que los generadorpor el LEX de UNIX, a diferencia que los construidos con objetos de esta claseno realizan movimientos innecesarios de datos.

Documentación de la Biblioteca ExpReg v 1.x

189

Page 190: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

unsigned AnaLex::Inicio() const;

Esta función devuelve el valor del campo Inic.

unsigned AnaLex::Tam() const;

Esta función devuelve el valor del campo Tama.

unsigned AnaLex::NumLinea() const;

Esta función devuelve NumLin + 1.

unsigned AnaLex::Simbolo( Ascii0 & CadSimb ) const;

Esta función devuelve el tamaño del último símbolo léxico quereconoció éste analizador lexicográfico, 0 si hay problemas. Y en CadSimb lacadena del mismo.

char AnaLex::Saltear();unsigned AnaLex::Saltear( unsigned tam );

La primera versión hace que éste analizador lexicográfico saltee elcaracter actual. Devuelve el caracter que se acaba de saltear, 0 si se llegó al findel texto fuente (fin de archivo).

La segunda versión llama tam veces a la primera versión. Como efectose saltean tam caracteres a partir de la posición actual.

unsigned AnaLex::CadError( Ascii0 & Cad ) const;

Arma en Cad una cadena de caracteres válida del C++ en donde semuestra la línea de texto actual y la posición exacta en donde se encuentra ésteanalizador lexicográfico, lo que se muestra por medio de un símbolo ^ abajodel caracter actual en la línea siguiente a la actual.

En el caso de que en la última llamada a Examinar no hubiera dadoerror, el símbolo apuntador apuntará al comienzo del símbolo léxico que sereconoció al último.

Si hay problemas, Cad será una cadena Ascii0 nula (Cad.Long() valdrá0), y la función devolverá 0. En caso contrario, devolverá la longitud de Cad(que incluirá a la línea nueva agregada).

Documentación de la Biblioteca ExpReg v 1.x

190

Page 191: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

13.7 Objeto global AnaLexExpReg

extern AnaLex AnaLexExpReg;

Este objeto AnaLex es utilizado por ExpReg::Reasignar para realizarel análisis lexicográfico del texto de entrada fuente. Fue definido como globala los efectos de que sea utilizado por cualquiera que lo necesite.

Este analizador lexicográfico devuelve 0 si se llegó al final del texto (finde archivo), en caso contrario devuelve alguno de los siguientes códigos(definidos en EXPREG.H):

_id_Numeral: caracter '#'

_id_Ident: es un identificador. La longitud es por de dos o más caracteres.

_id_CteCar: es un caracter.

_id_Rango: un rango especificado con '[' y ']'.

_id_Disyuncion: el caracter '|'

_id_Opcional: el caracter '?'

_id_Uno_o_Mas: el caracter '+'

_id_Cero_o_Mas: el caracter '*'

_id_Abre_Paren: el caracter '('

_id_Cierra_Paren: el caracter ')'

Este analizador lexicográfico no fue escrito a mano, fue generado porSLR1 v 2.x.

El analizador nunca devuelve error léxico. Esto se hizo especificandouna función adicional que resuelve cualquier problema léxico.

Antes de utilizarlo por primera vez en cada sesión de análisis léxico,recuerde Reiniciar el mismo con el texto fuente de entrada.

Documentación de la Biblioteca ExpReg v 1.x

191

Page 192: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Parte 4. Ejemplos de Aplicación

192

Page 193: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 14: Una Calculadora Simple

En este capítulo se desarrollará un intérprete de expresiones aritméticas,que será usado en un programa para Windows 3.1 o posterior y OS/2 2.1 oposterior, para implementar una calculadora que incluye la posibilidad de"recordar" las últimas operaciones.

El código fuente de este ejemplo se incluye al final de este capítulo.

14.1 Análisis y Diseño

14.1.1 Visión General

La calculadora a desarrollar consta de 2 partes bien definidas:

1. Una parte es la que implementa el evaluador de expresiones aritméticasusando un analizador sintáctico y lexicográfico. Esta parte esindependiente del sistema operativo en el que funcione la calculadora,esto es, el código se escribe una sola vez y no se lo toca más a menosque haya que corregir un error.

2. La otra parte es la que usa el software de la primera parte, y esdependiente del sistema operativo donde funcionará la calculadora.

Se utilizará la técnica de análisis sintáctico SLR; el analizador sintácticoserá generado por SLR1 v 2.x. El analizador lexicográfico seráautomáticamente generado por SLR1 a partir de la especificación de lagramática para expresiones aritméticas dada de entrada.

La evaluación estará a cargo de una función que ocultará todo elprocesamiento inherente a la evaluación de expresiones aritméticas.

14.1.2 Sintaxis de una Expresión Aritmética

La sintaxis de una expresión aritmética queda descripta por la gramáticasiguiente, la que con algunas modificaciones se usará como entrada paraSLR1. Para la gramática se utiliza la sintaxis usada por SLR1 v 2.x.

Fórmula --> Suma ;Suma --> Suma '+' Producto | Suma '-' Producto | Producto ;Producto --> Producto '*' Factor | Producto '/' Factor | Factor ;Factor --> Numero | '(' Suma ')' | '-' Factor ;

Una Calculadora Simple

193

Page 194: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La gramática precedente define precedencias de operadores, se lasresume en la siguiente tabla:

Orden Operador Observaciones

1. La más alta ( )-

Paréntesis Menos unario

2 */

Multiplicación División

3. La más baja +-

Suma Resta

Fig. 19 Precedencia de operadores de una expresión aritmética

No se incluye la posibilidad de incluir variables en una expresiónaritmética.

Los siguientes son ejemplos de expresiones aritméticas:

Ejemplo 1: 2*5+3*2 Resultado: 16

Ejemplo 2: -32/4 + 2 Resultado: -6

La estructura de un número se describe mediante la siguiente expresiónregular, la que define números muy similares a los de punto flotante del C++:

// Expresión regular para un número real en formato C++:# Díg [0-9]Díg * '.' ? Díg + ( (e | E) Díg + ) ?

El analizador lexicográfico ignorará los espacios en blanco. Seconsidera espacio en blanco a:

[ \n\r\f\t\v] +

Donde \n es nueva línea, \r es retorno de carro, \f es alimentación de página, \tes tab y \v es tabulado vertical.

14.1.3 Las Acciones Semánticas

Las acciones semánticas que se incluirán realizan directamente laevaluación de la expresión aritmética, usando la pila para acarrear losresultados parciales de los distintos subárboles. El resultado final seencontrará en la raíz del árbol de análisis sintáctico.

Una Calculadora Simple

194

Page 195: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El tipo de elemento de la pila se cambia a ElemPilaCalc, la que agregaa ElemPila el resultado parcial para esa posición de la pila. La declaración dela clase se la da en el archivo CALC.GLC, la que finalmente irá a parar alarchivo CALC.CMM.

La interfase en pantalla del programa será generado por ApplicationExpert, el generador de aplicaciones para OWL 2.x de Borland C++. Sólo seagregó un poco de código a un módulo generado por AppExpert.

Las acciones semánticas se muestran en el archivo CALC.GLC. Enparticular se debe observar la que se da para la regla "Fórmula --> Suma" quecoloca el resultado final de la evaluación en una variable global llamadaResultadoFinal. También se debe observar que el error de división por 0 sedetecta en la acción semántica para la regla de división, y se fija la variableglobal ErrDivPor0 a 1 si hay problemas. De esta manera el sistema operativono detiene la ejecución del programa por división por 0.

14.1.4 La función Evaluar

La función Evaluar que se encuentra en el módulo EVALUAR.CMMes la que realiza la evaluación de una expresión aritmética. Oculta todo elprocesamiento que se realiza para evaluar la expresión aritmética dada enformato texto plano y emitir el resultado en formato double (real de dobleprecisión) del C++.

El prototipo de la misma es el siguiente:

Ent8 Evaluar( const char * Formula, double & Resultado );

El parámetro Formula es una cadena de caracteres válida del C++conteniendo la fórmula a evaluar. Básicamente es un texto plano, sin formato.Se lo puede obtener de cualquier forma.

El parámetro Resultado es el resultado de la evaluación de la Formula.

La función devuelve 0 si hay error de sintaxis, lexicográfico o divisiónpor 0, y distinto a 0 si no hay problemas. Si no hay problemas, Resultadocontiene el resultado final.

Una Calculadora Simple

195

Page 196: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

14.2 Módulos fuentes independientes del Sistema Operativo

A continuación se enumeran los modulos fuentes que han sido escritospara la calculadora y que son independientes del sistema operativo.

14.2.1 CALC.GLC: La gramática con acciones semánticas

Este módulo se debe especificar como entrada para SLR1 v 2.x. A partirdel mismo se generan los módulos CALC.CMM, CALC.TAB y CALC.EST.

// Gramática fuente para una calculadora simple.// Versión 1.0 - Domingo E. Becker, Tel (085) 22-2488

%{# ifndef __SLR1_H // por las dudas# include "slr1.h"# endif

class ElemPilaCalc : public ElemPila {public: double Resultado; // resultado de la operación hasta esta posición.

ElemPilaCalc() { } ~ElemPilaCalc() { }};

static double ResultadoFinal;static Ent8 ErrDivPor0;

}%

// definiciones para el analizador lexicográfico:

# TERMINAL Numero // en numero.er está la expresión regular# IGNORAR Blancos

// elemento de la pila# ELEMPILA ElemPilaCalc

// Reglas:

Fórmula --> Suma %{ ResultadoFinal = $1.Resultado; // asignamos a variable global. }% ;

Suma --> Suma '+' Producto %{ $$.Resultado = $1.Resultado + $3.Resultado; }% | Suma '-' Producto %{ $$.Resultado = $1.Resultado - $3.Resultado; }% | Producto ;

Producto --> Producto '*' Factor %{ $$.Resultado = $1.Resultado * $3.Resultado; }% | Producto '/' Factor %{ if ($3.Resultado != 0) $$.Resultado = $1.Resultado / $3.Resultado; else ErrDivPor0 = 1; }% | Factor ;

Una Calculadora Simple

196

Page 197: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Factor --> Numero %{ $$.Resultado = $1.CadTerm; // conversión automática de tipo por // Ascii0 }% | '(' Suma ')' %{ $$.Resultado = $2.Resultado; }% | '-' Factor %{ $$.Resultado = - $2.Resultado; }% ;

14.2.2 CALC.CMM: módulo generado por SLR1 v 2.x

A partir de CALC.GLC se generó este módulo en el cual SLR1 v 2.xescribió la función con las acciones semánticas, el analizador lexicográfico yel analizador sintáctico.

Se lo incluye aquí a modo de ejemplo.

// Código fuente generado por SLR1 versión 2.2 (Dic 95)// Domingo Eduardo Becker, Sgo. del Estero, Tel (085) 22-2488

// Código de acciones semánticas.// Código generado por Gramatica::ImprAccSem versión 2.// Domingo Eduardo Becker.

# ifndef __SLR1_H# include "slr1.h"# endif

// Código fuente previo a las acciones semánticas.

# ifndef __SLR1_H // por las dudas# include "slr1.h"# endif

class ElemPilaCalc : public ElemPila {public: double Resultado; // resultado de la operación hasta esta posición.

ElemPilaCalc() { } ~ElemPilaCalc() { }};

static double ResultadoFinal;static Ent8 ErrDivPor0;

// Fin del código fuente previo a las acciones semánticas.

void AccSemCalc( Ent16ns NumRegla, ElemPilaCalc * Pila, Ent16ns PP ) { switch (NumRegla) { case 1: // Fórmula ---> Suma { ResultadoFinal = Pila[PP+1].Resultado; // asignamos a variableglobal. } break;

case 2: // Suma ---> Suma '+' Producto { Pila[PP+1].Resultado = Pila[PP+1].Resultado + Pila[PP+3].Resultado; } break;

Una Calculadora Simple

197

Page 198: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case 3: // Suma ---> Suma '-' Producto { Pila[PP+1].Resultado = Pila[PP+1].Resultado - Pila[PP+3].Resultado; } break;

case 5: // Producto ---> Producto '*' Factor { Pila[PP+1].Resultado = Pila[PP+1].Resultado * Pila[PP+3].Resultado; } break;

case 6: // Producto ---> Producto '/' Factor { if (Pila[PP+3].Resultado != 0) Pila[PP+1].Resultado = Pila[PP+1].Resultado / Pila[PP+3].Resultado; else ErrDivPor0 = 1; } break;

case 8: // Factor ---> Numero { Pila[PP+1].Resultado = Pila[PP+1].CadTerm; // conversión automáticade tipo por Ascii0 } break;

case 9: // Factor ---> '(' Suma ')' { Pila[PP+1].Resultado = Pila[PP+2].Resultado; } break;

case 10: // Factor ---> '-' Factor { Pila[PP+1].Resultado = - Pila[PP+2].Resultado; } break; } // switch (NumRegla)} // Fin de AccSemCalc

// Fin del código de acciones semánticas.

// Analizador lexicográfico para la gramática.// Generado por Gramatica::ImprAnaLex versión 2.// Domingo Eduardo Becker.

# ifndef __EXPREG_H# include "expreg.h"# endif

# include "Blancos.cmm" // afdBlancos# include "Numero.cmm" // afdNumero

static RecSimb vrs[] = { 1, 0, 0, "+", 2, 0, 0, "-", 3, 0, 0, "*", 4, 0, 0, "/", 5, 1, & afdNumero, 0, 6, 0, 0, "(", 7, 0, 0, ")", 0, 1, & afdBlancos, 0};

# define NUMRECSIMB 8

AnaLex alCalc(vrs, NUMRECSIMB);

// Definición del analizador sintáctico (SLR1 v 2.2).

Una Calculadora Simple

198

Page 199: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Cambiar de lugar la definición si es necesario.

# include "CALC.tab" // tablas del analizador sintáctico

AnalSLR1<ElemPilaCalc> asCalc(ntlpdCalc, accionCalc, ir_aCalc,AccSemCalc);

14.2.3 NUMERO.ER: expresión regular para un número real no negativo

La expresión regular que se encuentra en este módulo se especificacomo entrada a AFD v 3.x. El sufijo a utilizar es Numero.

// Expresión regular para un número real en formato C++:# Díg [0-9]Díg * '.' ? Díg + ( (e | E) Díg + ) ?

14.2.4 BLANCOS.ER: expresión regular para los blancos de un texto

La expresión regular siguiente se especificará como entrada a AFD v3.x. El sufijo a utilizar es Blancos.

// Expresión regular para blancos:[ \n\r\f\t\v] +

14.2.5 NUMERO.CMM: generado por AFD v 3.x a partir de NUMERO.ER

Se lo incluye a modo de ejemplo.

// AFD generado por la versión 3.4 de ExpReg::Reasignar (Nov 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erNumero[] = "// Expresión regular para un número realen formato C++:\r\n# Díg [0-9]\r\nDíg * \'.\' ? Díg + ( (e | E) Díg + )?\r\n";static const char * vcNumero[] = { "0-9", ".", "e", "E"};static const Ent16ns tNumero[] = { 1, 2, TNDEF, TNDEF, 1, 2, 3, 3, 4, TNDEF, TNDEF, TNDEF, 5, TNDEF, TNDEF, TNDEF, 4, TNDEF, 3, 3, 5, TNDEF, TNDEF, TNDEF};static const Ent16ns efNumero[] = { 3, 1, 4, 5};AutomFinDet afdNumero = { erNumero, vcNumero, 4, tNumero, efNumero };

Una Calculadora Simple

199

Page 200: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

14.2.6 BLANCOS.CMM: generado por AFD v 3.x a partir de BLANCOS.ER

Se lo incluye a modo de ejemplo.

// AFD generado por la versión 3.4 de ExpReg::Reasignar (Nov 95)// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.

# ifndef __EXPREG_H# include "expreg.h"# endif

static const char erNumero[] = "// Expresión regular para un número realen formato C++:\r\n# Díg [0-9]\r\nDíg * \'.\' ? Díg + ( (e | E) Díg + )?\r\n";static const char * vcNumero[] = { "0-9", ".", "e", "E"};static const Ent16ns tNumero[] = { 1, 2, TNDEF, TNDEF, 1, 2, 3, 3, 4, TNDEF, TNDEF, TNDEF, 5, TNDEF, TNDEF, TNDEF, 4, TNDEF, 3, 3, 5, TNDEF, TNDEF, TNDEF};static const Ent16ns efNumero[] = { 3, 1, 4, 5};AutomFinDet afdNumero = { erNumero, vcNumero, 4, tNumero, efNumero };

14.2.7 EVALUAR.CMM: función Evaluar

Obsérvese en este módulo la simplicidad del uso del analizadorsintáctico y del analizador lexicográfico generado.

// evaluar.cmm Jue 07 Dic 95// Domingo E. Becker

# include "calc.cmm" // generado a partir de calc.glc por SLR1 v 2.x

Ent8 Evaluar( const char * Formula, double & Resultado ) { if (Formula == 0) return 0; // imposible evaluar Formula alCalc.Reiniciar(Formula); Ascii0 CadPosErr; ErrDivPor0 = 0; Ent8 r = asCalc.Analizar(alCalc, CadPosErr) && ! ErrDivPor0; if (r) Resultado = ResultadoFinal; return r;}

14.3 Módulos dependientes del sistema operativo

La interfase en pantalla es la parte dependiente del sistema operativo dela calculadora.

Una Calculadora Simple

200

Page 201: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Se eligió hacer un diálogo en el que habrá un campo de entrada de textoen donde se escribirá la fórmula a evaluar, otro en donde se mostrará elresultado, una lista de cadenas en donde se encuentren las últimas fórmulasevaluadas y dos botones, uno para evaluar y otro para salir (ver figura 20).

Visualmente se ve lo siguiente:

Fig. 20 Ventana principal de la Calculadora.

La ventana ha sido construida usando el Resource Workshop delBorland C++. AppExpert se encargó de realizar y controlar todas lasconexiones del diálogo con el código fuente que él mismo generó.

Se hace la observación de que todos los módulos pueden serrecompilados sin ninguna modificación con el Borland C++ 2.0 para OS/2.Sólo se debe procesar el archivo CALCAPP.RC con el convertidor de recursospara convertirlo a formato Presentation Manager de OS/2 (el procesado es muysimple).

Los módulos fuente generado se muestran a continuación.

14.3.1 CALCAPP.H: generado por AppExpert

#if !defined(__calcapp_h) // Sentry, use file only if it'snot already included.#define __calcapp_h

/* Project calc Copyright © 1995. All Rights Reserved.

Una Calculadora Simple

201

Page 202: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

SUBSYSTEM: calc.exe Application FILE: calcapp.h AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Class definition for TCalcApp (TApplication). */

#include <owl\owlpch.h>#pragma hdrstop

#include "calcapp.rh" // Definition of all resources.

//{{TApplication = TCalcApp}}class TCalcApp : public TApplication {private:

public: TCalcApp (); virtual ~TCalcApp ();

//{{TCalcAppVIRTUAL_BEGIN}}public: virtual void InitMainWindow();//{{TCalcAppVIRTUAL_END}}

//{{TCalcAppRSP_TBL_BEGIN}}protected: void CmHelpAbout ();//{{TCalcAppRSP_TBL_END}}DECLARE_RESPONSE_TABLE(TCalcApp);}; //{{TCalcApp}}

#endif // __calcapp_h sentry.

14.3.2 CALCDLG.H: generado por AppExpert

#if !defined(__calcdlg_h) // Sentry, use file only if it'snot already included.#define __calcdlg_h

/* Project calc Copyright © 1995. All Rights Reserved.

SUBSYSTEM: calc.exe Application FILE: calcdlg.h AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Class definition for TCalcDLGClient (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

Una Calculadora Simple

202

Page 203: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

#include <owl\edit.h>#include <owl\listbox.h>#include "calcapp.rh" // Definition of all resources.

//{{TDialog = TCalcDLGClient}}struct TCalcDLGClientXfer {//{{TCalcDLGClientXFER_DATA}} TListBoxData ListaDeFormulas;//{{TCalcDLGClientXFER_DATA_END}}};

class TCalcDLGClient : public TDialog {public:

TCalcDLGClient (TWindow *parent, TResId resId = IDD_CLIENT, TModule*module = 0); virtual ~TCalcDLGClient ();

//{{TCalcDLGClientVIRTUAL_BEGIN}}public: virtual void SetupWindow ();//{{TCalcDLGClientVIRTUAL_END}}

//{{TCalcDLGClientRSP_TBL_BEGIN}}protected: void Evaluar (); void DobleClickLista ();//{{TCalcDLGClientRSP_TBL_END}}DECLARE_RESPONSE_TABLE(TCalcDLGClient);

//{{TCalcDLGClientXFER_DEF}}protected: TListBox *ListaDeFormulas;

//{{TCalcDLGClientXFER_DEF_END}}}; //{{TCalcDLGClient}}

#endif // __calcdlg_h sentry.

14.3.3 CALCAPP.CMM: generado por AppExpert

/* Project calc Copyright © 1995. All Rights Reserved.

SUBSYSTEM: calc.exe Application FILE: calcapp.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of TCalcApp (TApplication). */

#include <owl\owlpch.h>#pragma hdrstop

#include "calcapp.h"

Una Calculadora Simple

203

Page 204: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

#include "calcdlg.h" // Definition of client class.

//{{TCalcApp Implementation}}

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(TCalcApp, TApplication)//{{TCalcAppRSP_TBL_BEGIN}} EV_COMMAND(CM_HELPABOUT, CmHelpAbout),//{{TCalcAppRSP_TBL_END}}END_RESPONSE_TABLE;

//////////////////////////////////////////////////////////// TCalcApp// =====//TCalcApp::TCalcApp () : TApplication("Calculadora"){

// INSERT>> Your constructor code here.}

TCalcApp::~TCalcApp (){ // INSERT>> Your destructor code here.}

//////////////////////////////////////////////////////////// TCalcApp// =====// Application intialization.//void TCalcApp::InitMainWindow (){// if (nCmdShow != SW_HIDE)// nCmdShow = (nCmdShow != SW_SHOWMINNOACTIVE) ? SW_SHOWNORMAL :nCmdShow;

TFrameWindow *frame = new TFrameWindow(0, GetName(), newTCalcDLGClient(0), true);

// Override the default window style for the main window.// frame->Attr.Style |= WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN |WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE; frame->Attr.Style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);

// // Assign ICON w/ this application. // frame->SetIcon(this, IDI_SDIAPPLICATION);

SetMainWindow(frame);

}

//////////////////////////////////////////////////////////

Una Calculadora Simple

204

Page 205: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// TCalcApp// ===========// Menu Help About calc.exe commandvoid TCalcApp::CmHelpAbout (){}

int OwlMain (int , char* []){ try { TCalcApp app; return app.Run(); } catch (xmsg& x) { ::MessageBox(0, x.why().c_str(), "Exception", MB_OK); }

return -1;}

14.3.4 CALCDLG.CMM: generado por AppExpert y modificado por el autor

Usando Class Expert (del AppExpert) se agregaron respuestas al botónEvaluar y al doble click con el ratón a una fórmula dentro de la lista defórmulas ya evaluadas. Las funciones se llaman TCalcDLGClient::Evaluar yTCalcDLGClient::DobleClickLista respectivamente.

/* Project calc Copyright © 1995. All Rights Reserved.

SUBSYSTEM: calc.exe Application FILE: calcdlg.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of TCalcDLGClient (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "calcapp.h"#include "calcdlg.h"

# include <ascii0.h>Ent8 Evaluar( const char * Formula, double & Resultado );

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(TCalcDLGClient, TDialog)//{{TCalcDLGClientRSP_TBL_BEGIN}} EV_BN_CLICKED(IDOK, Evaluar), EV_LBN_DBLCLK(IDC_LISTAFORMULAS, DobleClickLista),//{{TCalcDLGClientRSP_TBL_END}}END_RESPONSE_TABLE;

Una Calculadora Simple

205

Page 206: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

//{{TCalcDLGClient Implementation}}

//////////////////////////////////////////////////////////// TCalcDLGClient// ==========// Construction/Destruction handling.static TCalcDLGClientXfer TCalcDLGClientData;

TCalcDLGClient::TCalcDLGClient (TWindow *parent, TResId resId, TModule*module) : TDialog(parent, resId, module){//{{TCalcDLGClientXFER_USE}} ListaDeFormulas = new TListBox(this, IDC_LISTAFORMULAS);

SetTransferBuffer(&TCalcDLGClientData);//{{TCalcDLGClientXFER_USE_END}}

// INSERT>> Your constructor code here.}

TCalcDLGClient::~TCalcDLGClient (){ Destroy();

// INSERT>> Your destructor code here.}

void TCalcDLGClient::Evaluar (){ // INSERT>> Your code here. Ascii0 formula(300), resultadoAscii; double resultado; Ent8 r; GetDlgItemText(IDC_FORMULA, formula, formula.TamBlq()); if (formula.Long()) { if (::Evaluar(formula, resultado)) { resultadoAscii = resultado; SetDlgItemText(IDC_RESULTADO, resultadoAscii); } else SetDlgItemText(IDC_RESULTADO, "Error"); ListaDeFormulas->InsertString(formula, 0); }}

void TCalcDLGClient::DobleClickLista (){ // INSERT>> Your code here. Ascii0 cad(300); ListaDeFormulas->GetSelString(cad, cad.TamBlq()); if (cad.Long()) { SetDlgItemText(IDC_FORMULA, cad); TWindow(GetDlgItem(IDC_FORMULA)).SetFocus();// Formula->SetFocus(); }}

void TCalcDLGClient::SetupWindow (){ TDialog::SetupWindow();

Una Calculadora Simple

206

Page 207: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// INSERT>> Your code here. TWindow(GetDlgItem(IDC_FORMULA)).SetFocus();// Formula->SetFocus();}

Una Calculadora Simple

207

Page 208: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 15: Consultas a Archivos Base de Datos BCE

El ejemplo desarrollado en este capítulo es un ejemplo de recuperacióninteligente de la información en memoria. A tal efecto, antes se debe recuperarla información de un archivo base de datos.

Cuando sea oportuno se mostrarán analogías con las sentencias deconsultas SQL (structured query language).

La Biblioteca BCE para C++ se usa aquí como una herramienta. ElAdministrador de Archivos Bases de Datos BCE es parte de esa biblioteca, yaunque su código fuente es incluido al final de este capítulo, su documentaciónno se incluye.

15.1 Conceptos Teóricos Básicos

15.1.1 Bases de Datos

Un archivo base de datos es una colección de registros, en el que seincluye principalmente información sobre la descripción de la estructura delregistro, así como también otra información que pueda ser importante.

Se puede representar por uno o más archivos del nivel del SistemaOperativo, aunque usualmente, un archivo base de datos se representa con unarchivo del sistema operativo.

Se denomina archivo del sistema operativo al concepto de archivoofrecido por el mismo. Un archivo para el sistema operativo es una colecciónde bytes, cada uno de los cuales pueden ser accedidos al azar como un vector(si se desea) o bien secuencialmente, y de la E/S se encarga el SistemaOperativo. En general, un archivo del sistema operativo reside en memoriapersistente (disco, cinta, etc.).

En la documentación de Paradox (cualquier versión) y dBase V, a losarchivos bases de datos se los denomina tablas. Una base de datos es unacolección de tablas (archivos bases de datos). Se denomina cursor al nombrelógico usado para acceder a la tabla. Para una tabla, en una misma sesiónpueden haber varios cursores. La denominación de tabla proviene de laconfección manual de tablas que antes se hacía, un archivo base de datos debe

Consultas a Archivos Base de Datos BCE

208

Page 209: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ser visto como una tabla en donde las filas son los registros y las columnas sonlos campos de los registros.

A continuación, archivo base de datos se abreviará ABD.

La razón de almacenar la descripción de la estructura del registro en elarchivo es la de obtener la independencia del código fuente de la estructura delregistro. Si no se usan ABDs, una vez escrito el código fuente, si la estructuradel registro cambia se debe retocar el código fuente. En cambio, si se usaranABDs, sólo se deben retocar los campos que cambiaron y/o agregar losaccesos a los campos nuevos.

El acceso a la implementación lógica del registro lo realiza elAdministrador de Archivos Bases de Datos. El administrador de bases de datostrata con varias bases de datos a la vez; no debe ser confundido con eladministrador de ABDs. El acceso a la implementación física del registro en elmedio lo realiza el sistema operativo.

Para este ejemplo, se utilizará el Administrador de Archivos Bases deDatos de la Biblioteca BCE, cuyo autor es quien suscribe. El código fuente seincluye al final de este capítulo.

15.1.2 El Lenguaje de Consultas Estructurado (SQL)

Con la aparición de las bases de datos se hizo necesario un lenguajeespecial que pudiera describir transacciones con los mismos. Estos lenguajesrecibieron el nombre de lenguajes para bases de datos, de entre todos ellos, elmás popular es el del dBase, el cual fue definido por convención como elestándar. Lamentablemente (para los programadores serios), ese lenguaje naciócomo un engendro que no cumplía con los conceptos más básicos yfundamentales de la ingeniería del software, pero era fácil de aprender yentender para los novatos que no tenían ninguna idea de programación. (Siresulta que un programador acostumbrado a trabajar con lenguajes como elC++ aprende el dBase, lo primero que se le viene a la cabeza es decir que,como lenguaje de programación, el dBase es un desastre. Esto no quita de quesea posible realizar grandes proyectos de programación con él.). A todo estohay que agregarle que cada empresa que construía un paquete de bases dedatos comercial, hacía un lenguaje que se decía ser compatible dBase, lo cualno resultó ser cierto.

Con el lenguaje de consultas estructurado se intentó unificar los criteriosy conceptos, así como también ofrecer un conjunto de comandos que permiten

Consultas a Archivos Base de Datos BCE

209

Page 210: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

agregar, cambiar y borrar datos, y una gran habilidad para consultar sincodificar demasiado. De todas las sentencias que tiene ese lenguaje, la másinteresante y difícil de implementar es la sentencia SELECT.

La sentencia SELECT selecciona registros de una base de datos deacuerdo a ciertos criterios que se especifican con cláusulas. Entre esascláusulas se encuentra la cláusula LIKE que significa parecido a. La inclusiónde esta cláusula hace necesario el uso de expresiones regulares para especificarla forma general a la que debe parecerse. El resultado de esta sentencia es unanueva tabla que contiene los registros seleccionados. Queda a consideracióndel diseñador del administrador de bases de datos si se creará la tabla nueva osi se trabajará directamente con las tablas que participan en la sentenciaSELECT.

El lenguaje Object PAL de Paradox 1.0 para Windows en adelante,incluye una sentencia muy interesante que comienza con la palabra claveQUERY, y no es otra cosa que la codificación de una consulta medianteejemplos. En esa sentencia se incluye también la cláusula LIKE, conposibilidades similares a la cláusula LIKE de una sentencia SELECT de SQL.El resultado de una consulta con QUERY es una tabla, que tiene un nombrefísico por defecto si no se lo especifica.

En este ejemplo se simulará el funcionamiento del selector de registrosde un administrador de bases de datos que trabaja con un lenguaje SQL.

15.1.3 Niveles de Abstracción en el Administrador de Archivos Bases deDatos BCE.

La clase Archivo define la interfase general y mínima de una clase quese dice ser Archivo. En BCE un Archivo es un recipiente de bytes, con accesosbásicos de lectura y escritura para los tipos de datos fundamentales (seconsideran tipos de datos fundamentales a los tipos que provee el compilador).La clase Archivo es abstracta, lo que significa que no se pueden definirobjetos de esta clase. Esta clase define el nivel más bajo de abstracción.Cualquier detalle particular de una implementación deberá ser ocultado por laclase derivada.

La clase ArchivoSO es una clase derivada de Archivo, en la que se dandefiniciones a las funciones virtuales puras declaradas en la clase base. Estaclase sirve de interfase para el acceso a las funciones básicas para el manejo dearchivos en dispositivos de almacenamiento masivo ofrecidas por el SistemaOperativo. Las funciones básicas que ofrece el sistema operativo son: abrir,

Consultas a Archivos Base de Datos BCE

210

Page 211: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

leer, escribir, posicionar el puntero de archivo y cerrar. En ArchivoSO seprovee el acceso directo a estas funciones. Para la E/S de datos se provee laposibilidad de controlar si será binaria o en formato texto. Si es binario, porejemplo para un float se escribiría sizeof(float) = 4 bytes, en cambio, si es enformato entonces se pueden llegar a escribir hasta 32 bytes, que serán loscaracteres correspondientes a la representación en texto del número.

La clase ArchivoSO está en el mismo nivel de abstracción que la claseArchivo, sólo es una implementación particular del concepto de archivointroducido por BCE (que no es otra cosa que el mismo concepto introducidopor COBOL).

La clase ArchBD (que no es derivada de Archivo) implementa eladministrador de archivos bases de datos. El código del administrador son lasfunciones miembro de esta clase. Cada objeto de esta clase es el nombre lógicode un archivo base de datos; en Paradox o dBase se diría cursor. Para cadaarchivo físico pueden haber varios cursores, esto es, varios objetos ArchBDcon los que se estén realizando accesos. Esta clase ofrece las siguientesfunciones básicas: abrir, leer registro, escribir registro, posicionar el punterode archivo, cerrar y acceder a un campo particular del registro. Esta clase estáen un nivel más alto de abstracción que la clase Archivo. En ArchBD losaccesos se hacen por bloques de bytes, todos del mismo tamaño, a los que selos denomina registro. La estructura de los registros se incluye en el mismoarchivo físico.

15.1.4 Coincidencia exacta / ocurrencia

Dada una expresión que define un lenguaje (puede ser una expresiónregular o un literal), se dirá que hay coincidencia exacta entre una cadena decaracteres y la expresión dada si la cadena de caracteres pertenece al lenguajedefinido por la expresión (es oración de ese lenguaje).

Por el contrario, se dirá que hay una ocurrencia de una oración dellenguaje definido por la expresión dentro de la cadena de caracteres dada, siexiste alguna subcadena dentro de la cadena dada para la cual hay coincidenciaexacta con la expresión dada.

Para los usuarios normales de computadoras (que en general no sonprogramadores), las definiciones precedentes son más comprensibles que losconceptos manejados en la Teoría de los Lenguajes Formales. Se los defineaquí para poder usarlos más adelante en este ejemplo.

Consultas a Archivos Base de Datos BCE

211

Page 212: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Se debe recordar que si la expresión dada es tomada como un literal, ellenguaje definido por la misma tendrá sólo una oración. Puede tener más deuna oración si es tomada como expresión regular.

15.2 Análisis y Diseño

15.2.1 Objetivos y metas de este ejemplo

El objetivo de este ejemplo es el de acceder a un archivo base de datosBCE, y permitir realizar una consulta para un solo campo del mismo.

Las metas para llegar al objetivo son:

1. Leer la estructura del registro y mostrar los campos del mismo enpantalla, permitiendo la selección de un solo campo.

2. Definir una expresión que dirá cómo debe ser el contenido de un campo.Asimismo, se incluirá la posibilidad de usar expresiones regulares y deindicar si la concordancia debe ser exacta o que contenga.

3. Para todos los campos que cumplen con la expresión dada se mostrará elnúmero de registro y el contenido del campo en la pantalla.

15.2.2 Visión general del diseño de la interfase y el funcionamiento

La interfase en pantalla del programa es la siguiente:

Consultas a Archivos Base de Datos BCE

212

Page 213: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 21 Ventana principal del programa ejemplo de consultas

Al arrancar el programa se le pedirá al usuario que ingrese un nombre dearchivo o lo busque en los dispositivos de almacenamiento masivo. Una vezhecho esto se muestra el nombre del archivo en el campo Archivo de laventana principal (ver Fig. 21). En la lista etiquetada con Campo a consultar

se muestran los campos del archivo seleccionado, de los cuales se deberáseleccionar uno.

En el campo Expresión se debe ingresar la expresión a usar en laconsulta, la que puede ser un literal o una expresión regular (en ambos casoses una cadena de caracteres). Si es una expresión regular, se debe chequear lacaja de chequeo etiquetada con Expresión Regular (aparecerá una cruz dentrodel cuadradito cuando esté chequeada, de manera similar a la que se muestraen la misma Fig. 21).

Si la consulta a realizar es por coincidencia exacta, la caja de chequeoetiquetada con Que contenga no debe estar chequeada. Si, en cambio, se busca

Consultas a Archivos Base de Datos BCE

213

Page 214: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

una ocurrencia de una oración dentro del campo a consultar, la caja dechequeo Que contenga debe estar chequeada (con una cruz).

Para realizar la consulta se debe presionar el botón Consultar. Parapoder consultar se debe ingresar la expresión regular y seleccionar el campo aconsultar, caso contrario habrá error. Una vez presionado el botón paraconsultar, se limpiará la lista Registros que verifican y se la llenará con loscontenidos de los campos de los registros que verifican con la expresióningresada. Primero se colocará el número de registro y luego el valor delcampo.

En el único momento en que se mantiene abierto el archivo es cuando seestá realizando la consulta (desde el momento de presionar Consultar hasta elmomento en que se terminó de recorrer todo el archivo; luego se lo cierra). Deesta manera se minimiza el número de archivos abiertos en el sistema.

El botón Otro archivo permite seleccionar otro archivo base de datos. Eldiálogo para ingresar el nombre es similar al que se muestra al arrancar elprograma, y es el estándar del API (application programming interfase) delsistema. Al aceptar el nombre, se intenta abrir el archivo base de datos. Si nohay problemas, se extraen los nombres de los campos y se los muestra en lalista Campo a consultar (previo vaciado de la misma); luego se cierra elarchivo. Si no se puede abrir el archivo entonces se vuelve al estado anteriorde la pantalla principal.

15.2.3 Implementación de la carga de la lista de campos

La carga de la lista de campos la realiza la función ConsDlgClient::

CargarCampos, donde ConsDlgClient es la clase que representa a la ventanaprincipal.

Se intenta abrir el archivo base de datos cuyo nombre se pasa comoparámetro. Si la apertura del archivo no falla, se limpia la lista de campos y sela llena con los campos del archivo que se acaba de abrir. Las funcionesutilizada para averiguar los campos son: ArchBD::NumCampos yArchBD::CampoNumero. La segunda devuelve el nombre del campo cuyoíndice se pasa como parámetro.

Al finalizar la carga de la lista de campos se cierra el archivo base dedatos.

Consultas a Archivos Base de Datos BCE

214

Page 215: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

15.2.4 Implementación de la función que realiza la consulta

La función que recibe la petición del usuario de realizar una consultacon los parámetros ingresados por pantalla es ConsDlgClient::Consultar. Lafunción que realiza la consulta se llama Consultar y es global.

El prototipo de la función Consultar es el siguiente:

Ent16 Consultar( const char * NomArchBD, const char * Campo, TListBox * Registros, const char * Expresion, Ent8 EsExpReg = 1, Ent8 QueContenga = 1 );

El parámetro NomArchBD recibe el nombre del archivo base de datos aconsultar.

El parámetro Campo es el nombre del campo con el que se trabajará.

El parámetro Registros es una lista de cadenas de caracteres.Inicialmente se la vaciará. Luego se la llenará con los registros cuyo campoCampo cumple con la expresión dada en Expresion.

El parámetro Expresion contiene la expresión a usar para la consulta.

El parámetro EsExpReg contiene 0 si Expresion no es expresiónregular, y distinto de 0 si es expresión regular. El valor por defecto es queExpresion es expresión regular.

El parámetro QueContenga tiene 0 si se buscará coincidencia exacta, ydistinto a 0 si se buscarán ocurrencias. El valor por defecto es buscarocurrencias.

Si se observa el código fuente de esta función (en el móduloDLGCLI.CMM) se verá la simplicidad de la misma. Esta función sólo utilizafunciones provistas por el Administrador de Archivos Bases de Datos BCE,por la biblioteca ExpReg v 1.x y por la biblioteca estándar del C++.

Los registros se leen uno por uno. Para cada uno, se extrae el campo enformato texto en una variable aparte del tipo Ascii0, con nombreCampoRegAct. Luego, como el contenido del campo está en la memoria de lamáquina, entonces la recuperación inteligente de la información (consulta) sela realiza en memoria.

Si EsExpReg entonces se utiliza un objeto ExpReg para realizar laconsulta. En este caso, si se buscan ocurrencias (QueContenga) entonces se

Consultas a Archivos Base de Datos BCE

215

Page 216: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

usa la función ExpReg::Buscar, caso contrario se usa la función ExpReg::

Examinar. Estas dos funciones son de la biblioteca ExpReg.

Si no EsExpReg entonces se hace simple comparación de cadenas conalguna función estándar del C++, a saber: si se buscan ocurrencias se utiliza lafunción strstr, y si se busca coincidencia exacta entonces stricmp. Esta últimarealiza comparación de cadenas asumiendo que las mayúsculas son iguales alas minúsculas.

Si el campo seleccionado no es una cadena de caracteres (es algún otrotipo que fue almacenado en formato binario), entonces la conversión a cadenade caracteres se realiza automáticamente. Se utiliza la función ArchBD::

SacarCampoAutoConv, que convierte a texto automáticamente si el campo aextraer es almacenado en formato binario. Esta función da soporte a todos lostipos de datos fundamentales del C++, y trabaja conjuntamente con la claseAscii0 de BCE.

15.3 Módulos fuentes de este ejemplo

Gran parte de los módulos fuente han sido generado por AppExpert, elgenerador de interfases de aplicaciones que utilizan OWL 2.x para Windows yOS/2, del Turbo C++ 4.5 para Windows. La aplicación generada fue probadaen Windows. Procesando el archivo de recursos generado con el conversor derecursos del Borland C++ 2.0 para OS/2 se lo puede recompilar sin problemasy obtener una versión para OS/2 de este ejemplo.

Los módulos fuentes que han sido retocados por el autor a efectos de laimplementación del ejemplo son DLGCLI.CMM y DLGCLI.H.

A continuación se enumerarán los módulos fuentes.

15.3.1 DLGCLI.CMM: generado por AppExpert y modificado por el autor

/* Project consulta Copyright © 1996. All Rights Reserved.

SUBSYSTEM: consulta.exe Application FILE: dlgcli.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of ConsDlgClient (TDialog).

Consultas a Archivos Base de Datos BCE

216

Page 217: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

*/

#include <owl\owlpch.h>#pragma hdrstop

#include "consapp.h"#include "dlgcli.h"

# include <owl\opensave.h># include <bd.h># include <expreg.h>

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(ConsDlgClient, TDialog)//{{ConsDlgClientRSP_TBL_BEGIN}} EV_BN_CLICKED(IDC_CONSULTAR, Consultar), EV_BN_CLICKED(IDC_CAMBIARARCH, CambiarArchivo),//{{ConsDlgClientRSP_TBL_END}}END_RESPONSE_TABLE;

//{{ConsDlgClient Implementation}}

//////////////////////////////////////////////////////////// ConsDlgClient// ==========// Construction/Destruction handling.static ConsDlgClientXfer ConsDlgClientData;

ConsDlgClient::ConsDlgClient (TWindow *parent, TResId resId, TModule*module) : TDialog(parent, resId, module){//{{ConsDlgClientXFER_USE}} ListaDeCampos = new TListBox(this, IDC_CAMPOS); ListaDeRegistros = new TListBox(this, IDC_REGISTROS); QueContenga = new TCheckBox(this, IDC_CONTENGA, 0); EsExpReg = new TCheckBox(this, IDC_EXPREG, 0);

SetTransferBuffer(&ConsDlgClientData);//{{ConsDlgClientXFER_USE_END}}

// INSERT>> Your constructor code here.}

ConsDlgClient::~ConsDlgClient (){ Destroy();

// INSERT>> Your destructor code here.}

const char NomArch[] = "agenda.bd";

int ConsDlgClient::CargarCampos( const char * NomArch, TListBox * Campos ){ ArchBD arch; if (arch.Abrir(NomArch, MA_L)) return CodError;

Consultas a Archivos Base de Datos BCE

217

Page 218: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Campos->ClearList(); Ent16ns i, NumCampos = arch.NumCampos(); for (i = 0; i < NumCampos; ++i) ListaDeCampos->AddString( arch.CampoNumero(i)->Nombre );

arch.Cerrar();

return CodError;}

void ConsDlgClient::SetupWindow (){ TDialog::SetupWindow();

// INSERT>> Your code here. ListaDeCampos->ClearList(); ListaDeRegistros->ClearList(); QueContenga->SetCheck(BF_CHECKED); EsExpReg->SetCheck(BF_CHECKED); CambiarArchivo();}

Ent16 Consultar( const char * NomArchBD, const char * Campo, TListBox * Registros, const char * Expresion, Ent8 EsExpReg = 1, Ent8QueContenga = 1 ) { // Si no hay campos seleccionados entonces Operación Inválida if (Campo == 0 || ! *Campo || Expresion == 0) return CodError = E_OPINV;

// Intentar abrir el archivo para Lectura ArchBD arch; if (arch.Abrir(NomArchBD, MA_L)) return CodError;

Registros->ClearList();

// Armar la expresión regular si es necesario: ExpReg ExprRegular; Ascii0 CadPosError; if (EsExpReg && ! ExprRegular.Reasignar(Expresion, CadPosError)) return CodError = E_OPINV;

// Comienza la consulta: Ascii0 Reg, CampoRegAct; Ent8 Cumple; Ent16ns i; unsigned inicio, tam;

for (i = 0; ! arch.Leer(); ++i) { // Sacamos el campo y lo convertimos en cadena de caracteres if (arch.SacarCampoAutoConv(Campo, CampoRegAct)) break; // Error

// Consultar: if (EsExpReg) Cumple = QueContenga ? ! ExprRegular.Buscar(CampoRegAct, inicio,tam) && tam : ! ExprRegular.Examinar(CampoRegAct, 0, tam); else Cumple = QueContenga ? strstr((const char *) CampoRegAct, Expresion)!= 0 : stricmp(CampoRegAct, Expresion) == 0;

// Si cumple agregarlo a la lista: if (Cumple) { Reg.printf("%u: %s", i, (char *) CampoRegAct);

Consultas a Archivos Base de Datos BCE

218

Page 219: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Registros->AddString(Reg); } }

arch.Cerrar();

return CodError = E_SINERROR;}

void ConsDlgClient::Consultar (){ // INSERT>> Your code here. // Obtener expresión regular: Ascii0 Expr(100); GetDlgItemText(IDC_EXPRESION, Expr, Expr.TamBlq());

// Obtener el nombre del campo a consultar: Ascii0 NomCampo(100); if (! ListaDeCampos->GetSelCount()) { MessageBox("Seleccione un campo.", "ERROR", MB_ICONHAND | MB_OK); return; } ListaDeCampos->GetSelString(NomCampo, NomCampo.TamBlq()); if (! NomCampo.Long()) { MessageBox("No se pudo determinar el nombre del campo.", "ERROR", MB_ICONHAND | MB_OK); return; }

// Llamar a la función que realiza la consulta: if (::Consultar(NomArch, NomCampo, ListaDeRegistros, Expr, EsExpReg->GetCheck() == BF_CHECKED, QueContenga->GetCheck() == BF_CHECKED)) MessageBox("Problemas en función ::Consultar", "ERROR", MB_OK | MB_ICONHAND);}

void ConsDlgClient::CambiarArchivo (){ // INSERT>> Your code here. Ascii0 NomArch(100); TOpenSaveDialog::TData DatosDlg(OFN_HIDEREADONLY | OFN_FILEMUSTEXIST |OFN_NOCHANGEDIR, "Tipos ArchBD (*.BD)|*.bd|Todos losarchivos (*.*)|*.*|", 0, 0,"bd");

TFileOpenDialog dlg(this, DatosDlg); if (dlg.Execute() == IDOK) { if (CargarCampos(DatosDlg.FileName, ListaDeCampos)) MessageBox("El archivo no es tipo ArchBD", "ERROR", MB_OK | MB_ICONHAND); else SetDlgItemText(IDC_NOMARCH, DatosDlg.FileName); }}

15.3.2 DLGCLI.H: generado por AppExpert y modificado por el autor

#if !defined(__dlgcli_h) // Sentry, use file only if it's notalready included.#define __dlgcli_h

Consultas a Archivos Base de Datos BCE

219

Page 220: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

/* Project consulta Copyright © 1996. All Rights Reserved.

SUBSYSTEM: consulta.exe Application FILE: dlgcli.h AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Class definition for ConsDlgClient (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include <owl\checkbox.h>#include <owl\listbox.h>#include "consapp.rh" // Definition of all resources.

//{{TDialog = ConsDlgClient}}struct ConsDlgClientXfer {//{{ConsDlgClientXFER_DATA}} TListBoxData ListaDeCampos; TListBoxData ListaDeRegistros; bool QueContenga; bool EsExpReg;//{{ConsDlgClientXFER_DATA_END}}};

class ConsDlgClient : public TDialog {public:

ConsDlgClient (TWindow *parent, TResId resId = IDD_CLIENT, TModule*module = 0); virtual ~ConsDlgClient ();

int CargarCampos( const char * NomArch, TListBox * Campos );

//{{ConsDlgClientVIRTUAL_BEGIN}}public: virtual void SetupWindow ();//{{ConsDlgClientVIRTUAL_END}}

//{{ConsDlgClientXFER_DEF}}protected: TListBox *ListaDeCampos; TListBox *ListaDeRegistros; TCheckBox *QueContenga; TCheckBox *EsExpReg;

//{{ConsDlgClientXFER_DEF_END}}

//{{ConsDlgClientRSP_TBL_BEGIN}}protected: void Consultar (); void CambiarArchivo ();//{{ConsDlgClientRSP_TBL_END}}DECLARE_RESPONSE_TABLE(ConsDlgClient);}; //{{ConsDlgClient}}

#endif // __dlgcli_h sentry.

Consultas a Archivos Base de Datos BCE

220

Page 221: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

15.3.3 CONSAPP.CMM: generado por AppExpert

/* Project consulta Copyright © 1996. All Rights Reserved.

SUBSYSTEM: consulta.exe Application FILE: consapp.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of ConsultaApp (TApplication). */

#include <owl\owlpch.h>#pragma hdrstop

#include "consapp.h"#include "dlgcli.h" // Definition of client class.

//{{ConsultaApp Implementation}}

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(ConsultaApp, TApplication)//{{ConsultaAppRSP_TBL_BEGIN}} EV_COMMAND(CM_HELPABOUT, CmHelpAbout),//{{ConsultaAppRSP_TBL_END}}END_RESPONSE_TABLE;

//////////////////////////////////////////////////////////// ConsultaApp// =====//ConsultaApp::ConsultaApp () : TApplication("Principal"){

// INSERT>> Your constructor code here.}

ConsultaApp::~ConsultaApp (){ // INSERT>> Your destructor code here.}

//////////////////////////////////////////////////////////// ConsultaApp// =====// Application intialization.//void ConsultaApp::InitMainWindow (){

Consultas a Archivos Base de Datos BCE

221

Page 222: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (nCmdShow != SW_HIDE) nCmdShow = (nCmdShow != SW_SHOWMINNOACTIVE) ? SW_SHOWNORMAL :nCmdShow;

TFrameWindow *frame = new TFrameWindow(0, GetName(), newConsDlgClient(0), true);

// // Assign ICON w/ this application. // frame->SetIcon(this, IDI_SDIAPPLICATION);

SetMainWindow(frame);

}

//////////////////////////////////////////////////////////// ConsultaApp// ===========// Menu Help About consulta.exe commandvoid ConsultaApp::CmHelpAbout (){}int OwlMain (int , char* []){ try { ConsultaApp app; return app.Run(); } catch (xmsg& x) { ::MessageBox(0, x.why().c_str(), "Exception", MB_OK); }

return -1;}

15.3.4 CONSAPP.H: generado por AppExpert

#if !defined(__consapp_h) // Sentry, use file only if it'snot already included.#define __consapp_h

/* Project consulta Copyright © 1996. All Rights Reserved.

SUBSYSTEM: consulta.exe Application FILE: consapp.h AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Class definition for ConsultaApp (TApplication). */

#include <owl\owlpch.h>#pragma hdrstop

#include "consapp.rh" // Definition of all resources.

Consultas a Archivos Base de Datos BCE

222

Page 223: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

//{{TApplication = ConsultaApp}}class ConsultaApp : public TApplication {private:

public: ConsultaApp (); virtual ~ConsultaApp ();

//{{ConsultaAppVIRTUAL_BEGIN}}public: virtual void InitMainWindow();//{{ConsultaAppVIRTUAL_END}}

//{{ConsultaAppRSP_TBL_BEGIN}}protected: void CmHelpAbout ();//{{ConsultaAppRSP_TBL_END}}DECLARE_RESPONSE_TABLE(ConsultaApp);}; //{{ConsultaApp}}

#endif // __consapp_h sentry.

15.4 Fuentes del Administrador de Archivos Bases de Datos BCE

La biblioteca de soporte es la BCE.

Los módulos .CMM aquí listados son los del administrador de archivosbases de datos. Se los debe compilar una vez y sólo #incluir el archivocabecera BD.H para el uso de la clase ArchBD. Para el encadenamiento sedeberán incluir los .OBJ generados a partir de los .CMM.

Los módulos .CMM contienen funciones cuya definición inline no eraconveniente. Se enumeran de 01 a 09.

15.4.1 BD.H: cabecera con las declaraciones necesarias

# ifndef __BD_H# define __BD_H

// bd.h: declaración de clases para manejar archivos bases de dato// con formato BCE.

# ifndef __ARCHIVO_H# include <archivo.h># endif

# ifndef __VECTOR_H# include <vector.h># endif

// Definiciones de tipos de archivos base de datos:

Consultas a Archivos Base de Datos BCE

223

Page 224: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# define _ARCHBD 0

// Clase DescrCampoConstABD: una forma simple de describir un campo de un// registro en forma de constante.

class DescrCampoConstABD {public: const char * Nombre; Ent16ns TamCampo; Ent8ns Tipo;};

# define tdAscii0 0# define tdEnt8 1# define tdEnt8ns 2# define tdEnt16 3# define tdEnt16ns 4# define tdEnt32 5# define tdEnt32ns 6# define tdfloat 7# define tddouble 8# define tdlongdouble 9# define tdOtro 10

extern const Ent16ns TamTipo[tdOtro];

// Ejemplo de declaración de la descripción de un registro:// DescrCampoConstABD EstrucReg[] = {// "Nombre", 30, tdAscii0// "DNI", sizeof(Ent32ns), tdEnt32ns // internamente un DNI se manejacomo Ent32ns// 0, 0, 0 // indica el fin de la descripción// };// - El fin de la descripción siempre debe estar presente en unadescripción// de registro, la misma se indica por la terna 0,0,0.// - Si TamCampo == 0 se debe asumir que el tamaño es sizeof(Tipo).// No se permite TamCampo = 0 para tdAscii0.// - Los Tipos de campo se especifican usando el prefijo 'td' y el// tipo de dato que usted desea.// - El Tipo de campo no es usado por la clase ArchBD, se incluye para// su uso durante la entrada de datos por pantalla. Si un campo es, por// ejemplo, de tipo tdfloat y el usuario lo maneja como tdEnt32 no hayningún// problema (tdfloat y tdEnt32 son ambos de 4 bytes de largo).// - Una vista es una versión resumida o igual a la estructura delregistro// del archivo base de datos.

// Clase DescrCampo: descriptor de campo con cadenas manejadas por Ascii0.

class DescrCampoABD {public: Ascii0 Nombre; Ent16ns TamCampo; Ent8ns Tipo;

DescrCampoABD() { TamCampo = Tipo = 0; } virtual ~DescrCampoABD() { }};

ArchivoSO & operator << ( ArchivoSO & arch, const DescrCampoABD & dc );ArchivoSO & operator >> ( ArchivoSO & arch, DescrCampoABD & dc );

Consultas a Archivos Base de Datos BCE

224

Page 225: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent16 EscrEstrReg( ArchivoSO & arch, const Vector<DescrCampoABD> & dc );Ent16 LeerEstrReg( ArchivoSO & arch, Vector<DescrCampoABD> & dc );

// La siguiente función global da soporte a PonerCampo y SacarCampo// En Acceder:// Si Sentido == 0 se mueve así: EstrReg ===> BlqUsuario// Si Sentido != 0 se mueve así: EstrReg <=== BlqUsuarioEnt16 Acceder( const char * NomCampo, void * Reg, const DescrCampoABD * EstrReg, Ent16ns NumCampos, void * BlqUsuario, Ent8 Sentido );

Ent16ns MoverReg( void * RegDes, const DescrCampoABD * dRegDes, Ent16nsncRegDes, const void * RegFue, const DescrCampoABD * dRegFue,Ent16ns ncRegFue );

const DescrCampoABD * BuscarDescr( const char * NomCampo, const DescrCampoABD * EstrReg, Ent16nsNumCampos, Ent16ns * Despl = 0 );Ent16ns TamCampo( const char * NomCampo, const DescrCampoABD * EstrReg, Ent16ns NumCampos );Ent8ns Tipo( const char * NomCampo, const DescrCampoABD * EstrReg,Ent16ns NumCampos );

Ent16ns TamReg( const DescrCampoABD * EstrReg, Ent16ns NumCampos );// devuelve el número de bytes de la vista EstrReg de un archivo base dedatos

Ent16 EsVista( const DescrCampoABD * EstrReg, Ent16ns NumCamposReg, const DescrCampoABD * Vista, Ent16ns NumCamposVista );

// Clase ArchBD: significa archivo base de datos. Un archivo base de datosnos da// la independencia del código fuente de la estructura del registro delarchivo.// Un archivo base de datos es también un archivo de tamaño de registrofijo.// En los sistemas administradores de bases de datos como Paradox o dBasese los// conoce como tablas. Un objeto ArchBD sería análogo a un cursor de esossitemas.

class ArchBD {protected: ArchivoSO Arch; Vector<DescrCampoABD> EstrReg; Ent16ns TamRegReal, TamReg_EstrReg, DesplInic; BlqMem Buffer; void Vaciar(); Ent16ns CalcTamReg(); Ent16ns FijarEstrRegInic( const DescrCampoConstABD * er ); Ent16 BorDes( Ent32 c, Ent16 bd ); virtual Ent16ns Control(); virtual Ent8 Tipo(); virtual Ent16ns LeerInfoCtrl(); virtual Ent16ns EscrInfoCtrl(); Ent16 Bloquear( Ent32 Desp, Ent32 Tam ); Ent16 Desbloquear( Ent32 Desp, Ent32 Tam ); Ent16 Escr( Ent8 ByteCtrlFijado );

public: ArchBD();

Consultas a Archivos Base de Datos BCE

225

Page 226: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

virtual ~ArchBD();

Ent16 Abrir( const char * nombre, Ent8 e_s ); Ent16 Crear( const char * nombre, const DescrCampoConstABD * er ); Ent16 Crear( const char * nombre, Vector<DescrCampoABD> & er ); Ent16 Cerrar();

Ent32ns PA(); // Devuelve el valor del Puntero de Archivo (pos actual) Ent16 PosPA( Ent32ns NumReg ); // Posicionar el PA ArchBD & operator [] ( Ent32 pos ); Ent16 Comienzo(); // lleva el pa al comienzo del archivo Ent16 Final(); // lleva el pa al final del archivo Ent32ns Tam(); // devuelve el tamaño del archivo en bytes Ent16ns TamReg(); Ent32ns NumReg(); Ent16 Estado(); Ascii0 NomFis(); Ent16 VaciarBuffer() { return Arch.VaciarBuffer(); }

virtual Ent16 Leer(); // lee en Buffer. Luego se deben acceder a loscampos del registro. virtual Ent16 Escr(); // escribe desde Buffer. Antes se deben acceder alos campos del registro. Ent16 Borrar( Ent32 CualReg ); Ent16 DesBorrar( Ent32 CualReg ); Ent16 Borrado(); // informa si el reg. leido está lógicamente borrado Ent16 BloquearReg( Ent32 Reg ); Ent16 DesbloquearReg( Ent32 Reg );

// Para PonerCampo y SacarCampo, NomCampo debe ser un campo de la // estructura del registro. Ent16 PonerCampo( const char * NomCampo, const void * blq_externo ); Ent16 SacarCampo( const char * NomCampo, void * blq_externo ) const;

// PonerCampo no falla si TamCampo(NomCampo) != TamTipo[Tipo]. // En particular, si Tipo es Ascii0 falla cuando ! Cad.TamBlq(). Ent16 PonerCampo( const char * NomCampo, const Ascii0 & Cad ); Ent16 PonerCampo( const char * NomCampo, Ent8 n ); Ent16 PonerCampo( const char * NomCampo, Ent8ns n ); Ent16 PonerCampo( const char * NomCampo, Ent16 n ); Ent16 PonerCampo( const char * NomCampo, Ent16ns n ); Ent16 PonerCampo( const char * NomCampo, Ent32 n ); Ent16 PonerCampo( const char * NomCampo, Ent32ns n ); Ent16 PonerCampo( const char * NomCampo, float f ); Ent16 PonerCampo( const char * NomCampo, double d ); Ent16 PonerCampo( const char * NomCampo, long double ld );

Ent16 PonerCampoAutoConv( const char * NomCampo, const Ascii0 & Cad );

// SacarCampo falla si TamCampo(NomCampo) != TamTipo[Tipo]. // En particular, si Tipo es Ascii0 sólo falla cuando no hay memoria. Ent16 SacarCampo( const char * NomCampo, Ascii0 & Cad ) const; Ent16 SacarCampo( const char * NomCampo, Ent8 & n ) const; Ent16 SacarCampo( const char * NomCampo, Ent8ns & n ) const; Ent16 SacarCampo( const char * NomCampo, Ent16 & n ) const; Ent16 SacarCampo( const char * NomCampo, Ent16ns & n ) const; Ent16 SacarCampo( const char * NomCampo, Ent32 & n ) const; Ent16 SacarCampo( const char * NomCampo, Ent32ns & n ) const; Ent16 SacarCampo( const char * NomCampo, float & f ) const; Ent16 SacarCampo( const char * NomCampo, double & d ) const; Ent16 SacarCampo( const char * NomCampo, long double & ld ) const;

Ent16 SacarCampoAutoConv( const char * NomCampo, Ascii0 & Cad );

Ent16ns TamCampo( const char * NombreDelCampo ) const; Ent8ns Tipo( const char * NombreDelCampo ) const;

Consultas a Archivos Base de Datos BCE

226

Page 227: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent16ns NumCampos() const; const DescrCampoABD * CampoNumero( Ent16ns i ) const; const char * CadInicial(); void CadInicial( const char * CadInic ); friend Ent16 Indexar( const char * NomArchBDFue, const DescrCampoABD * EstrRegInd, Ent16 (* fcmp)( const void * a, const void * b, const DescrCampoABD * EstrRegInd), Ent8 AceptarRedundancia );};

inline Ent16 ArchBD::Borrar( Ent32 cual ) { return BorDes(cual, 1);}

inline Ent16 ArchBD::DesBorrar( Ent32 cual ) { return BorDes(cual, 0);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, const void *blq_externo ) { return ::Acceder(NomCampo, Buffer.Blq(), EstrReg, EstrReg.Tam, (void *)blq_externo, 1);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, void * blq_externo) const { return ::Acceder(NomCampo, Buffer.Blq(), EstrReg, EstrReg.Tam,blq_externo, 0);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, const Ascii0 & Cad) { return (! Cad.TamBlq()) ? CodError = E_OPINV : PonerCampo(NomCampo,(const void *) Cad);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent8 n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent8ns n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent16 n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent16ns n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent32 n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, Ent32ns n ) { return PonerCampo(NomCampo, & n);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, float f ) { return PonerCampo(NomCampo, & f);}

Consultas a Archivos Base de Datos BCE

227

Page 228: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, double d ) { return PonerCampo(NomCampo, & d);}

inline Ent16 ArchBD::PonerCampo( const char * NomCampo, long double ld ) { return PonerCampo(NomCampo, & ld);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ascii0 & Cad )const { register Ent16ns tc = TamCampo(NomCampo); if (! tc) return CodError = E_OPINV; if (! Cad.Reasignar(tc + 1)) return CodError; if (SacarCampo(NomCampo, (void *) Cad)) return CodError; register char * p = Cad; p[tc] = 0; // asegura terminación en 0 de la cadena Ascii. return CodError = E_SINERROR;}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent8 & n ) const { if (TamCampo(NomCampo) != TamTipo[tdEnt8]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent8ns & n ) const{ if (TamCampo(NomCampo) != TamTipo[tdEnt8ns]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent16 & n ) const{ if (TamCampo(NomCampo) != TamTipo[tdEnt16]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent16ns & n )const { if (TamCampo(NomCampo) != TamTipo[tdEnt16ns]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent32 & n ) const{ if (TamCampo(NomCampo) != TamTipo[tdEnt32]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, Ent32ns & n )const { if (TamCampo(NomCampo) != TamTipo[tdEnt32ns]) return CodError = E_OPINV; return SacarCampo(NomCampo, & n);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, float & f ) const{ if (TamCampo(NomCampo) != TamTipo[tdfloat]) return CodError = E_OPINV; return SacarCampo(NomCampo, & f);}

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, double & d ) const{ if (TamCampo(NomCampo) != TamTipo[tddouble]) return CodError = E_OPINV; return SacarCampo(NomCampo, & d);}

Consultas a Archivos Base de Datos BCE

228

Page 229: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inline Ent16 ArchBD::SacarCampo( const char * NomCampo, long double & ld )const { if (TamCampo(NomCampo) != TamTipo[tdlongdouble]) return CodError =E_OPINV; return SacarCampo(NomCampo, & ld);}

inline Ent16ns ArchBD::TamReg() { return TamReg_EstrReg;}

inline Ent16ns ArchBD::TamCampo( const char * NombreDelCampo ) const { return ::TamCampo(NombreDelCampo, EstrReg, EstrReg.Tam);}

inline Ent8ns ArchBD::Tipo( const char * NombreDelCampo ) const { return ::Tipo(NombreDelCampo, EstrReg, EstrReg.Tam);}

inline ArchBD & ArchBD::operator [] ( Ent32 pos ) { PosPA(pos); return *this;}

inline Ent16 ArchBD::Comienzo() { return PosPA(0);}

inline Ent16 ArchBD::Final() { return PosPA(NumReg());}

inline Ent32ns ArchBD::Tam() { return Arch.Tam();}

inline Ent16ns ArchBD::NumCampos() const { return EstrReg.Tam;}

inline const DescrCampoABD * ArchBD::CampoNumero( Ent16ns i ) const { return i < EstrReg.Tam ? & EstrReg[i] : 0;}

inline Ent16 ArchBD::Bloquear( Ent32 desp, Ent32 tam ) { return Arch.Bloquear(desp, tam);}

inline Ent16 ArchBD::Desbloquear( Ent32 desp, Ent32 tam ) { return Arch.Desbloquear(desp, tam);}

inline Ent16 ArchBD::BloquearReg( Ent32 Reg ) { return Bloquear(Reg * TamRegReal + DesplInic, TamRegReal);}

inline Ent16 ArchBD::DesbloquearReg( Ent32 Reg ) { return Desbloquear(Reg * TamRegReal + DesplInic, TamRegReal);}

inline Ent16 ArchBD::Estado() { return Arch.Estado();}

inline Ascii0 ArchBD::NomFis() { return Arch.NomFis();

Consultas a Archivos Base de Datos BCE

229

Page 230: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

}

// Funciones globales ...................................................

// Funciones Acceder() para const void *inline Ent16 Acceder( const char * NomCampo, const void * fueNOdesSI, void * desNOfueSI, Ent16 Sentido, const DescrCampoABD * EstrReg ) { return (Sentido != 0) ? CodError = E_OPINV : Acceder(NomCampo, (void *) fueNOdesSI, desNOfueSI, Sentido,EstrReg);}

# endif // # ifndef __bd_h

15.4.2 ABD01.CMM

// abd01.cmm Jueves 11 de marzo de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

static char CadInicDef[] = "Archivo Base de Datos.\n\rBiblioteca de clasesBCE.";

ArchBD::ArchBD() { TamRegReal = TamReg_EstrReg = DesplInic = 0;}

ArchBD::~ArchBD() { Cerrar();}

Ent16ns ArchBD::Control() { return 1; // 1 byte para verificar si se ha borrado lógicamente elregistro}

Ent8 ArchBD::Tipo() { return _ARCHBD;}

void ArchBD::Vaciar() { Buffer.Vaciar(); EstrReg.Vaciar(); TamRegReal = TamReg_EstrReg = DesplInic = 0;}

Ent16ns ArchBD::CalcTamReg() { TamReg_EstrReg = ::TamReg(EstrReg, EstrReg.Tam); TamRegReal = TamReg_EstrReg + Control();

return TamReg_EstrReg;}

Ent16ns ArchBD::FijarEstrRegInic( const DescrCampoConstABD * er ) { if (er == 0) { CodError = E_ERNODEF; return 0;

Consultas a Archivos Base de Datos BCE

230

Page 231: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} // Contar cuantos campos hay: Ent16ns n; const DescrCampoConstABD * pdc = er; for (n = 0; pdc->TamCampo; ++n, ++pdc); // Pedir memoria: if (! EstrReg.Reasignar(n)) { CodError = E_NOHAYMEMORIA; return 0; } // Asignar la estructura: for (n = 0, pdc = er; n < EstrReg.Tam; ++n, ++pdc) { EstrReg[n].Nombre = pdc->Nombre; EstrReg[n].Tipo = pdc->Tipo; EstrReg[n].TamCampo = pdc->TamCampo ? pdc->TamCampo :TamTipo[pdc->Tipo]; }

CalcTamReg();

CodError = E_SINERROR; return n;}

Ent16ns ArchBD::EscrInfoCtrl() { Ent32 PAInic; Ascii0 cad;

if (! EstrReg.Tam || ! TamReg_EstrReg) return CodError = E_ERNODEF, 0;

PAInic = Arch.PA();

EscrCadCab(Arch, CadInicDef);

// Para verificación Arch.ArchivoSO::operator << ( Tipo() );

// Para seguridad en acceso Arch << TamRegReal;

// Ahora se escribe la descripción del registro EscrEstrReg(Arch, EstrReg); // comienza a escribir la descripción delos registros

return Arch.PA() - PAInic;}

Ent16ns ArchBD::LeerInfoCtrl() { Ent32ns PAInic = Arch.PA(); if (CodError) return 0;

SaltearCab(Arch);

// Comprobar el tipo Ent8 t; Arch >> (t); if (CodError || t != Tipo()) return CodError = E_ARCHINV, 0;

// Leer el tamaño del registro Ent16ns TamRegDisco; Arch >> TamRegDisco; // lee verdadero tamaño de registro

// Leer descripción de los campos: LeerEstrReg(Arch, EstrReg);

Consultas a Archivos Base de Datos BCE

231

Page 232: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (! CalcTamReg() || TamRegReal != TamRegDisco) return CodError = E_ARCHINV, 0;

return Arch.PA() - PAInic;}

Ent16 ArchBD::Abrir( const char * nom, Ent8 L_E ) { if (Arch.Estado() != MA_C) return CodError = E_ABIERTO;

if (L_E == MA_E || L_E == MA_A) L_E = MA_L_E; if (ExisteArch(nom)) { if (! Arch.Abrir(nom, L_E)) DesplInic = LeerInfoCtrl(); } else CodError = E_OPINV;

if (! CodError) { if (! Buffer.Reasignar(TamRegReal)) { Cerrar(); CodError = E_NOHAYMEMORIA; } }

return CodError;}

Ent16 ArchBD::Crear( const char * nombre, const DescrCampoConstABD * er ){ if (Arch.Estado() != MA_C) return CodError = E_ABIERTO;

if (! FijarEstrRegInic(er)) return CodError;

if (Arch.AbrirExt(nombre, A_LEERESCR | A_CREAR | A_VACIAR | A_BINARIO)) return CodError;

DesplInic = EscrInfoCtrl();

if (! CodError) { if (! Buffer.Reasignar(TamRegReal)) { Cerrar(); CodError = E_NOHAYMEMORIA; } }

return CodError;}

Ent16 ArchBD::Crear( const char * nombre, Vector<DescrCampoABD> & er ) { if (Arch.Estado() != MA_C) return CodError = E_ABIERTO;

EstrReg << er; if (! CalcTamReg()) return CodError = E_ERNODEF;

if (Arch.AbrirExt(nombre, A_LEERESCR | A_CREAR | A_VACIAR | A_BINARIO)) return CodError;

DesplInic = EscrInfoCtrl();

if (! CodError) { if (! Buffer.Reasignar(TamRegReal)) { Cerrar(); CodError = E_NOHAYMEMORIA; } }

Consultas a Archivos Base de Datos BCE

232

Page 233: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

return CodError;}

Ent16 ArchBD::Cerrar() { Vaciar(); return Arch.Cerrar();}

Ent16 ArchBD::Leer() { if (Arch.Estado() == MA_C) return CodError = E_CERRADO; Arch.Leer(Buffer.Blq(), TamRegReal); return CodError;}

Ent16 ArchBD::Escr( Ent8 ByteCtrlFijado ) { if (Arch.Estado() == MA_C) return CodError = E_CERRADO; if (! ByteCtrlFijado) { register char * preg = (char *) Buffer.Blq(); preg[TamReg_EstrReg] = 0; // no está lógicamente borrado } Arch.Escr(Buffer.Blq(), TamRegReal); return CodError;}

Ent16 ArchBD::Escr() { return Escr(0); // por defecto asume que no está logicamente borrado}

//Ent16 ArchBD::Rescr() {// if (Arch.Estado() == MA_C) return CodError = E_CERRADO;// return Arch.Rescr(Buffer.Blq(), TamRegReal);//}

Ent16 ArchBD::Borrado() { if (Arch.Estado() == MA_C) return CodError = E_CERRADO; register char * preg = (char *) Buffer.Blq(); return preg[TamReg_EstrReg];}

Ent16 ArchBD::BorDes( Ent32 cual, Ent16 bsidno ) { if (PosPA(cual)) return CodError; if (Leer()) return CodError; Ent8 borrado = Borrado(); if (bsidno && borrado || ! bsidno && ! borrado) return CodError = E_YAHECHO; register char * preg = (char *) Buffer.Blq(); preg[TamReg_EstrReg] = bsidno; PosPA(cual); return Escr(1);}

Ent32ns ArchBD::PA() { Ent32ns pa = Arch.PA(); if (CodError) return 0; return (pa - DesplInic) / TamRegReal;}

Ent16 ArchBD::PosPA( Ent32ns nr ) { Ent32ns pa = nr * TamRegReal + DesplInic; return Arch.PosPA(pa);}

Ent32ns ArchBD::NumReg() { Ent32ns tamarch; tamarch = Tam();

Consultas a Archivos Base de Datos BCE

233

Page 234: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (! tamarch || ! TamRegReal) return 0; return (tamarch - DesplInic) / TamRegReal;}

15.4.3 ABD02.CMM

// abd02.cmm Miércoles 5 de junio de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"# include <string.h>

Ent16 Acceder( const char * nomcampo, void * Reg, const DescrCampoABD *er, Ent16ns nc, void * BlqUsuario, Ent8 s ) { if (Reg == 0 || BlqUsuario == 0) return CodError = E_OPINV;

Ent16ns des; register const DescrCampoABD * pdc = BuscarDescr(nomcampo, er,nc, &des); if (pdc == 0) return CodError = des ? E_CAMPOINEXIST : E_OPINV;

if (! s) memmove(BlqUsuario, (char *) Reg + des, pdc->TamCampo); else memmove((char *) Reg + des, BlqUsuario, pdc->TamCampo);

return CodError = E_SINERROR;}

15.4.4 ABD03.CMM

// abd03.cmm Miércoles 5 de junio de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include <string.h># include "bd.h"

const DescrCampoABD * BuscarDescr( const char * nomcampo, const DescrCampoABD * er, Ent16ns nc, Ent16ns * Despl ) { if (Despl != 0) *Despl = 0; // inicializar en 0 por las dudas

if (! nc || er == 0 || nomcampo == 0) return 0; register const DescrCampoABD * paux; register Ent16ns i, des; for (paux = er, i = des = 0; i < nc; ++paux, ++i) if (! stricmp(nomcampo, paux->Nombre)) break; // salir del for else des += paux->TamCampo;

if (Despl != 0) *Despl = des; // si pide Despl, devolver

return i < nc ? paux : 0;}

Ent16ns TamCampo( const char * NomCampo, const DescrCampoABD * EstrReg,Ent16ns NumCampos ) {

Consultas a Archivos Base de Datos BCE

234

Page 235: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

register const DescrCampoABD * p = BuscarDescr(NomCampo, EstrReg,NumCampos); return p != 0 ? p->TamCampo : 0;}

Ent8ns Tipo( const char * NomCampo, const DescrCampoABD * EstrReg,Ent16ns NumCampos ) { register const DescrCampoABD * p = BuscarDescr(NomCampo, EstrReg,NumCampos); return p != 0 ? p->Tipo : 0;}

15.4.5 ABD04.CMM

// abd04.cmm Viernes 7 de mayo de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

Ent16ns TamReg( const DescrCampoABD * EstrReg, Ent16ns NumCampos ) { if (! NumCampos || EstrReg == 0) return 0; register const DescrCampoABD * er = EstrReg; register Ent16ns i, tamreg; for (tamreg = i = 0; i < NumCampos; ++er, ++i) tamreg += er->TamCampo; return tamreg;}

15.4.6 ABD05.CMM

// abd05.cmm Jueves 11 de marzo de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

Ent16ns MoverReg( void * RegDes, const DescrCampoABD * dRegDes, Ent16nsncRegDes, const void * RegFue, const DescrCampoABD * dRegFue,Ent16ns ncRegFue ) { if (RegDes == 0 || dRegDes == 0 || ! ncRegDes || RegFue == 0 || dRegFue == 0 || ! ncRegFue ) return 0; register const DescrCampoABD * pdRegDes; register char * pRegDes = (char *) RegDes; register Ent16ns i, nc; for (i = nc = 0, pdRegDes = dRegDes; i < ncRegDes; ++i, ++pdRegDes) { if (! Acceder(pdRegDes->Nombre, (void *) RegFue, dRegFue, ncRegFue, pRegDes, 0)) ++nc; // un campo más copiado pRegDes += pdRegDes->TamCampo; // avanza el puntero al campo destinosiguiente ++pdRegDes; }

return nc;}

Consultas a Archivos Base de Datos BCE

235

Page 236: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

15.4.7 ABD06.CMM

// abd06.cmm Viernes 7 de mayo de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

Ent16 EsVista( const DescrCampoABD * EstrReg, Ent16ns NumCamposReg, const DescrCampoABD * Vista, Ent16ns NumCamposVista ) { register const DescrCampoABD * pv = Vista; register Ent16ns i; for (i = 0; i < NumCamposVista; ++i, ++pv) if (pv->TamCampo != TamCampo(pv->Nombre, EstrReg, NumCamposReg))break;

return ! pv->TamCampo;}

15.4.8 ABD07.CMM

// abd07.cmm Mar 09 Ene 96

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

Ent16 EscrEstrReg( ArchivoSO & arch, const Vector<DescrCampoABD> & dc ) { arch << dc.Tam; for (Ent16ns i = 0; i < dc.Tam; ++i) arch << dc[i];

return CodError;}

Ent16 LeerEstrReg( ArchivoSO & arch, Vector<DescrCampoABD> & dc ) { Ent16ns i,n; arch >> n; if (! dc.Reasignar(n)) { CodError = ! i ? E_SINERROR : E_NOHAYMEMORIA; return CodError; } for (i = 0; i < n; ++i) arch >> dc[i];

return CodError;}

ArchivoSO & operator << ( ArchivoSO & arch, const DescrCampoABD & dc ) { arch << dc.Nombre << dc.TamCampo << dc.Tipo; return arch;}

ArchivoSO & operator >> ( ArchivoSO & arch, DescrCampoABD & dc ) { arch >> dc.Nombre >> dc.TamCampo >> dc.Tipo; return arch;}

Consultas a Archivos Base de Datos BCE

236

Page 237: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

15.4.9 ABD08.CMM

// abd08.cmm Vie 19 Ene 96

// Copyright (c) 1996 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

const Ent16ns TamTipo[tdOtro] = { 0, sizeof(Ent8), sizeof(Ent8ns), sizeof(Ent16), sizeof(Ent16ns), sizeof(Ent32), sizeof(Ent32ns), sizeof(float), sizeof(double), sizeof(long double)};

15.4.10 ABD09.CMM

// abd09.cmm Lun 22 Ene 96

// Copyright (c) 1996 by Domingo Eduardo Becker.// All rights reserved.

# include "bd.h"

Ent16 ArchBD::PonerCampoAutoConv( const char * NomCampo, const Ascii0 &Cad ) { Ent8ns TipoDelCampo = Tipo(NomCampo); Ent8 ent8; Ent8ns ent8ns; Ent16 ent16; Ent16ns ent16ns; Ent32 ent32; Ent32ns ent32ns; float f; double d;

switch (TipoDelCampo) { case tdAscii0: PonerCampo(NomCampo, Cad); break;

case tdEnt8: ent8 = Cad; PonerCampo(NomCampo, ent8); break;

case tdEnt8ns: ent8ns = Cad; PonerCampo(NomCampo, ent8ns); break;

case tdEnt16: ent16 = Cad; PonerCampo(NomCampo, ent16); break;

case tdEnt16ns: ent16ns = Cad; PonerCampo(NomCampo, ent16ns); break;

Consultas a Archivos Base de Datos BCE

237

Page 238: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case tdEnt32: ent32 = Cad; PonerCampo(NomCampo, ent32); break;

case tdEnt32ns: ent32ns = Cad; PonerCampo(NomCampo, ent32ns); break;

case tdfloat: f = Cad; PonerCampo(NomCampo, f); break;

case tddouble: d = Cad; PonerCampo(NomCampo, d); break;

default: CodError = E_OPINV; }

return CodError;}

Ent16 ArchBD::SacarCampoAutoConv( const char * NomCampo, Ascii0 & Cad ) { Ent8ns TipoDelCampo = Tipo(NomCampo); Ent8 ent8; Ent8ns ent8ns; Ent16 ent16; Ent16ns ent16ns; Ent32 ent32; Ent32ns ent32ns; float f; double d;

switch (TipoDelCampo) { case tdAscii0: SacarCampo(NomCampo, Cad); break;

case tdEnt8: if (! SacarCampo(NomCampo, ent8)) Cad = ent8; break;

case tdEnt8ns: if (! SacarCampo(NomCampo, ent8ns)) Cad = ent8ns; break;

case tdEnt16: if (! SacarCampo(NomCampo, ent16)) Cad = ent16; break;

case tdEnt16ns: if (! SacarCampo(NomCampo, ent16ns)) Cad = ent16ns; break;

case tdEnt32: if (! SacarCampo(NomCampo, ent32)) Cad = ent32;

Consultas a Archivos Base de Datos BCE

238

Page 239: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

break;

case tdEnt32ns: if (! SacarCampo(NomCampo, ent32ns)) Cad = ent32ns; break;

case tdfloat: if (! SacarCampo(NomCampo, f)) Cad = f; break;

case tddouble: if (! SacarCampo(NomCampo, d)) Cad = d; break;

default: CodError = E_OPINV; } return CodError;}

Consultas a Archivos Base de Datos BCE

239

Page 240: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 16: Un traductor sencillo para un lenguaje simple

El traductor que se desarrollará como ejemplo en este capítulo, pretendemostrar el uso de los generadores SLR1 y AFD. No pretende ser un traductorprofesional de un lenguaje sofisticado como los que hay actualmente en elmercado.

No se pone énfasis en el desarrollo profesional de un traductor, sino entratar de hacer entender cómo se debe proceder con las herramientas SLR1 yAFD en el desarrollo de un traductor.

A los efectos de mostrar el correcto funcionamiento del códigogenerado, se desarrolló un intérprete para ése código generado.

16.1 Objetivos y metas

El objetivo es escribir un traductor de un lenguaje simple. Para poderprobar el código generado, como no es código directamente ejecutable por lacomputadora, se escribirá también un intérprete para el código objeto.

Las metas para llegar a esos dos objetivos son:

1. Describir el lenguaje. Se utilizará una gramática libre de contexto paradescribir la estructura del lenguaje.

2. Describir el lenguaje objeto, al que se traducirá cada oración dellenguaje fuente.

3. Describir el esquema de traducción, esto es, se escribirán las accionessemánticas que se encargarán de realizar la traducción.

4. Implementar el traductor.

5. Escribir el intérprete: diseñar e implementar el intérprete y su interfase.

6. Escribir la guía del usuario y manual de referencia del programador dellenguaje simple.

Un traductor sencillo para un lenguaje simple

240

Page 241: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.2 Estructura del Lenguaje

La estructura del lenguaje queda perfectamente definido por la siguientegramática libre de contexto, dada en formato SLR1 v 2.x:

Leng --> Decl Sents ;

Decl --> 'Var' Idents ';'| ;

Idents --> MásIdents Ident ;

MásIdents --> Idents ',' | ;

Sents ---> Sents SentPC | SentPC ; // SentPC es sentencia y punto y comaSentPC --> Sent ';' ;Sent ---> Asignación | Mientras | Repetir ;

Asignación --> Ident '=' Expresión ;

Mientras --> 'Mientras' Expresión 'hacer' Sents 'Fin' ;

Repetir ---> 'Repetir' Sents 'Hasta' Expresión ;

Expresión --> ExprLogicaO ;

ExprLogicaO -> ExprLogicaO '||' ExprLogicaY | ExprLogicaY ;

ExprLogicaY -> ExprLogicaY '&&' ExprRelacional | ExprRelacional ;

ExprRelacional -> ExprRelacional '==' ExprArit | ExprRelacional '!=' ExprArit | ExprRelacional '<' ExprArit | ExprRelacional '<=' ExprArit | ExprRelacional '>' ExprArit | ExprRelacional '>=' ExprArit | ExprArit ;

ExprArit ---> ExprArit '+' Producto | ExprArit '-' Producto | Producto ;

Producto ---> Producto '*' Factor | Producto '/' Factor | Factor ;

Factor -----> Ident | Real | '-' Factor | '!' Factor | '(' Expresión ')' ;

Esta gramática será luego modificada para poder introducir accionessemánticas para realizar la traducción.

Los símbolos terminales, cuya estructura no está especificada en lagramática precedente, serán tratados con AFDs generados a partir de lassiguientes expresiones regulares (se usa formato AFD v 3.x):

Ident

// Exp reg para describir un identificador:# Letra [a-zA-Z_áéíóúñÑüÜ]# Digito [0-9]

Un traductor sencillo para un lenguaje simple

241

Page 242: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Letra (Letra | Digito)*

Un identificador comienza con una Letra y continúa opcionalmente conuna combinación finita de Letras y Digitos. Por lo menos tiene la longitud deun caracter.

Real

// Expresión regular para un número real en formato C++:# Díg [0-9]Díg * '.' ? Díg + ( (e | E) Díg + ) ?

Los números reales definidos por la expresión regular precedente sonsimilares a los de punto flotante del C++. El conjunto de números definido es:reales positivos con el 0.

El signo '-' (menos) unario es tomado como operador.

Para la escritura de una oración del lenguaje fuente se contempla laposibilidad de agregar secuencias de longitud variable de blancos entresímbolos terminales, así como también la posibilidad de insertar comentarios

similares a los del C++.

Blancos

// Expresión regular para blancos:[ \n\r\f\t\v] +

Comentarios

// Exp reg para comentarios similares a éste:/ / .*

El programa siguiente es una oración ejemplo del lenguaje:

// comentarioVar a,b,c;a = 12 + 4 - 5;b = a * 3 / 2;c = a + b - 4;

// Bucles anidados:c = 10;a = 0;mientras c hacer b = 0; Repetir b = b + 1; a = a + 1; Hasta b == 20; c = c - 1;Fin;// a debe tener 200

Un traductor sencillo para un lenguaje simple

242

Page 243: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.3 Descripción del Lenguaje Objeto

Sea un intérprete de código que consta de los siguientes elementos:

1. Un puntero de instrucción.

2. Un registro. Tipo de dato del registro: real.

3. Una pila.

4. Una tabla de variables.

El lenguaje objeto al que se traducirán los programas (oraciones)escritos en el lenguaje fuente, consta de instrucciones que modifican algunosde los elementos previamente descriptos. Las instrucciones pueden tener unoperando.

Las instrucciones y su correspondiente semántica son:

NoOp

No ejecuta ninguna operación. Sólo incrementa el puntero deinstrucción.

CrearVar Ident

Agregar a Ident a la tabla de variables. La variable no debe estarpreviamente agregada. Luego, incrementar el puntero de instrucción.

Asignar Ident

Asignar a Ident el valor del registro del intérprete. La variable Ident

debe ser previamente creada (debe existir en la tabla de variables). Luegoincrementar el puntero de instrucción.

MoverVar Ident

Buscar Ident en la tabla de variables, leer su contenido y cargarlo en elregistro del intérprete. La variable debe ser previamente creada por algunainstrucción que se ejecutó anteriormente. Luego incrementar el puntero deinstrucción.

Un traductor sencillo para un lenguaje simple

243

Page 244: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

MoverCte Real

Cargar Real en el registro de la máquina. Luego incrementar el punterode instrucción.

ApilarReg

Apilar el contenido del registro de instrucción en la pila del intérprete.Luego incrementar el puntero de instrucción.

O

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. A éstos números se los convierte a enteropor truncado. Aplicar la operación O lógica a esos números y guardar elresultado en el registro del intérprete. Luego incrementar el puntero deinstrucción.

Y

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. A éstos números se los convierte a enteropor truncado. Aplicar la operación Y lógica a esos números y guardar elresultado en el registro del intérprete. Luego incrementar el puntero deinstrucción.

Negar

Convertir el contenido del registro del intérprete a entero y aplicarle laoperación Negación lógica. El resultado se vuelve a almacenar en el registrodel intérprete.

Igual

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es igual a a esosnúmeros. Si son iguales, guardar 1 en el registro del intérprete, si son distintos,guardar 0. Luego incrementar el puntero de instrucción.

Un traductor sencillo para un lenguaje simple

244

Page 245: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Distinto

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es distinto de a esosnúmeros. Si son iguales, guardar 0 en el registro del intérprete, si son distintos,guardar 1. Luego incrementar el puntero de instrucción.

Menor

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es menor que a esosnúmeros. Si el operando izquierdo es menor que el segundo, guardar 1 en elregistro del intérprete, sino guardar 0. Luego incrementar el puntero deinstrucción.

MenorOIgual

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es menor o igual a aesos números. Si el operando izquierdo es menor o igual al segundo, guardar 1en el registro del intérprete, sino guardar 0. Luego incrementar el puntero deinstrucción.

Mayor

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es mayor que a esosnúmeros. Si el operando izquierdo es mayor que el segundo, guardar 1 en elregistro del intérprete, sino guardar 0. Luego incrementar el puntero deinstrucción.

MayorOIgual

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación es mayor o igual a aesos números. Si el operando izquierdo es mayor o igual al segundo, guardar 1

Un traductor sencillo para un lenguaje simple

245

Page 246: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

en el registro del intérprete, sino guardar 0. Luego incrementar el puntero deinstrucción.

Sumar

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación Suma a esosnúmeros y almacenar el resultado en el registro del intérprete. Luegoincrementar el puntero de instrucción.

Restar

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación Resta a esosnúmeros y almacenar el resultado en el registro del intérprete. Luegoincrementar el puntero de instrucción.

Multiplicar

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación Multiplicación aesos números y almacenar el resultado en el registro del intérprete. Luegoincrementar el puntero de instrucción.

Dividir

Desapilar 1 número de la pila del intérprete; éste número será eloperando de la izquierda del operador. El operando de la derecha será elcontenido del registro del intérprete. Aplicar la operación División a esosnúmeros y almacenar el resultado en el registro del intérprete. Luegoincrementar el puntero de instrucción.

Menos

El operando al que se aplicará esta operación se encuentra en el registrodel intérprete. Aplicar la operación Menos a ése número y almacenar el

Un traductor sencillo para un lenguaje simple

246

Page 247: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

resultado en el registro del intérprete. Luego incrementar el puntero deinstrucción.

IrA Número_De_Instrucción

Almacenar Número_De_Instrucción en el puntero de instrucción delintérprete.

IrASiF Número_De_Instrucción

Convertir a entero el contenido del registro del intérprete. Si el resultadoes un número igual a 0, entonces almacenar Número_De_Instrucción en elpuntero de instrucción del intérprete, sino incrementar el puntero deinstrucción.

IrASiV Número_De_Instrucción

Convertir a entero el contenido del registro del intérprete. Si el resultadoes un número distinto de 0, entonces almacenar Número_De_Instrucción en elpuntero de instrucción del intérprete, sino incrementar el puntero deinstrucción.

El siguiente es un programa ejemplo, generado por este traductor apartir del programa en lenguaje fuente dado en la sección 16.2. Lasinstrucciones se etiquetaron con números a efectos de que se observe haciadónde saltan las instrucciones de salto.

1: CrearVar a2: CrearVar b3: CrearVar c4: MoverCte 125: ApilarReg6: MoverCte 47: Sumar8: ApilarReg9: MoverCte 510: Restar11: Asignar a12: MoverVar a13: ApilarReg14: MoverCte 315: Multiplicar16: ApilarReg17: MoverCte 218: Dividir19: Asignar b20: MoverVar a21: ApilarReg22: MoverVar b23: Sumar24: ApilarReg25: MoverCte 4

Un traductor sencillo para un lenguaje simple

247

Page 248: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

26: Restar27: Asignar c28: MoverCte 1029: Asignar c30: MoverCte 031: Asignar a32: MoverVar c33: IrASiF 5634: MoverCte 035: Asignar b36: MoverVar b37: ApilarReg38: MoverCte 139: Sumar40: Asignar b41: MoverVar a42: ApilarReg43: MoverCte 144: Sumar45: Asignar a46: MoverVar b47: ApilarReg48: MoverCte 2049: Igual50: IrASiF 3551: MoverVar c52: ApilarReg53: MoverCte 154: Restar55: Asignar c56: IrA 31

16.4 Descripción del Esquema de Traducción

A la gramática dada en la sección 16.2 se la modificará a efectos depoder implementar las acciones semánticas que realizarán la traducción.

Las modificaciones importantes se documentan en las seccionessiguientes.

A la gramática nueva resultante se la puede ver en el archivoLENG.GLC que se muestra al final de este capítulo, en la sección donde selistan los fuentes.

La función AgregarSentCI agrega una instrucción de código objeto alprograma que se está generado a partir de la traducción.

16.4.1 Generación del Código para las Operaciones Binarias

Si la operación es binaria, de acuerdo a la forma general de reglasiguiente:

Un traductor sencillo para un lenguaje simple

248

Page 249: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Expr ---> Expr Oprd ExprMayorPrec ;

la regla nueva será:

Expr ---> Expr Oprd Apilar ExprMayorPrec ;

Apilar ---> ;

La segunda regla se agrega sólo una vez. Es una regla que deriva en lambda(no produce ningún efecto ni modifica el lenguaje). A este tipo de regla se lasdenomina marcadores.

Las acciones semánticas serán:

Expr ---> Expr Oprd Apilar ExprMayorPrec %{AgregarSentCI(Oprd);

}% ;

Apilar ---> %{AgregarSentCI(ApilarReg);

}% ;

16.4.2 Generación del Código para las Operaciones Unarias

Si la operación era unaria, la acción semántica es:

Expr ---> Oprd Expr %{AgregarSentCI(Oprd);

}% ;

16.4.3 Generación del Código para el "Repetir ... hasta ..."

La regla original "Repetir ... hasta ..." se modificó, agregando unmarcador. Las reglas semánticas quedaron así:

Repetir ---> 'Repetir' Rotulo Sents 'Hasta' Expresión %{// salto condicional a RotuloAgregarSentCI(IrASiF, $2.CadTerm);

}% ;

Rotulo --> %{// asignamos a $$.CadTerm el número de instrucción actual Ent16ns NumInstAct = Programa.NumElem();$$.CadTerm = NumInstAct;

}% ;

El marcador asigna al campo CadTerm el número de instrucción actual(la que se está por generar) que se encuentra almacenado en la variable globalNumInstAct. Luego, al reducir por la regla "Repetir ... hasta" se utiliza esevalor para el salto condicional.

Un traductor sencillo para un lenguaje simple

249

Page 250: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.4.4 Generación del Código para el "Mientras ... hacer ..."

La regla original "Mientras ... hacer ..." se modificó. Las accionessemánticas quedaron así:

Mientras --> 'Mientras' Rotulo ExprSaltoCond 'hacer' Sents 'Fin' %{// salto incondicional al primer rótuloAgregarSentCI(IrA, $2.CadTerm);// una vez agregada la sentencia, el rótulo del salto del no// terminal ExprSaltoCond debe referenciar a la posición actual:AsignarRotulo($3.CadTerm); // en CadTerm viene el nombre

// del rótulo }% ;

ExprSaltoCond --> Expresión %{// aquí hay un salto si es que el registro de la máquina es FGenerarRotulo($$.CadTerm);AgregarSentCI(IrASiF, $$.CadTerm);

}% ;

La regla "Rotulo --> ;" fue dada en la sección anterior. Se utiliza esaacción semántica.

Una vez evaluada la ExprSaltoCond se debe saltar a la instrucción quesigue después de la palabra clave Fin, entonces, luego de generar el códigopara Expresión se genera un rótulo que será resuelto al reducir por la regla del"Mientras ... hacer ..." (ver sentencia AsignarRotulo($3.CadTerm) ysentencia GenerarRotulo($$.CadTerm)) y se agrega el salto condicional.

Al reducir por la regla "Mientras ... hacer ...", se genera un saltoincondicional IrA a donde comienza la evaluación de la expresióncondicional. Esa posición se encuentra en $2.CadTerm que corresponde aRotulo.

16.4.5 Reglas Semánticas para la Recuperación de Operandos Actuales

Los operandos actuales son alcanzados por las reglas siguientes, endonde se muestran también las acciones semánticas:

Factor -----> Ident %{ // mover el valor de Ident al registro de la máquina if (BuscarVar($1.CadTerm)) AgregarSentCI(MoverVar, $1.CadTerm); }% | Real %{ // mover el valor del Real al registro dela máquina AgregarSentCI(MoverCte, $1.CadTerm); }%

Para el caso de que en el texto fuente se encuentre un identificador,antes de generar el código objeto se busca la variable en la tabla de variables

Un traductor sencillo para un lenguaje simple

250

Page 251: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

del traductor, para ver si la misma fue previamente declarada. Si es así, segenera el código MoverVar que extrae el valor de la tabla de variables delintérprete.

Si era un número real, directamente se genera el código que coloca elreal en el registro del intérprete.

16.4.6 Creación de las Variables

La creación de las variables en tiempo de ejecución se realiza con laregla semántica siguiente:

Idents --> MásIdents Ident %{ // nueva var declarada AgregarVar($2.CadTerm); AgregarSentCI(CrearVar, $2.CadTerm); }% ;

Se genera la sentencia CrearVar incondicionalmente. Además, seagrega el identificador que aparece en el texto fuente a la tabla de variables deltraductor. Luego, esa tabla se usa para ver si hay variables previamentedeclaradas.

16.4.7 Resolución de Saltos hacia Adelante

La resolución de saltos hacia adelante se realiza con la función globalResolverRotulos. La regla semántica es:

Leng --> Decl Sents %{ // Resolver rótulos de saltos hacia adelante: ResolverRotulos(); }% ;

La función ResolverRotulos recorre el código generado en busca desaltos no resueltos. Para cada rótulo encontrado, se lo busca en la tabla derótulos (la que hasta este momento ya tiene los rótulos resueltos) y se asigna laposición que le correspondió.

16.5 Implementación del Traductor

El traductor está implementado por las acciones semánticasespecificadas en LENG.GLC.

Un traductor sencillo para un lenguaje simple

251

Page 252: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

SLR1 v 2.x recibirá como entrada este archivo y generará el archivoLENG.CMM con el analizador sintáctico y el analizador lexicográfico.

Los AFDs usados por el analizador lexicográficos son generados a partirde los respectivos archivos .ER con las expresiones regulares.

16.5.1 Estructuras de Datos usadas

Las estructuras de datos usadas por el traductor son las siguientes.

1. Código Objeto y Programa Objeto

El código objeto es implementado por la clase CodInt que significacódigo intermedio (a partir de ese código se puede generar código demáquina). La declaración de esta clase se encuentra en INTERP.H, y lasdefiniciones de las funciones miembro en INTERP.CMM.

Los campos datos de la clase son:

Codigo: contiene el código de operación.

Operando: si la instrucción representada por este objeto tiene un operando, elmismo se encuentra en este campo. Se utiliza la clase Ascii0 para laconversión automática de tipo (recordar que hay operandos que sonidentificadores y otros que son números reales).

Durante la traducción, el programa que se está generando se guarda enuna lista simple encadenada de objetos CodInt. Para la lista simpleencadenada se usa la clase template LSE de la biblioteca BCE.

Durante la interpretación del código objeto, el programa se almacena enun vector de objetos CodInt. Se utiliza la clase template Vector de labiblioteca BCE.

2. Tabla de Variables

La tabla de variables para el momento de la traducción es una listasimple encadenada de objetos Ascii0.

Para el momento de la interpretación, la tabla de variables es una listasimple encadenada de objetos Variable.

Un traductor sencillo para un lenguaje simple

252

Page 253: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La clase Variable tiene los siguientes campos dato:

Ident: es el identificador usado en la declaración.

Valor: es el valor actual de esta variable.

La búsqueda en la tabla de variable es secuencial.

3. Rótulos y Tabla de Rótulos

Los rótulos (para las referencias hacia adelante) se implementan con laclase DescrRotulo que tiene los siguientes campos dato:

cRotulo: es la cadena identificadora del rótulo. La cadena tiene la forma RXXdonde XX es el número de éste rótulo. Se utilizan cadenas de esta formapuesto que al generar el programa se debe indicar de alguna manera que lainstrucción de salto tiene una referencia no resuelta. Entonces, en elOperando de la instrucción de salto habrá una cadena que comienza con R, yesto significará que ese salto no está resuelto.

nRotulo: es la posición a la apunta este rótulo. Al resolver el salto, se cambiacRotulo por nRotulo.

La tabla de rótulos sólo es usada durante la traducción, y se implementacon una lista simple encadenada de objetos DescrRotulo.

16.5.2 Descripción de las Funciones Globales Principales

1. BuscarVar

Esta función busca una variable en la tabla de variables. Si la encuentradevuelve un valor distinto de 0 y sino 0.

2. AgregarVar

Esta función agrega un identificador de variable a la lista de variables yadeclaradas. Si ya fue agregada se devuelve 0. Sino un valor distinto de 0.

3. AgregarSentCI

Un traductor sencillo para un lenguaje simple

253

Page 254: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Esta es una función polimórfica que agrega una sentencia de códigoobjeto al programa que se está generando.

4. GenerarRotulo

Esta función genera un rótulo (el campo cRotulo de un objetoDescrRotulo). Lo agrega al final de la lista de rótulo e informa el nombre(cRotulo) del rótulo.

5. AsignarRotulo

A partir de la cadena del rótulo (cRotulo) y un valor entero no negativo,se lo busca al rótulo en la lista de rótulos no resueltos y se asigna al camponRotulo el valor entero no negativo recibido. Ese número será luego utilizadopara resolver los saltos hacia adelante.

6. BuscarRotulo

Dado un nombre de rótulo (cRotulo), busca el descriptor del mismo enla tabla de rótulos y devuelve un puntero a ese descriptor. Si no lo encontró,devuelve 0.

7. ResolverRotulos

Esta función recorre el programa en busca de instrucciones de salto endonde el Operando tenga una cadena de la forma RXX. Si encuentra una,busca un rótulo con ese nombre y reemplaza la cadena por el valor actual delrótulo.

8. GuardarPrograma

Esta función guarda el programa que se encuentra en la lista simpleencadenada que generó el traductor, en un archivo binario.

Primero se guarda el número de instrucciones del programa y luego cadauna de las instrucciones.

Al cargar el programa en memoria (para la interpretación), se usará unvector, cuyo tamaño será el que se indica al comienzo del archivo.

Un traductor sencillo para un lenguaje simple

254

Page 255: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El archivo binario con el código tendrá extensión .CI. Además,opcionalmente se genera un archivo de texto con extensión .TXT que muestralas instrucciones en formato texto.

9. CargarPrograma

Esta función carga el programa desde el archivo binario en un vector deobjetos CodInt.

10.TraducirDeLengACodInt

A partir de un nombre de archivo, esta función carga el texto que seencuentra en ese archivo, que se supone está en lenguaje fuente, lo traduceutilizando el analizador sintáctico y lexicográfico generados por SLR1 v 2.x, yguarda el programa que se genere en un archivo con el mismo nombre que elde entrada pero extensión .CI. En otro archivo con el mismo nombre pero conextensión .TXT, se guarda el código generado pero en formato texto.

Esta función se encuentra definida en el módulo TRADUCIR.CMM, ydeclarada en el módulo INTERP.H.

16.6 Implementación del Intérprete para el Código Generado

Debido a que el intérprete se implementa con una clase llamadaInterprete, es posible la coexistencia de varios intérpretes en un mismoprograma.

16.6.1 Estructuras de Datos usadas

Las estructuras siguientes fueron descriptas en 16.5.1: tablas devariables, variables, código objeto y programa.

1. Pila del Intérprete

La pila del intérprete se implementa en una lista simple encadenada denúmeros de punto flotante de doble precisión: double. Se utiliza la clase LSEde la biblioteca BCE. El primer elemento de la lista es el tope de pila.

2. Estructura de un Intérprete

Un traductor sencillo para un lenguaje simple

255

Page 256: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Un intérprete se implementa con la clase Interprete, la que tiene lossiguientes campos dato:

Programa: es el programa a interpretar. Este intérprete se encarga de cargar elprograma desde un archivo binario conteniendo las instrucciones. La funciónque actualmente realiza la carga es CargarPrograma.

InstrAct: es el número de instrucción que se ejecutará en el paso siguiente.Inicialmente vale 0, que es el inicio del programa.

Registro: es el registro del intérprete.

Pila: es la pila del intérprete. La estructura se la explicó en el punto anterior.

TablaDeVar: es la tabla de variables declaradas.

Error: es el código de error, a saber: SinError, FinProg, FaltanOprnds,DirInval, VarNoDecl, VarDeclPrev, FaltaMem, PilaVacia, Div0.

16.6.2 Descripción de las Funciones Principales

Los códigos de errores devuelto por las funciones miembro de la claseInterprete son los que se enumeran en la descripción del campo Error de esaclase (ver sección anterior). Además de devolver el código de error, el campoError retiene el código de error devuelto por la última función del intérpreteque se ha ejecutado.

Las definiciones de las funciones cortas las encontrará en el móduloINTERP.H, y las del resto están en INTERP.CMM.

1. Interprete::CargarPrograma

Realiza la carga del Programa desde un archivo binario. Si no hayproblemas, el intérprete apuntará a la primera instrucción del mismo.

2. Interprete::Ejecutar

Ejecuta 1 instrucción, que es la apuntada por InstrAct. Devuelve elcódigo del error, 0 si no hay error.

3. Interprete::TopeDePila

Un traductor sencillo para un lenguaje simple

256

Page 257: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Devuelve 1 si hay elementos en la pila y en el parámetro pasadodevuelve el contenido del tope de la pila. Devuelve 0 si la pila está vacía, y elparámetro no es usado.

4. Interprete::Vaciar

Inicializa éste intérprete. Devuelve toda la memoria que eventualmenteesté usando.

5. Interprete::InstrActual

Devuelve 1 y la instrucción actual, apuntada por InstrAct, en formatocadena en la variable pasada como parámetro. Si no hay programa cargado,devuelve 0.

6. Interprete::CrearVar

Agrega una variable a la tabla de variables. El contenido inicial de lavariable es desconocido.

Devuelve 0 si no hay problemas y distinto a 0 si ya fue creada o faltamemoria.

7. Interprete::BuscarVar

Busca una variable en la tabla de variables. Devuelve el puntero aldescriptor de la misma o 0 si no fue encontrada.

8. Interprete::Apilar

Apila un valor (double) en la pila de éste intérprete. Devuelve 0 si nohay problemas, distinto a 0 si falta memoria.

9. Interprete::Desapilar

Desapila un valor (double) de la pila de éste intérprete. Devuelve 0 si nohay problemas, distinto a 0 si la pila estaba vacía.

Un traductor sencillo para un lenguaje simple

257

Page 258: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.7 Diseño e Implementación de la Interfase en Pantalla del Intérprete

El código para la interfase en pantalla fue generado por AppExpert, elgenerador de interfases de aplicaciones del Borland C++ 4.5. La misma fueretocada con el Resource Workshop del Borland C++ y quedó visualmente así:

Fig. 22 Interfase en pantalla del intérprete

El campo Sentencia del código intermedio actual muestra la sentenciaque se ejecutará en el paso siguiente.

La Tabla de Variables muestra el contenido de la tabla de variables. Sihay muchas variables aparecerá una barra de desplazamiento que permitiráhacer scroll en la lista.

El Registro de la Máquina muestra el contenido actual del registro delintérprete.

Contenido del tope de la pila muestra el contenido del tope de la pila delintérprete.

El botón Traza ejecuta la instrucción mostrada en el campo Sentencia

del código intermedio actual.

Un traductor sencillo para un lenguaje simple

258

Page 259: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

El botón Animar realiza una ejecución animada de instrucciones. Seejecuta una por una mostrando en cada paso el estado del intérprete. Se debeutilizar el botón Parar para detener la ejecución animada.

16.8 Guía del Usuario y Manual de Referencia del Programador delLenguaje Fuente

16.8.1 Introducción - Partes de un Programa

El lenguaje sirve únicamente para el tratamiento de números reales enmemoria.

Un programa en este lenguaje consta de dos partes bien definidas, asaber:

1. Declaraciones de variables.

2. Sentencias.

Las declaraciones de variables son opcionales y debe haber por lomenos una sentencia.

No hay distinción entre mayúsculas y minúsculas, y se incluye laposibilidad de incluir comentarios dentro del código fuente.

A continuación, las palabras claves se colocarán en mayúsculas.

16.8.2 Declaración de variables

Las variables únicamente pueden ser de un tipo y se declaran de lasiguiente forma:

VAR var1 [ , var2 [ , var3 [ ... ] ] ] ;

Se puede declarar una o más variables (lo que está entre corchetes esopcional). Los nombres de las variables deben ser identificadores quecomienzan con una letra seguido de combinaciones de letras y dígitos. Sepueden usar letras con acentos.

Un traductor sencillo para un lenguaje simple

259

Page 260: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.8.3 Sentencias

Las sentencias siempre finalizan con un ';' (punto y coma), y no hayproblemas en cuanto a la cantidad de espacios que se coloquen entre símbolos.

Existen tres tipos de sentencias:

1. Asignación:

Una asignación tiene la forma general siguiente:

IdentVar = Expresión ;

donde IdentVar es el nombre de una variable y Expresión es una expresiónválida del lenguaje. Ver sección "Expresiones válidas del Lenguaje" másadelante.

2. Sentencia iterativa Mientras ... hacer ...

Esta sentencia tiene la forma general siguiente:

MIENTRAS Expresión HACERSentencias

FIN ;

donde Expresión es una expresión válida del lenguaje y Sentencias son una omás sentencias válidas del lenguaje.

La semántica es: mientras Expresión se evalúe a 1, se ejecutan lassentencias. Esto es, si en la primera vez que se evalúa la expresión, la mismaresulta 0 entonces el bloque de sentencias puede no ejecutarse.

3. Sentencia iterativa Repetir ... hasta ...

Esta sentencia tiene la forma general siguiente:

REPETIRSentencias

HASTA Expresión ;

donde Expresión es una expresión válida del lenguaje y Sentencias son una omás sentencias válidas del lenguaje.

Un traductor sencillo para un lenguaje simple

260

Page 261: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La semántica es: ejecutar las Sentencias, luego, si Expresión evalúa a1, se vuelven a ejecutar las sentencias, sino se continúa con la sentenciasiguiente. Esto es, el bloque de sentencias se ejecuta al menos una vez.

16.8.4 Expresiones válidas del Lenguaje

Las expresiones válidas se describen mediante las siguientes reglas:

1. Si XXX es un identificador de variable o un número real, entonces XXXes una expresión válida. A este tipo de expresiones las denominaremosatómicas.

2. Si # es un operador unario y X es una expresión atómica, entonces # Xes una expresión válida, la cual también es atómica.

3. Si # es un operador binario y X1 y X2 son expresiones válidas, entoncesX1 # X2 es una expresión válida.

4. Si X es una expresión válida, ( X ) es una expresión válida, la cualtambién es atómica.

5. Son expresiones válidas las obtenidas por la aplicación reiterada de estasreglas.

Los operadores unarios se evalúan de derecha a izquierda, y losoperadores binarios de derecha a izquierda.

La precedencia de los operadores es la siguiente:

Precedencia Operador Observaciones

1. La más alta -!

( )

Menos unario Negador lógico Paréntesis

2. Operadores multiplicativos

*/

Multiplicación División

3. Operadores aditivos

+-

Suma Resta

Un traductor sencillo para un lenguaje simple

261

Page 262: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Precedencia Operador Observaciones

4. Operadores Relacionales

= =!=<

<=>

>=

Igual a Distinto de Menor que Menor o igual que Mayor que Mayor o igual que

5. Operador lógico && Conjunción

6. Operador lógico || Disyunción

Fig. 23 Precedencia de operadores en las expresiones del lenguaje

El resultado de una expresión donde el operador de menor precedenciasea el menos unario, un operador aditivo o un multiplicativo es un númeroreal.

El resultado de una expresión donde el operador de menor precedenciasea un operador lógico o un operador relacional es: 0 si es falso y distinto a 0si es verdadero. Para verdadero se utilizará un número entero.

El resultado de una expresión donde el operador de menor precedenciason los paréntesis, es del mismo tipo que la expresión que se encuentra dentrode ellos.

16.9 Módulos fuentes Independientes del Sistema Operativo

16.9.1 LENG.GLC: gramática del lenguaje fuente

// Gramática para un lenguaje simple donde se ilustra la implementación de// sentencias iterativas.// Versión 1 - Domingo E. Becker - 11 Dic 95// Usar Leng como sufijo en SLR1 v 2.x.

%{# ifndef __INTERP_H# include "interp.h"# endif

# include <string.h>

LSE<Ascii0> TablaDeVar;

Ent8 BuscarVar( const Ascii0 & var ) { if (! var.Long()) return 0; NodoLSE<Ascii0> * p = TablaDeVar.Entrada; while (p != 0) {

Un traductor sencillo para un lenguaje simple

262

Page 263: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (! stricmp(var, p->Dato)) break; p = p->pSig; } return p != 0;}

Ent8 AgregarVar( const Ascii0 & var ) { if (! var.Long()) return 0; // nombre nulo if (BuscarVar(var)) return 0; // ya está agregado return TablaDeVar.AgregFinal(var);}

LSE<CodInt> Programa;

Ent8 AgregarSentCI( Ent16ns Codigo, Ascii0 & Operando ) { NodoLSE<CodInt> * p = new NodoLSE<CodInt>; if (p == 0) return 0; p->Dato.Codigo = Codigo; p->Dato.Operando = Operando; return Programa.AgregFinal(p);}

Ent8 AgregarSentCI( Ent16ns Codigo ) { Ascii0 Nulo; return AgregarSentCI(Codigo, Nulo);}

class DescrRotulo {public: Ent16ns nRotulo; Ascii0 cRotulo;

DescrRotulo() { nRotulo = 0; } ~DescrRotulo() { }};

LSE<DescrRotulo> ListaDeRotulos; // sin resolver.

Ent8 GenerarRotulo( Ascii0 & Rotulo ) { Rotulo.printf("R%u", ListaDeRotulos.NumElem()); NodoLSE<DescrRotulo> * p = new NodoLSE<DescrRotulo>; if (p == 0) return 0; p->Dato.cRotulo = Rotulo; return ListaDeRotulos.AgregFinal(p);}

Ent8 AsignarRotulo( Ascii0 & Rotulo ) { NodoLSE<DescrRotulo> * p = ListaDeRotulos.Entrada; while (p != 0) { if (! strcmp(p->Dato.cRotulo, Rotulo)) break; p = p->pSig; } if (p == 0) return 0; p->Dato.nRotulo = Programa.NumElem(); return 1;}

NodoLSE<DescrRotulo> * BuscarRotulo( const Ascii0 & Rotulo ) { NodoLSE<DescrRotulo> * p = ListaDeRotulos.Entrada; while (p != 0) { if (! strcmp(p->Dato.cRotulo, Rotulo)) break; p = p->pSig; } return p;}

Un traductor sencillo para un lenguaje simple

263

Page 264: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent16ns ResolverRotulos() { Ent16ns NumRotRes = 0; NodoLSE<CodInt> * p = Programa.Entrada; NodoLSE<DescrRotulo> * q; while (p != 0) { if ((p->Dato.Codigo == CodInt::IrA || p->Dato.Codigo == CodInt::IrASiF|| p->Dato.Codigo == CodInt::IrASiV) && * (char *) p->Dato.Operando[0] == 'R') { q = BuscarRotulo(p->Dato.Operando); if (q != 0) { // si encuentra rótulo p->Dato.Operando = q->Dato.nRotulo; // resolver referenciaposterior ++NumRotRes; } } p = p->pSig; }

return NumRotRes;}

Ent8 GuardarPrograma( const char * NomArchCI, const char * NomArchTXT ) { if (NomArchCI == 0) return 0; Ent16ns NumInst = Programa.NumElem(); if (! NumInst) return 0; ArchivoSO ArchCI, ArchTXT; Ent8 GenerarTXT = NomArchTXT != 0; if (ArchCI.Abrir(NomArchCI, MA_E) || GenerarTXT && ArchTXT.Abrir(NomArchTXT, MA_E, MD_TXT)) return 0; NodoLSE<CodInt> * p; Ent16ns NumLin;

ArchCI << NumInst;

for (p = Programa.Entrada, NumLin = 1; p != 0; p = p->pSig, ++NumLin) { ArchCI << p->Dato; if (GenerarTXT) ArchTXT << NumLin << ": " << p->Dato << "\n"; }

ArchCI.Cerrar(); if (GenerarTXT) ArchTXT.Cerrar();

return 1;}

}%

# TERMINAL Ident# TERMINAL Real# IGNORAR Blancos# IGNORAR Coment

# MAYIGUALMIN

Leng --> Decl Sents %{ // Resolver rótulos de saltos hacia adelante: ResolverRotulos(); }% ;

Decl --> 'Var' Idents ';'| ;

Idents --> MásIdents Ident %{

Un traductor sencillo para un lenguaje simple

264

Page 265: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// nueva var declarada AgregarVar($2.CadTerm); AgregarSentCI(CodInt::CrearVar, $2.CadTerm); }% ;

MásIdents --> Idents ',' | ;

Sents ---> Sents SentPC | SentPC ; // SentPC es sentencia y punto y comaSentPC --> Sent ';' ;Sent ---> Asignación | Mientras | Repetir ;

Asignación --> Ident '=' Expresión %{ // asignación a Ident. Ver si existe, si es así, generar código if (BuscarVar($1.CadTerm)) AgregarSentCI(CodInt::Asignar, $1.CadTerm); }% ;

Rotulo --> %{ // asignamos a $$.CadTerm el número de instrucción actual (agenerar). Ent16ns NumInstAct = Programa.NumElem(); $$.CadTerm = NumInstAct; }% ;

Mientras --> 'Mientras' Rotulo ExprSaltoCond 'hacer' Sents 'Fin' %{ // salto incondicional al primer rótulo AgregarSentCI(CodInt::IrA, $2.CadTerm); // una vez agregada la sentencia, el rótulo del salto del noterminal // ExprSaltoCond debe referenciar a la posición actual: AsignarRotulo($3.CadTerm); // en CadTerm viene el nombre del rótulo }% ;

ExprSaltoCond --> Expresión %{ // aquí hay un salto si es que el registro de la máquina es falso GenerarRotulo($$.CadTerm); AgregarSentCI(CodInt::IrASiF, $$.CadTerm); }% ;

Repetir ---> 'Repetir' Rotulo Sents 'Hasta' Expresión %{ // salto condicional a Rotulo AgregarSentCI(CodInt::IrASiF, $2.CadTerm); }% ;

Expresión --> ExprLogicaO ;

ExprLogicaO -> ExprLogicaO '||' Apilar ExprLogicaY %{ // operar AgregarSentCI(CodInt::O); }% | ExprLogicaY ;

ExprLogicaY -> ExprLogicaY '&&' Apilar ExprRelacional %{ // operar AgregarSentCI(CodInt::Y); }% | ExprRelacional ;

ExprRelacional -> ExprRelacional '==' Apilar ExprArit %{ // operar AgregarSentCI(CodInt::Igual); }% | ExprRelacional '!=' Apilar ExprArit %{ // operar AgregarSentCI(CodInt::Distinto); }% | ExprRelacional '<' Apilar ExprArit %{

Un traductor sencillo para un lenguaje simple

265

Page 266: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// operar AgregarSentCI(CodInt::Menor); }% | ExprRelacional '<=' Apilar ExprArit %{ // operar AgregarSentCI(CodInt::MenorOIgual); }% | ExprRelacional '>' Apilar ExprArit %{ // operar AgregarSentCI(CodInt::Mayor); }% | ExprRelacional '>=' Apilar ExprArit %{ // operar AgregarSentCI(CodInt::MayorOIgual); }% | ExprArit ;

ExprArit ---> ExprArit '+' Apilar Producto %{ // operar AgregarSentCI(CodInt::Sumar); }% | ExprArit '-' Apilar Producto %{ // operar AgregarSentCI(CodInt::Restar); }% | Producto ;

Producto ---> Producto '*' Apilar Factor %{ // operar AgregarSentCI(CodInt::Multiplicar); }% | Producto '/' Apilar Factor %{ // operar AgregarSentCI(CodInt::Dividir); }% | Factor ;

Apilar --> %{ // Se supone que está por buscar la parte derecha de un operadorbinario. // Apilar el valor del registro de la máquina. AgregarSentCI(CodInt::ApilarReg); }% ;

Factor -----> Ident %{ // mover el valor de Ident al registro de la máquina if (BuscarVar($1.CadTerm)) AgregarSentCI(CodInt::MoverVar, $1.CadTerm); }% | Real %{ // mover el valor del Real al registro dela máquina AgregarSentCI(CodInt::MoverCte, $1.CadTerm); }% | '-' Factor %{ // operar AgregarSentCI(CodInt::Menos); }% | '!' Factor %{ // operar AgregarSentCI(CodInt::Negar); }% | '(' Expresión ')' ;

Un traductor sencillo para un lenguaje simple

266

Page 267: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.9.2 IDENT.ER: expresión regular para un identificador

// Exp reg para describir un identificador:# Letra [a-zA-Z_áéíóúñÑüÜ]# Digito [0-9]Letra (Letra | Digito)*

16.9.3 REAL.ER: expresión regular para un número real

// Expresión regular para un número real en formato C++:# Díg [0-9]Díg * '.' ? Díg + ( (e | E) Díg + ) ?

16.9.4 BLANCOS.ER: expresión regular para los blancos

// Expresión regular para blancos:[ \n\r\f\t\v] +

16.9.5 COMENT.ER: expresión regular para los comentarios

// Exp reg para comentarios similares a éste:/ / .*

16.9.6 INTERP.H: archivo cabecera con declaraciones

# ifndef __INTERP_H# define __INTERP_H

// interp.h: declaración de clases para implementar un intérprete decódigo// intermedio.

# ifndef __LSE_H# include "lse.h"# endif

# ifndef __VECTOR_H# include "vector.h"# endif

# ifndef __ARCHIVO_H# include <archivo.h># endif

// Clase CodInt: el código de la máquina hipotética (el intérprete)// consta de dos partes: el código de operación y el operando.// El código de operación se codifica con el enum dentro de la clase.// El operando es siempre una cadena de texto que contendrá un número realo// un identificador de variable a crear.

class CodInt {public: Ent16ns Codigo; Ascii0 Operando;

Un traductor sencillo para un lenguaje simple

267

Page 268: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

enum { NoOp, CrearVar, Asignar, MoverVar, MoverCte, ApilarReg, O, Y, Negar, Igual, Distinto, Menor, MenorOIgual, Mayor,MayorOIgual, Sumar, Restar, Multiplicar, Dividir, Menos, IrA, IrASiF, IrASiV }; CodInt() { Codigo = NoOp; } ~CodInt() { }

static const char * CadCodigo( Ent16ns Codigo ); const char * CadCodigo() const { return CadCodigo(Codigo); } void Cadena( Ascii0 & Cad ) const;};

Archivo & operator << ( Archivo & arch, const CodInt & ci );ArchivoSO & operator << ( ArchivoSO & arch, const CodInt & ci );ArchivoSO & operator >> ( ArchivoSO & arch, CodInt & ci );

Ent16 TraducirDeLengACodInt( const char * NomArch, Ascii0 & CadPosErr );

Ent16 CargarPrograma( const char * NomArch, Vector<CodInt> & Programa );

class Variable {public: Ascii0 Ident; double Valor;

Variable() { } ~Variable() { }};

class Interprete {public: Vector<CodInt> Programa; unsigned InstrAct; double Registro; LSE<double> Pila; // Pila implementada en lista simple encadenada LSE<Variable> TablaDeVar; Ent16ns Error;

Interprete() { Registro = InstrAct = Error = 0; } ~Interprete() { Vaciar(); }

Ent16 CargarPrograma( const char * NomArch ); Ent8 Ejecutar(); // Ejecuta 1 instrucción de código intermedio,solamente. Ent8 TopeDePila( double & valor ) const; // devuelve el valor del topede la pila. void Vaciar(); // devuelve la mem dinámica usada por éste intérprete Ent8 InstrActual( Ascii0 & cad ); enum { SinError = 0, FinProg, FaltanOprnds, DirInval, VarNoDecl,VarDeclPrev, FaltaMem, PilaVacia, Div0 }; Ent8 CrearVar( const Ascii0 & Ident ); Variable * BuscarVar( const Ascii0 & Ident ); Ent8 Apilar( double Valor ); Ent8 Desapilar( double & Valor );};

inline Ent16 Interprete::CargarPrograma( const char * NomArch ) { Vaciar(); return ::CargarPrograma(NomArch, Programa);}

Un traductor sencillo para un lenguaje simple

268

Page 269: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inline void Interprete::Vaciar() { Programa.Vaciar(); Registro = InstrAct = Error = 0; Pila.Vaciar(); TablaDeVar.Vaciar();}

inline Ent8 Interprete::TopeDePila( double & valor ) const { if (Pila.Entrada != 0) { valor = Pila.Entrada->Dato; return 1; } return 0;}

inline Ent8 Interprete::InstrActual( Ascii0 & cad ) { if (InstrAct < Programa.Tam) Programa[InstrAct].Cadena(cad); return InstrAct < Programa.Tam;}

# endif // # ifndef __INTERP_H

16.9.7 TRADUCIR.CMM: función TraducirDeLengACodInt

// traducir.cmm Mar 12 Dic 95// Domingo E. Becker

# include "leng.cmm" // generado por SLR1 v 2.x

Ent16 TraducirDeLengACodInt( const char * NomArch, Ascii0 & CadPosErr ) { Ascii0 Fuente; ArchivoSO ArchFuente;

if (ArchFuente.Abrir(NomArch, MA_L)) return 0;

if (! Fuente.Reasignar(ArchFuente.Tam() + 1)) return 0;

Ent16ns NumBytes = ArchFuente.Leer(Fuente, ArchFuente.Tam()); * Fuente[NumBytes] = 0; ArchFuente.Cerrar();

TablaDeVar.Vaciar(); Programa.Vaciar(); ListaDeRotulos.Vaciar();

Ascii0 NomArchCI, NomArchTXT; NomArchCI = NomExt(NomArch, ".ci"); NomArchTXT = NomExt(NomArch, ".txt"); alLeng.Reiniciar(Fuente); Ent8 r = asLeng.Analizar(alLeng, CadPosErr); if (r) r = GuardarPrograma(NomArchCI, NomArchTXT);

TablaDeVar.Vaciar(); Programa.Vaciar(); ListaDeRotulos.Vaciar();

return r;}

Un traductor sencillo para un lenguaje simple

269

Page 270: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

16.9.8 INTERP.CMM: funciones del intérprete

// interp.cmm

# include "interp.h"

const char * CodInt::CadCodigo( Ent16ns Codigo ) { const char * p; switch (Codigo) { case NoOp: p = "NoOp"; break;

case CrearVar: p = "CrearVar"; break;

case Asignar: p = "Asignar"; break;

case MoverVar: p = "MoverVar"; break;

case MoverCte: p = "MoverCte"; break;

case ApilarReg: p = "ApilarReg"; break;

case O: p = "O"; break;

case Y: p = "Y"; break;

case Negar: p = "Negar"; break;

case Igual: p = "Igual"; break;

case Distinto: p = "Distinto"; break;

case Menor: p = "Menor"; break;

case MenorOIgual: p = "MenorOIgual"; break;

case Mayor: p = "Mayor"; break;

Un traductor sencillo para un lenguaje simple

270

Page 271: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case MayorOIgual: p = "MayorOIgual"; break;

case Sumar: p = "Sumar"; break;

case Restar: p = "Restar"; break;

case Multiplicar: p = "Multiplicar"; break;

case Dividir: p = "Dividir"; break;

case Menos: p = "Menos"; break;

case IrA: p = "IrA"; break;

case IrASiF: p = "IrASiF"; break;

case IrASiV: p = "IrASiV"; break;

default: p = "Desconocido"; } return p;}

void CodInt::Cadena( Ascii0 & Cad ) const { switch (Codigo) { case CrearVar: case Asignar: case MoverVar: case MoverCte: case IrA: case IrASiF: case IrASiV: Cad.printf("%s %s", CadCodigo(), (const char *) Operando); break;

default: Cad = CadCodigo(); }}

Archivo & operator << ( Archivo & arch, const CodInt & ci ) { Ascii0 cad; ci.Cadena(cad); arch << (const char *) cad; return arch;}

Un traductor sencillo para un lenguaje simple

271

Page 272: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ArchivoSO & operator << ( ArchivoSO & arch, const CodInt & ci ) { if (! arch.TxtBin()) operator << ((Archivo &) arch, ci); else arch << ci.Codigo << ci.Operando; return arch;}

ArchivoSO & operator >> ( ArchivoSO & arch, CodInt & ci ) { arch >> ci.Codigo >> ci.Operando; return arch;}

Ent16 CargarPrograma( const char * NomArch, Vector<CodInt> & Programa ) { Programa.Vaciar(); if (NomArch == 0) return 0; ArchivoSO arch; if (arch.Abrir(NomArch, MA_L)) return 0; Ent16ns NumInst, i; arch >> NumInst; if (! NumInst || ! Programa.Reasignar(NumInst)) return 0;

for (i = 0; i < NumInst; ++i) arch >> Programa[i];

arch.Cerrar();

return 1;}

Ent8 Interprete::Ejecutar() { if (InstrAct >= Programa.Tam) return Error = FinProg;

Variable * pVar; double OperandoIzq; Ent16ns CodOp = Programa[InstrAct].Codigo;

Error = SinError;

switch (CodOp) { case CodInt::CrearVar: CrearVar(Programa[InstrAct].Operando); break;

case CodInt::Asignar: pVar = BuscarVar(Programa[InstrAct].Operando); if (pVar != 0) pVar->Valor = Registro; break;

case CodInt::MoverVar: pVar = BuscarVar(Programa[InstrAct].Operando); if (pVar != 0) Registro = pVar->Valor; break;

case CodInt::MoverCte: Registro = Programa[InstrAct].Operando; break;

case CodInt::ApilarReg: Apilar(Registro); break;

case CodInt::O: if (! Desapilar(OperandoIzq))

Un traductor sencillo para un lenguaje simple

272

Page 273: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Registro = (int) OperandoIzq || (int) Registro; break;

case CodInt::Y: if (! Desapilar(OperandoIzq)) Registro = (int) OperandoIzq && (int) Registro; break;

case CodInt::Negar: Registro = ! (int) Registro; break;

case CodInt::Igual: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq == Registro; break;

case CodInt::Distinto: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq != Registro; break;

case CodInt::Menor: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq < Registro; break;

case CodInt::MenorOIgual: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq <= Registro; break;

case CodInt::Mayor: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq > Registro; break;

case CodInt::MayorOIgual: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq >= Registro; break;

case CodInt::Sumar: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq + Registro; break;

case CodInt::Restar: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq - Registro; break;

case CodInt::Multiplicar: if (! Desapilar(OperandoIzq)) Registro = OperandoIzq * Registro; break;

case CodInt::Dividir: if (! Desapilar(OperandoIzq)) if (Registro == 0) Error = Div0; else Registro = OperandoIzq / Registro; break;

case CodInt::Menos: Registro = - Registro; break;

Un traductor sencillo para un lenguaje simple

273

Page 274: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case CodInt::IrASiV: if (! (int) Registro) { InstrAct++; if (InstrAct >= Programa.Tam) Error = FinProg; break; } case CodInt::IrA: InstrAct = (Ent16ns) Programa[InstrAct].Operando; if (InstrAct >= Programa.Tam) Error = FinProg; break;

case CodInt::IrASiF: if ((int) Registro) { InstrAct++; if (InstrAct >= Programa.Tam) Error = FinProg; break; } InstrAct = (Ent16ns) Programa[InstrAct].Operando; if (InstrAct >= Programa.Tam) Error = FinProg; break; }

if (Error == SinError && CodOp != CodInt::IrASiF && CodOp != CodInt::IrASiV && CodOp != CodInt::IrA) { InstrAct++; if (InstrAct >= Programa.Tam) Error = FinProg; }

return Error;}

Ent8 Interprete::CrearVar( const Ascii0 & Ident ) { if (BuscarVar(Ident) == 0) { NodoLSE<Variable> * p = new NodoLSE<Variable>; if (p == 0) Error = FaltaMem; else { p->Dato.Ident = Ident; TablaDeVar.AgregFinal(p); Error = SinError; } } else Error = VarDeclPrev;

return Error;}

Variable * Interprete::BuscarVar( const Ascii0 & Ident ) { NodoLSE<Variable> * p = TablaDeVar.Entrada; while (p != 0) { if (! stricmp(p->Dato.Ident, Ident)) break; // encontrado p = p->pSig; // sino seguir buscando } Error = p == 0 ? VarNoDecl : SinError; return p != 0 ? & p->Dato : 0;}

Ent8 Interprete::Apilar( double Valor ) { return Error = Pila.AgregComienzo(Valor) ? SinError : FaltaMem;}

Un traductor sencillo para un lenguaje simple

274

Page 275: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent8 Interprete::Desapilar( double & Valor ) { NodoLSE<double> * p = Pila.Entrada; if (p != 0) { Valor = p->Dato; Error = SinError; } else Error = PilaVacia; Pila.Eliminar(p); return Error;}

16.10 Módulos fuentes dependientes del Sistema Operativo

Se mostrarán solamente los módulos importantes. Los demás sonfácilmente generables utilizando el AppExpert del Borland C++.

16.10.1 DLGINTER.H: generado por AppExpert y modificado por el autor

#if !defined(__dlginter_h) // Sentry, use file only if it'snot already included.#define __dlginter_h

/* Project leng Copyright © 1995. All Rights Reserved.

SUBSYSTEM: leng.exe Application FILE: dlginter.h AUTHOR: Domingo Eduardo Becker.

OVERVIEW ======== Class definition for DlgInterp (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include <owl\listbox.h>#include "lengapp.rh" // Definition of all resources.

# include "interp.h"

//{{TDialog = DlgInterp}}struct DlgInterpXfer {//{{DlgInterpXFER_DATA}} TListBoxData ListaVars;//{{DlgInterpXFER_DATA_END}}};

class DlgInterp : public TDialog {public:

DlgInterp (TWindow *parent, TResId resId = IDD_INTERPRETE, TModule*module = 0); virtual ~DlgInterp ();

Un traductor sencillo para un lenguaje simple

275

Page 276: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Interprete Interp; Ent8 Animando;

void MostrarEstado(); void CargarListaVars();

//{{DlgInterpVIRTUAL_BEGIN}}public: virtual void SetupWindow ();//{{DlgInterpVIRTUAL_END}}

//{{DlgInterpRSP_TBL_BEGIN}}protected: void Traza (); void EjecucionAnimada (); void PararAnimacion ();//{{DlgInterpRSP_TBL_END}}DECLARE_RESPONSE_TABLE(DlgInterp);

//{{DlgInterpXFER_DEF}}protected: TListBox *ListaVars;

//{{DlgInterpXFER_DEF_END}}}; //{{DlgInterp}}

#endif // __dlginter_h sentry.

16.10.2 DLGINTER.CMM: generado por AppExpert y modificado por el autor

/* Project leng Copyright © 1995. All Rights Reserved.

SUBSYSTEM: leng.exe Application FILE: dlginter.cmm AUTHOR: Domingo Eduardo Becker.

OVERVIEW ======== Source file for implementation of DlgInterp (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "lengapp.h"#include "dlginter.h"

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(DlgInterp, TDialog)//{{DlgInterpRSP_TBL_BEGIN}} EV_BN_CLICKED(IDOK, Traza), EV_BN_CLICKED(IDC_ANIMAR, EjecucionAnimada), EV_BN_CLICKED(IDC_PARAR, PararAnimacion),//{{DlgInterpRSP_TBL_END}}

Un traductor sencillo para un lenguaje simple

276

Page 277: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

END_RESPONSE_TABLE;

//{{DlgInterp Implementation}}

//////////////////////////////////////////////////////////// DlgInterp// ==========// Construction/Destruction handling.static DlgInterpXfer DlgInterpData;

DlgInterp::DlgInterp (TWindow *parent, TResId resId, TModule *module) : TDialog(parent, resId, module){//{{DlgInterpXFER_USE}} ListaVars = new TListBox(this, IDC_VARIABLES);

SetTransferBuffer(&DlgInterpData);//{{DlgInterpXFER_USE_END}}

// INSERT>> Your constructor code here. Animando = 0;}

DlgInterp::~DlgInterp (){ Destroy();

// INSERT>> Your destructor code here.}

void DlgInterp::SetupWindow (){ TDialog::SetupWindow();

// INSERT>> Your code here. MostrarEstado();}

void DlgInterp::MostrarEstado() { Ascii0 cad; double real; if (Interp.Programa.Tam){ cad = Interp.Registro; SetDlgItemText(IDC_REGISTRO, cad); if (Interp.TopeDePila(real)) { cad = real; SetDlgItemText(IDC_PILA, cad); } else SetDlgItemText(IDC_PILA, "Vacía"); Interp.InstrActual(cad); SetDlgItemText(IDC_CODIGO, cad); CargarListaVars(); } else { SetDlgItemText(IDC_REGISTRO, "0"); SetDlgItemText(IDC_CODIGO, "No hay código"); SetDlgItemText(IDC_PILA, "Vacía"); ListaVars->ClearList(); }}

void DlgInterp::Traza ()

Un traductor sencillo para un lenguaje simple

277

Page 278: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

{ // INSERT>> Your code here. Ent8 r = Interp.Ejecutar(); MostrarEstado(); if (r != Interprete::SinError) { if (r == Interprete::FinProg) MessageBox("El programa ha finalizado.", "Observación", MB_OK | MB_ICONINFORMATION); else MessageBox("Error de ejecución", "ERROR", MB_OK | MB_ICONHAND);

Animando = 0; // por las dudas

CmOk(); }}

void DlgInterp::CargarListaVars() { ListaVars->ClearList(); Ascii0 cad; NodoLSE<Variable> * p; for (p = Interp.TablaDeVar.Entrada; p != 0; p = p->pSig) { cad.printf("%s: %g", (char *) p->Dato.Ident, p->Dato.Valor); ListaVars->AddString(cad); }}

void DlgInterp::EjecucionAnimada (){ // INSERT>> Your code here. Animando = 1; while (Animando) { Traza(); GetApplication()->PumpWaitingMessages(); // pseudoparalelismo deWindows }}

void DlgInterp::PararAnimacion (){ // INSERT>> Your code here. Animando = 0;}

La función DlgInterp::MostrarEstado muestra el estado del intérpreteen la pantalla.

La función DlgInterp::Traza pide al objeto intérprete que ejecute unainstrucción y muestra el estado en pantalla luego de ejecutarla.

La función DlgInterp::EjecucionAnimada realiza la ejecuciónanimada, mostrando el estado en pantalla para cada instrucción que se ejecuta.Esta función puede ser interrumpida por el usuario. Termina su ejecucióncuando el usuario así lo pide o cuando no hay más instrucciones para ejecutar.

Un traductor sencillo para un lenguaje simple

278

Page 279: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La función DlgInterp::PararAnimacion es automáticamente llamadapor el sistema operativo cuando el usuario presiona el botón Parar de laventana del intérprete.

Un traductor sencillo para un lenguaje simple

279

Page 280: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Parte 5. Anexos, Codigos Fuentes yConclusión.

280

Page 281: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 17: Introducción a las Gramáticas Generativas

Los conceptos aquí presentados se manejaban antes de que Chomskypresentara su trabajo sobre lingüística computacional.

Lo que Chomsky hizo fue encontrar la explicación matemática delmecanismo del lenguaje, partiendo de estudios de lingüística que se habíanrealizado hasta ese momento.

Hasta el día de la edición de este trabajo, no se presentaron objecionesvalederas a los estudios realizados por Chomsky, aunque, a primera vista,pareciera ser que la Teoría de los Lenguajes Formales va por otro caminodistinto al que tomó Chomsky.

Este capítulo está basado principalmente en Nique [1985]. ChristianNique es de nacionalidad francesa. Aunque en Francia había una Escuela queseguía caminos distintos en la investigación a los que seguía la EscuelaAmericana, donde estaba Chomsky, fueron los estudios de éste último los quepredominaron e hicieron historia, y los lingüistas franceses y alemanes los quemás lo usaron en un principio.

Al finalizar la lectura de este capítulo, el lector estará en mejorescondiciones de iniciar el estudio de la Teoría de los Lenguajes Formales,tratada en el capítulo 2 de este trabajo.

17.1 Un Mecanismo Finito para Generar un Número Infinito deOraciones

No sólo el hablante posee implícitamente el mecanismo del lenguaje,sino que además es "en todo momento capaz de emitir espontáneamente, o depercibir o comprender, un número indefinido de oraciones que, en su mayorparte, no ha pronunciado nunca ni oído antes". Esto equivale a decir que,cuando se habla , se hace algo más que reproducir esquemas de oraciones quese escuchó antes, sino que también se crean oraciones nuevas. Entonces elmecanismo del lenguaje es un mecanismo creador.

La repetición de oraciones es excepcional, y responde a características ycostumbres de algunos hablantes, por lo que (la repetición) no tiene ningunarelación con la utilización del lenguaje. No se habla repitiendo lo que se haoído, sino mediante un acto de creación cada vez, y esta característica esentonces la principal en el uso del lenguaje.

Introducción a las Gramáticas Generativas

281

Page 282: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Existen dos clases de creatividad que es preciso no confundir. Laprimera, que se llama creatividad por cambio de reglas, consistefundamentalmente en cambiar ciertas partes del mecanismo lenguaje. Es lo quehace variar la pronunciación de ciertas palabras, que crea otras nuevas, queacaba por admitir como gramatical lo que no era en un principio, nada más queuna desviación en relación a las reglas. El segundo tipo es completamentediferente. Se le llama creatividad gobernada por las reglas. Es la que permiteal hablante, por aplicación de las reglas de la gramática, crear una infinidad deoraciones. Esto no es posible más que por la misma naturaleza de las reglas dellenguaje, que poseen una propiedad muy particular, llamada en matemáticasrecursividad, es decir, la posibilidad de reproducirse hasta el infinito.

Se denomina competencia (Chomsky [1965]) al conocimiento que elemisor-receptor tiene de su lengua. La actuación se define como la utilizaciónreal en situaciones concretas de la competencia. A la competencia se laconsidera como un mecanismo finito, es decir, formado por un númerolimitado de reglas y capaz de generar un número infinito de oraciones.

La gramática, que no es otra cosa que la explicación dela competencia, deberá responder a la misma definición para ser válida. Poreso deberá disponer de reglas estrictas, formuladas con una extremadaprecisión, y que podrán traducir esta propiedad de la competencia: la de ser unmecanismo finito para generar un número infinito de oraciones.

17.2 Teoría General y Gramáticas Particulares

Normalmente se reserva el término gramática para el estudio de laslenguas particulares, y el de teoría general para el estudio de lasparticularidades en común que tienen todos los lenguajes, las diferencias entreellos, y entonces, las condiciones sobre la forma que debe tener la gramáticade cada lengua.

Se ve así la importancia de la teoría general (TG en adelante) para laelaboración de las gramáticas particulares: éstas deben tener en cuenta la TGpara ser adecuadas.

Se denomina corpus a un conjunto de oraciones de un lenguaje. Para elestudio de lenguas que ya no existen, se trata de conseguir un corpusrepresentativo de la misma.

Introducción a las Gramáticas Generativas

282

Page 283: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La TG puede ser concebida de tres maneras diferentes incluyentes entresí, y en cada una de ellas tendrá tareas distintas:

1. La TG puede proporcionar un conjunto de instrucciones, un mecanismo, quepermita al lingüista construir la mejor gramática de una lengua, a partir de uncorpus dado. El mecanismo sería de alguna manera "un procedimiento dedescubrimiento" de la gramática adecuada para cada lengua. Gráficamente:

Fig. 24 La Teoría General como un mecanismo para construirgramática.

2. La TG puede proporcionar un método que, dados un corpus y unagramática, permita decir si la gramática es o no adecuada. Sería en este caso"un procedimiento de decisión".

Fig. 25 La Teoría General como un mecanismo de validación degramáticas.

3. La TG puede, por último, ante dos gramáticas (o más) y un corpus, decircuál de las dos es la más adecuada. Se le llama entonces "procedimiento deevaluación de las gramáticas".

Fig. 26 La Teoría General como un mecanismo de selección degramáticas.

Dato: Corpus Respuesta: gramáticaTG

Datos: Respuesta: la gramática esTG

Corpus

Gramáticao no es la adecuada

Datos: Respuesta: la mejorTG

Corpus

Gramática 1

gramática es ...Gramática 2

Introducción a las Gramáticas Generativas

283

Page 284: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

La primera es la más exigente, pero no la más difícil, viene a pedir a lateoría que diga qué forma debe tener la gramática de cada lengua. Estapregunta es difícil de responder, por lo tanto no se está en condiciones deconstruir un procedimiento general de descubrimiento de las gramáticas. Perolo que si se puede, es usar ciertos criterios para construir una gramática paraun corpus dado.

La segunda es un poco menos exigente, puesto que sólo se trata deverificar si las oraciones del corpus pueden ser generadas por la gramática, enotras palabras, que se las pueda analizar sintácticamente por medio de lagramática.

La tercera es la más comprometida puesto que la selección se realiza enbase a criterios formados con la experiencia del lingüista, y los criterios a usarpueden ser varios, todos ellos con fundamentos válidos.

La Teoría General de la que se habló, recibió el nombre de Teoría de

los Lenguajes Formales, los lingüistas la conocen también como Lingüística

Computacional. Los temas tratados por esta teoría son mucho más profundosque los tratados en este capítulo.

17.3 Gramaticalidad e Interpretabilidad

La Gramaticalidad es otro concepto importante. Para tener una visiónmás clara de lo que es la gramaticalidad, es preciso oponerla a lainterpretabilidad.

Sea la oración siguiente:

El padre del primo del tío del abuelo del vecino de la hermana mayor

de la segunda mujer del escribano vino ayer a verme.

Sin duda, esta oración es ininterpretable cuando se accede a ella porprimera vez, pero es gramaticalmente correcta, y obedece a una de las reglasque subyacen en la competencia de la que se ha hablado anteriormente.

Es posible encontrarse frente a cuatro tipos de oraciones que son:

1. Gramaticales e interpretables. Ejemplo:A Pedro le gusta el chocolate.

Introducción a las Gramáticas Generativas

284

Page 285: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

2. Gramaticales e ininterpretables. Ejemplo:Pedro, cuyo amigo cuyo hermano bebe está borracho ha comidochocolate.

3. Agramaticales e interpretables. Ejemplo:Mamá, da buen chocolate bebé.

4. Agramaticales e ininterpretables. Ejemplo:Chocolate la había ser lo canta árbol.

Si se analiza sin mayor precisión la oración del ejemplo 2:

se observará que la oración está gramaticalmente bien formada.

En realidad, parece ser que la noción de interpretabilidad deberíaintegrarse en el estudio de la actuación, ya que depende de factores como lalimitación de la atención, comprensión, memoria, etc.

Una teoría de la competencia, por el contrario, es una teoría delmecanismo del lenguaje, y debe, pues, dar cuenta de las oraciones gramaticalesy excluir las agramaticales. La noción de gramaticalidad no puede ni debeconfundirse con la aparición en un corpus, ni con la probabilidad estadística deaparición, ya que un buen número de oraciones que se pronuncian no sontotalmente gramaticales, y las que son gramaticales en algunos casos nunca sepronuncian.

En este sentido, la teoría de la competencia, es decir, la gramática

generativa, aparece un poco como gramática normativa. Pero no lo es delmismo modo que lo eran las gramáticas tradicionales. No trata de preservar el"hermoso" lenguaje, y no se erige en el defensor de un pretendido "lenguajecorrecto". Toma el lenguaje tal cual es, diferente según los individuos, segúnlas clases sociales, según las situaciones, y trata sólo de dar cuenta de sufuncionamiento. Pero no dicta ninguna regla del tipo: "No hay que decir ...sino hay que decir ...". Constata lo que se dice, lo que no se dice, o que no sedice ya tal o cual oración. No se pronuncia nunca sobre las nociones de "bueno mal lenguaje", "estilo pesado", "torpeza", etc. Le basta decir cuáles son las

Pablo ha comido el chocolate

cuyo amigo está borracho

cuyo hermano bebe

Introducción a las Gramáticas Generativas

285

Page 286: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

oraciones gramaticales y cuáles las agramaticales, para dar cuenta de laestructura de las primeras y excluir las segundas.

17.4 La Gramática Generativa

17.4.1 Noción de Gramática Generativa

Apoyándose únicamente sobre las reflexiones precedentes, es posibleconsiderar la gramática como una teoría que da cuenta de las oracionesgramaticales, y sólo de las gramaticales. Pero esta definición por si sola no essatisfactoria. La definición más correcta es:

Una gramática es un modelo de la competencia, es decir, que debe

hacer explícita la gramática implícita que poseen los sujetos hablantes.

El término modelo es muy importante. La gramática, de alguna manera,es una máquina, un mecanismo que nos permite generar oraciones.Esquemáticamente:

Fig. 27 La gramática como mecanismo para generar oraciones.

Este esquema muestra en qué sentido la gramática ha podido sercalificada de generativa. Permite generar el conjunto infinito de oraciones dela lengua. Pero no hay que confundirla con una máquina que permita laemisión real de las oraciones.

Además, se hace la observación de que la gramática es "neutra" tantofrente al emisor como al receptor. Es una teoría de la estructura y delfuncionamiento del código lingüístico, y no dice nada respecto al mecanismofísico-psicológico que permite hablar y comprender.

La gramática generativa es tan sólo la explicitación del sistema de reglasque subyace a la competencia, y la competencia es común al hablante y al

Constitucion

de

Oraciones

Entrada(instrucciones o reglas)

Salida

(oraciones realizadas)

Introducción a las Gramáticas Generativas

286

Page 287: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

oyente. En realidad, el estudio de la emisión y de la recepción cae dentro deuna teoría de la actuación.

De hecho, la gramática generativa no es una gramática en el sentido enel que habitualmente se da a esta palabra. Sin duda se ocupa también de laestructura de la lengua, pero si se distingue de las otras gramáticas no es sólopor el punto de vista que ha elegido, sino sobre todo por el fin que se haimpuesto. Las gramáticas tradicionales y estructurales eran modelostaxonómicos de la lengua, mientras que las generativas son un modeloexplicativo. Desea no sólo formar un inventario de los elementos lingüísticos,sino también explicar su funcionamiento, la regularidad de cada lengua, lascaracterísticas comunes universales del lenguaje, y dar cuenta del fenómeno dela creatividad. En este sentido, las gramáticas taxonómicas son a la vezanteriores y necesarias para la gramática generativa: las primeras describen loshechos lingüísticos que la segunda explica.

Al construir una gramática generativa, es decir, al dar cuenta de lacompetencia, se debe partir de un hablante-oyente ideal que pertenezca a unacomunidad lingüística completamente homogénea, que conozca perfectamentesu lengua y que, cuando aplique ese conocimiento en una actuación real, noesté influenciado por condiciones gramaticalmente irrelevantes como lalimitación de memoria, distracciones de interés o atención, o errores. Es unateoría de la actuación la que deberá considerar estos diversos fenómenos.

17.4.2 Sincronía / Diacronía

Por el mismo fin que se impone, la gramática generativa no puedeestudiar la lengua más que en un cierto momento de su historia.

Los términos lingüística sincrónica y lingüística diacrónica fueronintroducidos por Saussure [1916] para distinguir los estudios que tienen porobjeto un cierto estado de la lengua de aquellos que se interesan por suevolución, respectivamente.

La gramática generativa no puede ser más que sincrónica, en el mismosentido en que la competencia no puede estar situada más que en un momentodeterminado en el tiempo y en la evolución de la lengua.

17.4.3 Análisis en Constituyentes Inmediatos

Se desarrollará un ejemplo simple para explicar cómo construir unagramática generativa. Lo que se está por hacer es descubrir los aspectos más

Introducción a las Gramáticas Generativas

287

Page 288: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

importantes de la teoría general antes mencionada. A tal efecto, se debeolvidar por un momento de la TG y concentras la atención en la tarea que éstapuede realizar: dado un corpus, obtener la gramática adecuada para el lenguajeal que pertenece el corpus.

Se tiene un corpus cuyos componentes son oraciones que tienen lamisma estructura gramatical, según una gramática tradicional. Las oracionespertenecen al lenguaje utilizado en la escritura de este documento (Castellano).El corpus es el siguiente:

Fig. 28 Un corpus del Castellano.

Si tomamos la primera oración, lo primero que se observa es unaoración correcta. Esa oración tiene sujeto y predicado, que son los dosconstituyentes inmediatos de la oración.

Si se analiza el sujeto, se observa que tiene un núcleo y un modificador

directo (MD); y éstos son sus componentes inmediatos. Lo mismo ocurre conel predicado, que tiene un verbo y un objeto directo (OD) comoconstituyentes. A su vez, el OD está formado por un núcleo y un MD.Gráficamente:

Fig. 29 Separación de la oración en constituyentes inmediatos.

El caballo salta el alambrado.El gato toma la leche.El perro come la carne.El reloj marca la hora.La niña saca la lengua.

El caballo salta el alambrado .

El caballo salta el alambrado .

El caballo salta el alambrado .

El caballo salta el alambrado .1

2

3

4

Introducción a las Gramáticas Generativas

288

Page 289: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

o bien:

Fig. 30 Análisis de la oración en constituyentes inmediatos.

El paso 1 toma la oración. El paso 2 separa la oración en suscomponentes inmediatos y así sucesivamente.

Se podría decir que del paso 4 sigue un quinto:

Fig. 31 Ultimo paso del análisis en constituyentes inmediatos.

con el cual demostramos que el análisis en constituyentes inmediatos esválido.

Si al esquema realizado se lo grafica de otra forma, se tendría losiguiente:

1

2

3

4

O

S P

V OD

V

MD N

MD N MD N

4 V

El caballo salta el alambrado .5

MD N MD N

O

S P

V OD

El caballo salta el alambrado

MD N MD N

Introducción a las Gramáticas Generativas

289

Page 290: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 32 Análisis en componentes inmediatos (análisis sintáctico)de la oración del corpus.

Este esquema es similar al anterior, y difiere solamente en que seutilizan menos líneas. Como se observará, el gráfico es más claro que elanterior. A este tipo de esquema se lo conoce como árbol, y en lingüísticacomputacional, como árbol de derivación o de análisis sintáctico.

Para generar las oraciones, la gramática debe poseer un conjunto deinstrucciones. Estas se presentan bajo la forma de reglas que permiten rescribirun símbolo en una secuencia de símbolos. El problema aquí ya no es laestructura de una oración particular, sino el de la estructura de toda oraciónpotencial.

En el corpus, las oraciones estaban formadas por sujetos (S) ypredicados (P). Se puede, entonces, formular una regla que diga más o menoslo siguiente: si se está en presencia del símbolo O (oración), rescríbalo en S P(es decir, la concatenación de las nociones sujeto y predicado). Esta reglatendrá la forma:

O ---> S P

Se leerá "O se rescribe en S P".

La regla dada indica cómo pasar del paso 1 al 2 en el análisis realizadoarriba, es decir, dice cuáles son los constituyentes de la noción O (oración). Sepuede así escribir el conjunto de reglas:

O ---> S PS ---> MD NP ---> V ODOD ---> MD N

(Se debe tener en cuenta que en este ejemplo no se consideran aspectossemánticos y morfológicos.)

Estas reglas no son suficientes para generar verdaderamente lasoraciones. Hay que añadirles otra serie de reglas llamadas reglas léxicas:

MD ---> el | laN ---> caballo | alambrado | gato | leche | perro | carne | reloj |

Introducción a las Gramáticas Generativas

290

Page 291: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

hora | niña | lenguaV ---> salta | toma | come | marca | saca

Se leerá "MD se rescribe en el ó en la". El "ó" es en sentido excluyente. Laspalabras que aparecen en las reglas lexicales son todas aquellas que formabanalguna oración en el corpus, no son palabras que no estaban en el corpus (esdecir, no se las inventa).

Se debe observar que las reglas lexicales se rescriben en nociones (osímbolos) que pertenecen al lenguaje. Dichas nociones o símbolos sedenominan nociones terminales o símbolos terminales. Las nociones osímbolos que en este ejemplo se escribieron con mayúsculas, son utilizadaspara describir al lenguaje que se está estudiando, y reciben el nombre demetanociones o símbolos no terminales. Al lenguaje utilizado para describir unlenguaje se lo denomina metalenguaje.

Aplicando sucesivamente las diferentes reglas obtenidas, se puedeobtener lo que se llama una derivación. Si para una oración dada se puedeconstruir un árbol de derivación que contenga sólo símbolos terminales en sushojas, se dirá que la oración es sintácticamente correcta (o gramaticalmentecorrecta), sin importar si es interpretable o no.

Para mostrar más específicamente por qué se dice que la gramática esgenerativa, se partirá desde O, y se realizarán derivaciones sucesivas hastallegar a obtener símbolos terminales en las hojas del árbol de derivación. Unaposibilidad sería la siguiente:

Fig. 33 Ejemplo de generación de una oración.

La oración obtenida es gramaticalmente correcta, y no figura en elcorpus. Es en este sentido en que se considera a la gramática como generativa,porque a partir de un número finito de reglas se puede generar un número muy

O

S P

V OD

La niña toma la leche

MD N MD N

Introducción a las Gramáticas Generativas

291

Page 292: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

grandes (y a veces infinito) de oraciones. Por supuesto que si se hubieranelegido otras reglas léxicas se habría llegado a una oración como "El gatocome el alambrado", lo cual no tiene sentido. La solución a este problemapuede ser agregar más reglas que no permitan tal combinación. Igualmente, laconcordancia en género y número del núcleo con el modificador directo sepuede resolver agregando reglas que restrinjan el uso de ellos.

Obsérvese que las reglas "S ---> N MD" y "OD ---> N MD" tienenla misma secuencia de símbolos en la parte derecha de la flecha. Debido a quela gramática sólo explica la estructura y no el significado, esas dos reglas sepueden resumir en una sola, obteniéndose así una gramática mas pequeña.

Por último se puede decir que, si se tiene la descripción del lenguaje(corpus), es probable que se pueda encontrar una gramática generativa quedescriba la estructura del mismo. Lo de probable viene del hecho de que lateoría general no tiene un procedimiento para escribir las reglas de lagramática, por lo que el lingüista debe usar mucho su intuición.

La explicación del concepto de recursividad y del por qué es posiblegenerar infinitas oraciones con un número finito de reglas se da en el capítulo2 de este trabajo.

Introducción a las Gramáticas Generativas

292

Page 293: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 18: Un poco de Historia

18.1 Los descubrimientos y las investigaciones

Chomsky [1956] introdujo las gramáticas independientes del contextocomo parte de un estudio sobre lenguajes naturales. La utilización de este tipode gramáticas para la especificación de la sintaxis de los lenguajes deprogramación surgió independientemente. El lingüista Panini diseñó unanotación sintáctica equivalente para especificar las reglas de la gramática delsánscrito de entre el 400 a.C. y el 200 a.C. (Ingerman [1967]).

En una carta de Knuth [1964], está contenida la propuesta de que BNF,que comenzó como una abreviatura de Backus Normal Form (forma normal deBackus), se leyera Backus-Naur Form (forma de Backus-Naur), para reconocerlas contribuciones de Naur como editor del informe de ALGOL 60 (Naur[1963]).

Las definiciones dirigidas por la sintaxis son una forma de definicióninductiva, en la cual la inducción se encuentra en la estructura sintáctica.Como tales, han sido muy utilizadas en matemática. Su aplicación a loslenguajes de programación se introdujo con el uso de una gramática paraestructurar el informe de ALGOL 60. Poco tiempo después, Irons [1961]construyó un compilador dirigido por la sintaxis.

El análisis sintáctico descendente recursivo se utiliza aproximadamentedesde 1960. Bauer [1976] atribuye el método a Lucas [1961]. Hoare [1962,pág. 128] describe un compilador de ALGOL organizado como "un conjuntode procedimientos, cada uno de los cuales puede procesar una de las unidadessintácticas del informe de ALGOL 60". Foster [1968] analiza la eliminación dela recursividad por la izquierda de las producciones con acciones semánticasque no afecten a los valores de los atributos.

McKarthy [1963] abogaba por que la traducción de un lenguaje sebasara en una sintaxis abstracta. En el mismo artículo, McKarthy [1963, pág.24] dejaba "que el lector se convenciera por sí mismo" de que una formulaciónrecursiva por el final de la función factorial es equivalente a un programaiterativo.

Las ventajas de dividir un compilador en una etapa inicial y otra final seanalizaron en un informe del comité de Strong y colaboradores [1958]. Elinforme acuño el término UNCOL (del inglés universal computer oriented

Un poco de Historia

293

Page 294: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

language, lenguaje orientado a un computador universal) para un lenguajeintermedio universal. El concepto ha quedado como un ideal.

Kernighan y Pike [1984] describen en detalle cómo construir unprograma de calculadora de escritorio a partir de un esquema de traduccióndirigida por la sintaxis, utilizando las herramientas para la construcción decompiladores disponibles en el sistema operativo UNIX.

Las limitaciones impuestas a los aspectos léxicos de un lenguaje suelenestar determinadas por el ambiente en que se creó el lenguaje. Cuando sediseñó FORTRAN en 1954, las tarjetas perforadas eran un medio común deentrada. En FORTRAN se ignoraron los espacios en blanco debido en parte aque los perforistas, que preparaban las tarjetas a partir de notas escritas amano, tendían a equivocarse al contar los espacios en blanco (Backus [1981]).La separación en ALGOL 58 de la representación en hardware a partir dellenguaje de referencia fue un acuerdo alcanzado debido a que un miembro delcomité de diseño insistió: "No, nunca usaré un punto para el signo decimal".(Wegstein [1981]).

Knuth [1973] presenta otras técnicas para manejar la entrada conbuffers. Feldman [1979b] analiza las dificultades prácticas del reconocimientode componentes léxicos en FORTRAN 77.

Las expresiones regulares fueron estudiadas por primera vez por Kleene[1956], que estaba interesado en describir los acontecimientos que se podíanrepresentar con el modelo de autómata finito de actividad nerviosa deMcCulloch y Pitts [1943]. La minimización de los autómatas finitos fueestudiada por primera vez por Huffman [1954] y Moore [1956]. Laequivalencia entre autómatas determinísticos y no determinísticos en cuanto asu capacidad para reconocer lenguajes fue mostrada por Rabin y Scott [1959].McNaughton y Yamada [1960] describen un algoritmo para construir un AFDdirectamente a partir de una expresión regular, que es el que se implementa eneste trabajo.

Pronto se comprendió que las herramientas para construir analizadoreslexicográficos a partir de especificaciones en forma de expresiones regularesserían útiles en la implantación de compiladores. En Johnson y otros [1968] seanaliza uno de estos primeros sistemas. LEX, se debe a Lesk [1975], y se hautilizado para construir analizadores lexicográficos para muchos compiladoresque trabajan bajo UNIX.

Las expresiones regulares y los autómatas finitos se han utilizado paramuchas aplicaciones, además de para la compilación. Muchos editores de texto

Un poco de Historia

294

Page 295: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

usan expresiones regulares para búsquedas dentro del texto. El sistema UNIXtiene tres programas de búsqueda de propósito general basados en expresionesregulares: grep, egrep y fgrep. El programa grep no permite unión o paréntesispara agrupar en sus expresiones regulares, pero si una forma limitada dereferencia hacia atrás como en SNOBOL. Actualmente, grep se encuentra encasi todos los sistemas operativos de computadoras personales. También seutilizan las expresiones regulares en lenguajes de consultas de bases de datos yen lenguajes para procesamiento de archivos, como AWK (Aho, Kernighan yWeinberger [1979]). Jarvis [1976] utilizó expresiones regulares para describirrasgos distintivos en circuitos impresos.

El muy influyente informe de ALGOL 60 (Naur [1963]) utilizó la formade Backus Naur (BNF) para definir la sintaxis de un importante lenguaje deprogramación. Se descubrió la equivalencia entre BNF y las gramáticasindependientes del contexto, y la teoría de los lenguajes formales fue objeto deuna gran atención en la década de 1960.

Los métodos de análisis sintáctico se hicieron mucho más sistemáticostras el desarrollo de las gramáticas independientes del contexto. Se inventarondiversas técnicas generales para analizar cualquier gramática independiente delcontexto. Una de las primeras es la técnica de programación dinámicadescubierta independientemente por Younger [1967] y Kasami [1965]. Comotesis doctoral, Earley [1970] también desarrolló un algoritmo de análisissintáctico universal para todas las gramáticas independientes del contexto.

Se han empleado muchos métodos distintos de análisis sintáctico en loscompiladores. Los análisis sintácticos por descenso recursivo y predictivo sonmuy utilizados en la práctica. Dada su flexibilidad, se utilizó el análisissintáctico por descenso recursivo en muchos de los primeros generadores decompiladores como META (Schorre [1964]) y TMG (McClure [1965]). Pratt[1973] propone un método de análisis sintáctico descendente por precedenciade operadores.

Las gramáticas LL fueron estudiadas por Lewis y Stearns [1968] y suspropiedades se desarrollaron en Rosenkrantz y Stearns [1970]. Losanalizadores sintácticos predictivos fueron estudiados a fondo por Knuth[1971]. Lewis, Rosenkrantz y Stearns [1976] describen el uso de losanalizadores sintácticos predictivos en los compiladores. En Tamagnini [1994]se presenta un generador de tablas para el análisis sintáctico LL(1). Losalgoritmos para convertir gramáticas a la forma LL(1) se introducen en Foster[1968], Wood [1969], Stearns [1971] y Soisalon-Soininen y Ukkonen [1979].

Un poco de Historia

295

Page 296: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Las gramáticas y los analizadores sintácticos LR fueron introducidospor primera vez por Knuth [1965], quien describió la construcción de lastablas de análisis sintáctico LR canónico. El método LR no resultó prácticohasta que Korenjak [1969] mostró que con él se podrían producir analizadoressintácticos de tamaño razonable para gramáticas de los lenguajes deprogramación. Cuando DeRemer [1969, 1971] inventó los métodos SLR yLALR, que son más simples que el de Korenjak, la técnica LR se convirtió enel método elegido para los generadores automáticos de analizadoressintácticos. Hoy en día, los generadores de analizadores LR son habituales enlos entornos de construcción de compiladores.

La impresión de que el análisis sintáctico descendente permite unamayor flexibilidad en la traducción resultó ser falsa, ya que Brosgol [1974]demostró que un esquema de traducción basado en una gramática LL(1) sepuede simular durante el análisis sintáctico LR(1).

Gran parte de la investigación se dedicó a la construcción deanalizadores sintácticos LR. El uso de gramáticas ambiguas en el análisissintáctico LR se debe a Aho, Johnson y Ullman [1975] y a Earley [1975]. Laeliminación de las reducciones por reglas simples ha sido estudiada enAnderson, Eve y Horning [1973], Aho y Ullman [1973b], Demers [1975],Backhouse [1976], Joliat [1976], Pager [1977], Soisalon-Soininen [1980] yTokuda [1981].

Watt [1977] utilizó no terminales marcadores para garantizar que losvalores de los atributos heredados aparezcan en una pila durante el análisissintáctico ascendente. Las posiciones en los lados derechos de las reglas dondese pueden insertar los no terminales marcadores sin perder la propiedad LR(1)son estudiadas por Purdom y Brown [1980].

Aho y Johnson [1974] realizan un estudio general del análisis sintácticoLR y analizan algunos de los algoritmos en que se basa el generador deanalizadores sintácticos YACC, incluido el uso de producciones de error parala recuperación de errores. Aho y Ullman [1972 y 1973a] dan un tratamientobastante completo del análisis sintáctico LR y de sus fundamentos teóricos. Lacorrección de errores durante el análisis sintáctico es estudiada por Conway yMaxwell [1963], Moulton y Muller [1967], Conway y Wilcox [1973], Levy[1975], Tai [1978] y Röhrich [1980].

Un poco de Historia

296

Page 297: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

18.2 Historia del desarrollo de los Generadores Presentados en estetrabajo

18.2.1 SLR1 v 1 y su biblioteca de soporte

A fines de noviembre de 1992 comienza el desarrollo de SLR1 v 1. Elprimer prototipo funcionando se obtuvo el 15 Dic 92; el ejecutable se llamóSLR1 y, desde ese momento el generador recibió ese nombre. Para la carga dela gramática en memoria se utiliza un analizador lexicográfico hecho a mano, yun analizador sintáctico SLR hecho a mano.

La primera revisión de SLR1 v 1 fue en Set 93. La segunda revisióncomenzó en Dic 94 y terminó el 21 Dic 94; al finalizar esta revisión nace laversión 2 de SLR1. Esta versión incluye el uso de templates de C++ para lasestructuras de datos. La implementación del generador queda pendiente, sólose creó la biblioteca de soporte del mismo.

18.2.2 AFD v 1 y la biblioteca ExpReg v 1

La primera versión de AFD, el generador de autómatas finitosdeterminísticos a partir de expresiones regulares, fue comenzado a desarrollarel 09 Ene 95, su análisis comenzó en Dic 94, durante la segunda revisión deSLR1. La obtención del primer prototipo fue el 13 Ene 95, y recibe el nombrede AFD v 1, el ejecutable tenía el nombre AFD.EXE y corría bajo DOS. Paracargar la expresión regular en memoria se utilizó un analizador sintácticogenerado con SLR1 v 1. El analizador lexicográfico de esta versión devolvíasímbolos léxicos de longitud igual a 1. El 13 Ene 95 también nace la bibliotecaExpReg v 1, que hasta el momento de la escritura de este capítulo no cambió.

18.2.3 AFD v 2

Utilizando AFD v 1 y la biblioteca ExpReg v 1 se generaron autómataspara el analizador lexicográfico de las versiones siguientes de AFD. AFD v 2nace el 19 Ene 95, su analizador lexicográfico reconoce ahora símbolos delongitud mayor de un caracter, y se incluye la posibilidad de utilizarsecuencias de escape similares a las del C++, a excepción de \0 y \xDDD.

Un poco de Historia

297

Page 298: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

18.2.4 AFD v 3.1 y 3.2

AFD v 3.1 comienza a desarrollarse el 19 Ene 95 y finalizó el 24 Ene95. La gramática de AFD v 2 se cambió por una nueva, y se mejora elanalizador lexicográfico para que trabaje correctamente con la nuevagramática. Se cambiaron las precedencias de los operadores que puedenparticipar en una expresión regular.

AFD v 3.2 incluye la posibilidad de especificar archivos de entrada y desalida.

18.2.5 SLR1 v 2 y su biblioteca de soporte

SLR1 v 2 nace el 26 Ene 95. Se utilizan SLR1 v 1 y AFD v 3.2 paraconstruir los analizadores sintáctico y lexicográfico.

Los principales cambios fueron:

1. El analizador sintáctico es ahora un objeto construido a partir de lastablas generadas por SLR1 v 1 y, opcionalmente, se especifica lafunción de acciones semánticas y la función para ver el estado de la piladel analizador. El análisis sintáctico se realiza a través de la funciónAnalizar de la clase que implementa el analizador (queda todoencapsulado en esa clase). El analizador lexicográfico pasa a ser unparámetro en el llamado a la función Analizar.

2. El objeto analizador es una instancia de la clase AnalSLR1<XX> dondeAnalSLR1 es una clase template y XX es la clase que implementa elelemento de la pila del analizador. Por defecto, el elemento de la pilarecibe el nombre de ElemPila y su declaración se provee al usuario deSLR1 v 2.

3. Se agrega la posibilidad de la "limpieza" de la pila, para los casos en quelas clases que implementen su estructura sean complejas.

El segundo prototipo fue desarrollado con la versión 2 de lametagramática para la especificación de gramáticas, en donde se incluyenacciones semánticas. A partir de ese momento es posible especificardirectamente esquemas de traducción a SLR1 v 2. El analizador sintáctico delsegundo prototipo fue generado a partir del primer prototipo de esta mismaversión. El analizador lexicográfico fue generado por el primer prototipo deSLR1 v 2, mientras que las expresiones regulares y los AFDs no cambiaron.

Un poco de Historia

298

Page 299: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

18.3 Historia del capítulo 17

El documento que da una introducción a las gramáticas generativas,presentado en el capítulo 17 de este trabajo, fue escrito por primera vez enJunio de 1991, con la colaboración de la profesora Rosa Díaz de Lopez, paraservir de apoyo teórico a la cátedra Idioma I de la carrera de Ingeniería enComputación de la Universidad Católica de Santiago del Estero.

La primera revisión del documento fue realizada por el autor y por laprofesora al momento de terminar de escribirlo. La segunda revisión delmismo fue realizada en Junio de 1992. La tercera revisión en Junio de 1993. Yla última revisión en Febrero de 1996, durante su inclusión en este trabajo.

Un poco de Historia

299

Page 300: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 19: Códigos Fuentes de la Biblioteca de Soporte de SLR1v 2.x

La biblioteca de soporte de la versión 1.x está incluida en esta versión,por tal razón, su códifo fuente no es incluida y se incluye sólo los de la versión2.x.

Los módulos fuentes presentados en este capítulo son independientesdel sistema operativo y del compilador con el cual se trabaje. No ocurre lomismo con la implementación de SLR1 v 2.x.

A los efectos de no repetir código fuente dentro de este trabajo, cuandosea aplicable, se introducirán referencias hacia otras partes dentro de estedocumento, en donde era oportuno incluirlos.

19.1 GRAMLC.H

# ifndef __GRAMLC_H# define __GRAMLC_H

// GRAMLC.H: definición de las clases necesarias para tratar congramáticas// libres de contexto.// Creación: 20-10-93

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

class Archivo; // declarada en archabst.h (de la biblioteca de clasesBCE)class ArchivoSO; // declarada en archivo.h (de BCE)

# ifndef __ASCII0_H# include <ascii0.h># endif

# ifndef __FVARIAS_H# include <fvarias.h> // func Aceptar# endif

class Simbolo {protected: Ascii0 * Cad; Ent8 ReasignarCadena( const char * cad );public: Ent16ns Codigo : 15; // 15 bits para el código de símbolo (máx 23767símbolos) Ent8ns NoTerminal : 1; // 1 bit para decir si es no terminal o terminal

Simbolo() { Codigo = NoTerminal = 0; Cad = 0; } Simbolo( const Simbolo & s ); Simbolo( const char * Cadena, Ent16ns Codigo, Ent8ns NoTerminal ); Simbolo( const Ascii0 & cadena, Ent16ns codigo, Ent8ns noterminal );

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

300

Page 301: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

virtual ~Simbolo();

const Ascii0 & Cadena() const; static Ascii0 ErrorCadenaNula; // por si Cad == 0

Ent8 Reasignar( const char * Cadena, Ent16ns Codigo, Ent8ns NoTerminal); Ent8 Reasignar( const Ascii0 & Cadena, Ent16ns Codigo, Ent8ns NoTerminal);

Simbolo & operator = ( const Simbolo & s );

Ent8 operator == ( const char * cadena ) const; Ent8 operator == ( Ent16ns CodComp ) const; Ent16ns CodigoCompuesto() const;

enum { CAD, CAD_COD, CAD_TER, CAD_COD_TER }; static Ent8 Mostrar( Ent8 que = CAD ); // // por defecto se muestra solo la cadena del símbolo};

inline Simbolo::Simbolo( const Simbolo & s ) { Codigo = NoTerminal = 0; Cad = 0; operator = (s);}

inline Simbolo::Simbolo( const char * Cadena, Ent16ns Codigo, Ent8nsNoTerminal ) { Cad = 0; Reasignar(Cadena,Codigo,NoTerminal);}

inline Simbolo::Simbolo( const Ascii0 & cadena, Ent16ns codigo, Ent8nsnoterminal ) { Cad = 0; Reasignar(cadena,codigo,noterminal);}

inline Ent8 Simbolo::ReasignarCadena( const char * cadena ) { if (Cad != 0) { delete Cad; Cad = 0; } if (cadena == 0) return 1; // cadena fuente nula Cad = new Ascii0; if (Cad == 0) return 0; *Cad = cadena; Cad->Reasignar(); // hace que Cad tenga una copia de cadena en mem. din. return CodError == 0;}

inline Ent8 Simbolo::Reasignar( const char * cadena, Ent16ns cod, Ent8nsnoterm ) { Codigo = cod; NoTerminal = noterm; return ReasignarCadena(cadena);}

inline Ent8 Simbolo::Reasignar( const Ascii0 & cadena, Ent16ns cod, Ent8nsnoterm ) { Codigo = cod; NoTerminal = noterm; return ReasignarCadena(cadena);}

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

301

Page 302: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inline Simbolo & Simbolo::operator = ( const Simbolo & s ) { Reasignar(s.Cadena(), s.Codigo, s.NoTerminal); return *this;}

inline Ent16ns CodigoCompuesto( Ent16ns cod, Ent8ns noterminal ) { return noterminal ? 0x8000 | cod : cod;}

inline Ent16ns Simbolo::CodigoCompuesto() const { return ::CodigoCompuesto(Codigo, NoTerminal);}

inline const Ascii0 & Simbolo::Cadena() const { return Cad == 0 ? (ErrorCadenaNula.Vaciar(), ErrorCadenaNula) : *Cad;}

extern "C" int stricmp( const char *, const char *);

inline Ent8 Simbolo::operator == ( const char * cadena ) const { return Cad == 0 || ! Cad->Long() ? 0 : ! stricmp(cadena, *Cad);}

inline Ent8 Simbolo::operator == ( Ent16ns CodComp ) const { return CodComp == CodigoCompuesto();}

Archivo & operator << ( Archivo & a, const Simbolo & s );ArchivoSO & operator << ( ArchivoSO & a, const Simbolo & s );ArchivoSO & operator >> ( ArchivoSO & a, Simbolo & s );

// Clase ConjSimb: define la forma que debe tener un conjunto de// símbolos.

class ConjSimb { // Conjunto de Símbolos genéricopublic: ConjSimb() { } virtual ~ConjSimb() { }

virtual void Vaciar() = 0; // vacía al conjuto de símbolos // Si la implementación lo permite, las funciones Agregar deben // agregar el símbolo al final de todos los anteriores. virtual Ent8 Agregar( const char * cadena, Ent16ns codigo, Ent8nsnoterminal, Ent8 AceptRedundancia ) = 0; virtual Ent8 Agregar( const Simbolo & s, Ent8 AceptRedundancia ) = 0; virtual const Simbolo * Buscar( const char * Cadena ) const = 0; virtual const Simbolo * Buscar( Ent16ns CodigoCompSimb ) const = 0; virtual Ent16ns NumSimb() const = 0; // devuelve el número de símbolos Ent8 EsElemento( const char * Cadena ) const; Ent8 EsElemento( const Ascii0 & Cadena ) const; Ent8 EsElemento( Ent16ns CodigoCompSimb ) const; Ent8 EsElemento( const Simbolo & s ) const;};

inline Ent8 ConjSimb::EsElemento( const char * Cadena ) const { return Buscar(Cadena) != 0;}

inline Ent8 ConjSimb::EsElemento( const Ascii0 & Cadena ) const { return ConjSimb::EsElemento((const char *) Cadena);}

inline Ent8 ConjSimb::EsElemento( Ent16ns CodigoCompSimb ) const { return Buscar(CodigoCompSimb) != 0;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

302

Page 303: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

}

inline Ent8 ConjSimb::EsElemento( const Simbolo & s ) const { if (s.Cadena().Long()) return EsElemento(s.Cadena()) || EsElemento(s.CodigoCompuesto()); else return EsElemento(s.CodigoCompuesto());}

Ent8 CambAcepAmbig();

# ifndef __LSE_H# include "lse.h"# endif

// ConjSimbLSE: Conjunto de símbolos donde los símbolos se encuentran enuna// lista simple encadenada.

class ConjSimbLSE : public ConjSimb {protected: void Agregar( register NodoLSE<Simbolo> * p );public: LSE<Simbolo> lse; NodoLSE<Simbolo> * pUlt;

ConjSimbLSE() { pUlt = 0; } ConjSimbLSE( const ConjSimbLSE & cs ); virtual ~ConjSimbLSE() { }

virtual void Vaciar() { lse.Vaciar(); pUlt = 0; } // vacia el conjunto virtual Ent16ns NumSimb() const { return lse.NumElem(); }

virtual Ent8 Agregar( const char * cadena, Ent16ns codigo, Ent8nsnoterminal, Ent8 AceptRedundancia = 0 ); virtual Ent8 Agregar( const Simbolo & s, Ent8 AceptRedundancia = 0 ); Ent8 Agregar( Ent16ns codigo, Ent8ns noterminal, Ent8 AceptRedundancia =0 ); Ent8 AgregarSinCad( const Simbolo & s, Ent8 AceptRedundancia = 0 ); Ent16ns Agregar( const ConjSimbLSE & cs, Ent8 AceptRedundancia = 0 );

const Simbolo * Buscar( const char * Cadena ) const; const Simbolo * Buscar( const Ascii0 & Cadena ) const; const Simbolo * Buscar( Ent16ns CodigoCompSimb ) const;};

inline ConjSimbLSE::ConjSimbLSE( const ConjSimbLSE & cs ) { pUlt = 0; Agregar(cs);}

inline void ConjSimbLSE::Agregar( register NodoLSE<Simbolo> * p ) { if (lse.Entrada == 0) lse.Entrada = pUlt = p; else { pUlt->pSig = p; pUlt = p; }}

inline Ent8 ConjSimbLSE::Agregar( const Simbolo & s, Ent8 ar ) { register NodoLSE<Simbolo> * p; // Si no se acepta redundancia y el símbolo ya existe no se agrega// antes del 30Ene96:

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

303

Page 304: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// if ( ! ar && ( EsElemento(s.CodigoCompuesto()) ||// (const char *) s.Cadena() != 0 &&EsElemento(s.Cadena()) ) )// ahora: if ( ! ar && EsElemento(s) ) return 0; p = new NodoLSE<Simbolo>(s); if (p == 0) return 0; Agregar(p); return 1;}

inline Ent8 ConjSimbLSE::Agregar( const char * cadena, Ent16ns codigo, Ent8ns noterminal, Ent8 ar ) { register NodoLSE<Simbolo> * p; // Si no se acepta redundancia y el símbolo ya existe no se agrega if (! ar && (EsElemento(CodigoCompuesto(codigo, noterminal)) || cadena != 0 && EsElemento(cadena))) return 0; p = new NodoLSE<Simbolo>; if (p == 0) return 0; p->Dato.Reasignar(cadena, codigo, noterminal); Agregar(p); return 1;}

inline Ent8 ConjSimbLSE::Agregar( Ent16ns cod, Ent8ns noterm, Ent8 ar ) { return ConjSimbLSE::Agregar(0, cod, noterm, ar);}

inline Ent8 ConjSimbLSE::AgregarSinCad( const Simbolo & s, Ent8 ar ) { return ConjSimbLSE::Agregar(0, s.Codigo, s.NoTerminal, ar);}

inline const Simbolo * ConjSimbLSE::Buscar( const Ascii0 & Cadena ) const{ return ConjSimbLSE::Buscar((const char *) Cadena);}

Archivo & operator << ( Archivo & archivo, const ConjSimbLSE & conjunto );

class Alfabeto;

class ReglaLC : public ConjSimbLSE { // Regla de una gramática Libre deContextopublic: Ascii0 AccSem; // acciones semánticas

ReglaLC() { } ReglaLC( const ReglaLC & r ); virtual ~ReglaLC() { }

Ent8 Agregar( const char * cadena, Ent16ns codigo = 0, Ent8ns noterminal= 0, Ent8 AceptRedundancia = 1 );

Ent8 Agregar( const Simbolo & s, Ent8 AceptRedundancia = 1 ); Ent8 Agregar( const ConjSimbLSE & cs, Ent8 AceptRedundancia = 1 ); Ent8 Agregar( Ent16ns codigo, Ent8ns noterminal, Ent8 AceptRedundancia =1 ); Ent8 AgregarSinCad( const Simbolo & s, Ent8 AceptRedundancia = 1 );

Ent16ns LongParteDer() const; // longitud de la parte derecha de laregla const Simbolo * ParteIzq() const { return SimboloI(0); }

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

304

Page 305: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

const Simbolo * SimboloI( Ent16ns i ) const; void Vaciar() { ConjSimbLSE::Vaciar(); AccSem.Vaciar(); }};

inline ReglaLC::ReglaLC( const ReglaLC & r ) { Agregar(r); AccSem = r.AccSem;}

inline Ent8 ReglaLC::Agregar( const char * cad, Ent16ns cod, Ent8ns nt,Ent8 ar ) { return ConjSimbLSE::Agregar(cad,cod,nt,ar);}

inline Ent8 ReglaLC::Agregar( const Simbolo & s, Ent8 ar ) { return ConjSimbLSE::Agregar(s,ar);}

inline Ent8 ReglaLC::Agregar( const ConjSimbLSE & cs, Ent8 ar ) { return ConjSimbLSE::Agregar(cs,ar);}

inline Ent8 ReglaLC::Agregar( Ent16ns cod, Ent8ns noterm, Ent8 ar ) { return ConjSimbLSE::Agregar(cod, noterm, ar);}

inline Ent8 ReglaLC::AgregarSinCad( const Simbolo & s, Ent8 ar ) { return ConjSimbLSE::AgregarSinCad(s, ar);}

inline Ent16ns ReglaLC::LongParteDer() const { register Ent16ns c = ConjSimbLSE::NumSimb(); return c ? c-1 : 0;}

inline const Simbolo * ReglaLC::SimboloI( Ent16ns i ) const { register ReglaLC * este = (ReglaLC *) this; // this es const ReglaLC * return este->lse.DatoNodoI(i);}

Archivo & operator << ( Archivo & a, const ReglaLC & r );

class Alfabeto : public ConjSimbLSE {public: Alfabeto() { } Alfabeto( const Alfabeto & a ) : ConjSimbLSE(a) { } virtual ~Alfabeto() { }

// Todas las funciones de ConjSimbLSE se heredan públicamente // por lo que están disponibles para su uso.

};

class DescrTerminal {public: Ascii0 Cadena, NomArch; DescrTerminal() { } ~DescrTerminal() { }};

// Cadena: Ident que aparece en las directivas IGNORAR y TERMINAL. Si// Cadena no es hallado en el conj. de terminales, se usó IGNORAR.// NomArch: nombre del archivo donde está la expresión regular. Si// ! NomArch.Long() entonces el nombre es la Cadena del símbolo.

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

305

Page 306: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// DescrAccSem: clase que describe una acción semántica común a dos// o más reglas.

class DescrAccSem {public: Ascii0 Ident, TxtAccSem; DescrAccSem() { } ~DescrAccSem() { }};

// Ident: identificador usado en la directiva ACCSEM.// TxtAccSem: texto correspondiente al BlqCod especificado en ladirectiva.

class Gramatica {public: Alfabeto Term, NoTerm; LSE<ReglaLC> Reglas; Ascii0 BlqCodInic, ClaseElemPila; LSE<DescrAccSem> TablaAccSem; // Acciones semánticas comunes a dos o // más reglas. LSE<DescrTerminal> TablaTerminal; // si hay terminales descriptos por // expresiones regulares, aquí estánlos // nombres de archivo. Ent8 MayIgualMin; static Ent16ns CodError;

Gramatica() { MayIgualMin = 0; } Gramatica( Alfabeto & terminal, Alfabeto & no_terminal ); virtual ~Gramatica() { }

Ent8 Reasignar( const char * TxtGram, Ascii0 & CadPosErr ); // Reasignar carga gramática en formato texto de TxtGram. CadPosErrtiene // la posición del error si se produce alguno. En Gramatica::CodErrorestá // el código de error luego de reasignar. Evalúe con los códigos de la // clase AnalSLR1 declarada en slr1.h.

Ent8 AgregRegla( const ReglaLC & regla ); const Simbolo * SimbInic() const; Ent16ns NumNoTerm() const { return NoTerm.NumSimb(); } Ent16ns NumTerm() const { return Term.NumSimb(); }

Ent16ns ArmarAlfabetos(); // ArmarAlfabetos construye Term y NoTerm a partir de Reglas. Asigna // códigos a los símbolos que aparecen en Reglas de acuerdo al orden de // aparición en las mismas.

Ent8 AnulableSimple( Ent16ns CodCompSimbNoTerminal ) const; Ent8 Anulable( Ent8 * pvBandAnulable ) const;

Ent16ns CalcPrimeroSinLambda( Alfabeto * pvaPrim, Ent8 * pvAnulable = 0) const; // CalcPrimeroSinLambda calcula Primero() para todos los símbolos no // terminales de la gramática, pero sin agregar lambda a ninguno de los // conjuntos. pvaPrim es un puntero a un vector de alfabetos cuyo tamaño // es el número de símbolos no terminales de la gramática actual, cada // elemento del vector contiene Primero() de cada símbolorespectivamente, // por orden de aparición de los símbolos en NoTerm.

Ent16ns CalcSiguiente( Alfabeto * pvaSig, Alfabeto * pvaPrim = 0,

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

306

Page 307: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent8 * pvAnulable = 0 ) const; // CalcSiguiente() calcula Siguiente() para todos los no terminales dela // gramática. pvaSig y pvaPrim apuntan cada uno a un vector de Alfabetos // cuyo tamaño es el número de simb. no terminales de la gramáticaactual // (NumNoTerm()). En pvaSig se guardan los conjuntos siguientes y en // pvaPrim, si no es nulo, se guardan los conjuntos primero.

Ent8 ImprAccSem( Archivo & arch, const char * sufijo = 0 ) const; // Imprime en formato C++ las acciones semánticas especificadas paraesta // gramática.

Ent8 ImprAnaLex( Archivo & arch, const char * sufijo = 0 ) const; // Imprime un analizador lexicográfico en formato C++ para la gramática, // implementado con un objeto de la clase AnaLex (de expreg.h).

Ent16 ImprAnulPrimSig( Archivo & arch );

void Vaciar();};

inline Ent8 Gramatica::AgregRegla( const ReglaLC & regla ) { return Reglas.AgregFinal(regla);}

inline const Simbolo * Gramatica::SimbInic() const { return Reglas.NumElem() ? Reglas.Entrada->Dato.ParteIzq() : 0;}

inline void Gramatica::Vaciar() { Term.Vaciar(); NoTerm.Vaciar(); Reglas.Vaciar(); BlqCodInic.Vaciar(); TablaAccSem.Vaciar(); TablaTerminal.Vaciar(); MayIgualMin = 0;}

// SimbFA es el nombre lógico del símbolo que representa al fin de archivoextern Simbolo SimbFA; // ("FA", 0, 0) tiene código 0 y es terminal

Archivo & operator << ( Archivo & arch, const Gramatica & gram );//ArchivoSO & operator << ( ArchivoSO & arch, const Gramatica & gram );//ArchivoSO & operator >> ( ArchivoSO & arch, Gramatica & gram );

# endif // # ifndef __GRAMLC_H

19.2 SLR1.H

El código fuente de este módulo se presenta en la sección 12.14.1.

19.3 GENSLR.H

# ifndef __GENSLR_H# define __GENSLR_H

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

307

Page 308: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// genslr.h: clases para el programa generador de tablas de análisis// sintáctico SLR(1).

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# ifndef __GRAMLC_H# include "gramlc.h"# endif

class Archivo; // declarada en archabst.h ( de la biblioteca de clasesBCE)

class ElemCanonLR0 { // elemento del análisis sintáctico LR(0)public: const NodoLSE<ReglaLC> * pr; // puntero a la regla const NodoLSE<Simbolo> * punto; // punto en la parte derecha de la regla

ElemCanonLR0() { pr = 0; punto = 0; } ElemCanonLR0( const NodoLSE<ReglaLC> * Pr, const NodoLSE<Simbolo> * ps); Ent8 operator == ( const ElemCanonLR0 & oe ) const; friend Archivo & operator << ( Archivo & a, const ElemCanonLR0 & eclr0);};

inline ElemCanonLR0::ElemCanonLR0( const NodoLSE<ReglaLC> * Pr, const NodoLSE<Simbolo> * ps ) {

pr = Pr; punto = ps;}

inline Ent8 ElemCanonLR0::operator == ( const ElemCanonLR0 & oe ) const { return pr == oe.pr && punto == oe.punto;}

Archivo & operator << ( Archivo & a, const ElemCanonLR0 & eclr0 );

class ConjElem { // Conjunto de elementos LR(0)public: LSE<ElemCanonLR0> lse; // conjunto de elementos Ent16ns numelem;

ConjElem() { numelem = 0; } ~ConjElem() { lse.Vaciar(); numelem = 0; }

Ent8 Agregar( const NodoLSE<ReglaLC> * Pr, const NodoLSE<Simbolo> * ps); Ent16ns AgregCerradura( const Gramatica & g ); void Vaciar() { lse.Vaciar(); numelem = 0; } friend Archivo & operator << ( Archivo & a, const ConjElem & ce ); Ent8 operator == ( const ConjElem & ce ) const;};

Archivo & operator << ( Archivo & a, const ConjElem & ce );

class Estado { // un estado es un conjunto de elementos LR(0)public: ConjElem * pce; // conjunto de elementos LR(0) (estado) Ent16ns n; // número de estado (o de conj. de elementos)

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

308

Page 309: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent16ns * ves; // vector de estados siguientes

Estado() { pce = 0; n = 0; ves = 0; } Estado( ConjElem * Pce, Ent16ns N ) { pce = Pce; n = N; ves = 0; }};

class ConjEst { // conjunto de estadospublic: LSE<Estado> lse; // Conjunto de estados Ent16ns numest; // número de estados

ConjEst() { numest = 0; } ~ConjEst() { Vaciar(); }

Ent8 Armar( Gramatica & g, Ent8 (* FuncError) ( Ent16ns estado, Ent16ns val_previo, Ent16ns num_regla, const Simbolo & s )= 0 ); void Vaciar() { lse.Vaciar(); numest = 0; } Ent8 ImprTabla( Archivo & a, const Gramatica & g ) const; Ent8 ImprTabla( const char * NomArch, const Gramatica & g ) const; Ent8 ImprTablaC( const char * NomArch, const Gramatica & g, const char * sufijo = 0 ) const; friend Archivo & operator << ( Archivo & a, const ConjEst & ce );};

# endif // # ifndef __GENSLR_H

19.4 SIMB01.CMM

// simb01.cmm Miércoles 20 de Octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include "archabst.h"

static Ent8 b = Simbolo::CAD;

Ent8 Simbolo::Mostrar( Ent8 que ) { if (que > CAD_COD_TER) return 0; b = que; return 1;}

Archivo & operator << ( Archivo & a, const Simbolo & s ) { if (b != Simbolo::CAD) a << "("; a << (const char *) s.Cadena(); if (b == Simbolo::CAD_COD || b == Simbolo::CAD_COD_TER) a << ", " << s.Codigo; if (b == Simbolo::CAD_TER || b == Simbolo::CAD_COD_TER) a << ", " << (s.NoTerminal ? 'N' : 'T'); if (b != Simbolo::CAD) a << ")"; return a;}

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

309

Page 310: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

19.5 SIMB02.CMM

// simb02.cmm viernes 22 de octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Simbolo SimbFA("FA",0,0);

19.6 SIMB03.CMM

// simb03.cmm Domingo 11 de diciembre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include "archivo.h"

ArchivoSO & operator << ( ArchivoSO & a, const Simbolo & s ) { register Ent8 bin = a.TxtBin();

if (bin) { a << s.Cadena(); a << s.Codigo; a << s.NoTerminal; } else (Archivo &) a << s;

return a;}

ArchivoSO & operator >> ( ArchivoSO & a, Simbolo & s ) { register Ent8 bin = a.TxtBin(); Ascii0 cad; Ent16ns cod; Ent8ns noterm;

if (bin) { a >> cad; a >> cod; a >> noterm; s.Reasignar(cad, cod, noterm); } return a;}

19.7 SIMB04.CMM

// simb04.cmm

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Simbolo::~Simbolo() {

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

310

Page 311: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ReasignarCadena(0);}

Ascii0 Simbolo::ErrorCadenaNula;

19.8 CSLSE01.CMM

// cslse01.cmm Viernes 22 de Octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

const Simbolo * ConjSimbLSE::Buscar( const char * Cadena ) const { IterLSE<Simbolo> c;// register const Ascii0 * pa;

for (c = lse; c != 0; ++c) {// pa = & c.Cursor->Dato.Cadena(); if (c.Cursor->Dato == Cadena) break; }

return c != 0 ? & c.Cursor->Dato : 0;}

19.9 CSLSE02.CMM

// cslse02.cmm Viernes 22 de Octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

const Simbolo * ConjSimbLSE::Buscar( Ent16ns CodComp ) const { IterLSE<Simbolo> c;

for (c = lse; c != 0; ++c) if (c.Cursor->Dato == CodComp) break;

return c != 0 ? & c.Cursor->Dato : 0;}

19.10 CSLSE03.CMM

// cslse03.cmm Miércoles 20 de Octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include "archabst.h"

Archivo & operator << ( Archivo & a, const ConjSimbLSE & cs ) { IterLSE<Simbolo> c = cs.lse; register Ent8 coma = 0; register Simbolo * ps;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

311

Page 312: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Ent16ns n; a << "{ "; n = 0; while (c != 0) { if (coma) a << ", "; else coma = 1; a << c.Cursor->Dato; ++c; if (++n == 5) { a << "\n "; n = 0; } }

return a << " }";}

19.11 CSLSE04.CMM

// cslse04.cmm Viernes 22 de octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Ent16ns ConjSimbLSE::Agregar( const ConjSimbLSE & cs, Ent8 ar ) { if (! ar && this == & cs) return 0; IterLSE<Simbolo> c; register Ent16ns i; for (c = cs.lse, i = 0; c != 0; ++c) if (Agregar(c.Cursor->Dato, ar)) ++i;

return i;}

19.12 RLC01.CMM

// rlc01.cmm Vie 27 Ene 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include <archivo.h>

Archivo & operator << ( Archivo & a, const ReglaLC & r ) { register const NodoLSE<Simbolo> * pns; Ent8 b;

if ( (pns = r.lse.Entrada) != 0 ) { b = Simbolo::Mostrar(); a << pns->Dato << " ---> "; while (pns->pSig != 0) { pns = pns->pSig; a << pns->Dato << " "; } Simbolo::Mostrar(b); }

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

312

Page 313: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

return a;}

19.13 GRAM01.CMM

// gram01.cmm Viernes 20 de octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Ent16ns Gramatica::ArmarAlfabetos() { register Ent16ns cod; register const Simbolo * pSimbEnAlf; register NodoLSE<ReglaLC> * pRegla; NodoLSE<Simbolo> * pnSimbEnRegla; register Simbolo * pSimbEnRegla; Ent16ns cant_simb;

// Armar alfabeto no terminal asignando los códigos en el mismo. // A los símbolos de la izq. de la regla también se le asignan loscódigos. pRegla = Reglas.Entrada; cod = 1; while (pRegla != 0) { pSimbEnRegla = & pRegla->Dato.lse.Entrada->Dato; if ( (pSimbEnAlf= NoTerm.Buscar(pSimbEnRegla->Cadena())) == 0) { // El símbolo no existe en el alfabeto de símbolos no terminales. // En el símbolo que reside en la regla se asigna el código pSimbEnRegla->Codigo = cod++; pSimbEnRegla->NoTerminal = 1; // no terminal // Se agrega al alfabeto NoTerm.Agregar(*pSimbEnRegla); } else { // El símbolo está en el alfabeto no terminal, // asignar código ya asignado al símbolo de la regla pSimbEnRegla->Codigo = pSimbEnAlf->Codigo; pSimbEnRegla->NoTerminal = 1; // no terminal (no hay dudas) } pRegla = pRegla->pSig; // Avanzar al sig. elemento de la lista. }

cant_simb = cod - 1;

// Luego armar alfabeto terminal y asignar los códigos. // Si algún símbolo de la parte derecha de las reglas existe en algún // alfabeto entonces se copia el código asignado. pRegla = Reglas.Entrada; cod = 1; // el 0 se reserva para "fin de archivo" while (pRegla != 0) { // Para todas las reglas ya se ejecutó la función Primero() pnSimbEnRegla = pRegla->Dato.lse.Entrada->pSig; while ( pnSimbEnRegla != 0 ) { pSimbEnRegla = & pnSimbEnRegla->Dato; if ( (pSimbEnAlf = NoTerm.Buscar(pSimbEnRegla->Cadena())) == 0 && (pSimbEnAlf = Term.Buscar(pSimbEnRegla->Cadena())) == 0 ) { // No está en ninguno de los alfabetos // En el símbolo que reside en la regla se asigna el código pSimbEnRegla->Codigo = cod++; pSimbEnRegla->NoTerminal = 0; // Se agrega al alfabeto Term.Agregar(*pSimbEnRegla);

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

313

Page 314: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} else { // El símbolo ya está en alguno de los alfabetos y // pSimbEnAlf apunta a él pSimbEnRegla->Codigo = pSimbEnAlf->Codigo; pSimbEnRegla->NoTerminal = pSimbEnAlf->NoTerminal; } pnSimbEnRegla = pnSimbEnRegla->pSig; } pRegla = pRegla->pSig; }

return cant_simb + cod - 1;}

19.14 GRAM02.CMM

// gram02.cmm Viernes 22 de octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Ent8 Gramatica::AnulableSimple( Ent16ns CodSimb ) const { if (! Reglas.NumElem() || ! (CodSimb & 0x8000)) return 0; IterLSE<ReglaLC> i; register const NodoLSE<Simbolo> * pr; CodSimb &= 0x7fff; for (i = Reglas; i != 0; ++i) { pr = i.Cursor->Dato.lse.Entrada; if (pr->Dato.Codigo == CodSimb && pr->pSig == 0) break; }

return i != 0; // si encuentra una regla 'CodSimb --> ' CodSimb esanulable}

Ent8 Gramatica::Anulable( Ent8 * vAnul ) const { if (! Reglas.NumElem() || vAnul == 0) return 0; Ent8 iterar; Ent16ns i, CodNTAct; NodoLSE<ReglaLC> * pr; NodoLSE<Simbolo> * ps; for (ps = NoTerm.lse.Entrada; ps != 0; ps = ps->pSig) { i = ps->Dato.Codigo - 1; vAnul[i] = AnulableSimple( ps->Dato.CodigoCompuesto() ); }

do { // el proceso es iterativo hasta que no se cambia ninguna bandera iterar = 0; for (pr = Reglas.Entrada; pr != 0; pr = pr->pSig) { CodNTAct = pr->Dato.lse.Entrada->Dato.Codigo; for (ps = pr->Dato.lse.Entrada->pSig; ps != 0; ps = ps->pSig) if (! ps->Dato.NoTerminal || ! vAnul[ ps->Dato.Codigo - 1]) break; // salir si alguno de la derecha no es anulable

if (ps == 0) { // todos son no terminales y anulables if (! vAnul[CodNTAct - 1]) { vAnul[CodNTAct - 1] = 1; if (! iterar) iterar = 1; // se cambió al menos un elemento } // de vAnul } }

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

314

Page 315: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} while (iterar);

return 1;}

Ent16ns Gramatica::CalcPrimeroSinLambda( Alfabeto * prim, Ent8 * vanul )const { // prim debe ser un vector de NoTerm.NumElem() elementos. if (! Reglas.NumElem() || prim == 0) return 0;

Ent8 * Anul; Anul = vanul != 0 ? vanul : new Ent8[ NumNoTerm() ]; if (Anul == 0) return 0; if (vanul == 0) Anulable(Anul);

IterLSE<Simbolo> isa, isr; // isa: iterador de símbolos en alfabeto // isr: iterador de símbolos en regla IterLSE<ReglaLC> ir; // iterador de reglas (para el conjunto de reglas) const register Simbolo * psa, * psr; // psa: puntero a un símbolo enalfabeto // psr: puntero a un símbolo enregla Ent8 agreg, iterar = 1; Ent16ns i, numpas = 0; // agreg: == 0 si agregó algún símbolo, != 0 si no agregó // iterar: == 0 si se debe salir. // numpas: contabiliza el número de pasadas (el cálculo de PRIMERO() es // iterativo).

while (iterar) { // se itera si se agrega algún símbolo, // se para cuando en una iteración no se agregó ninguno iterar = 0; for (isa = NoTerm.lse, i = 0; isa != 0; ++isa, ++i) { // para cadasímbolo // no terminal de la gramática psa = & isa.Cursor->Dato; for (ir = Reglas; ir != 0; ++ir) { // para cada regla del conj dereglas

// si la regla es 'A --> Y' con A símbolo actual y Y' distinto alambda if (ir.Cursor->Dato.ParteIzq()->Codigo == psa->Codigo && (isr = ir.Cursor->Dato.lse, ++isr) != 0) { // isr apunta al primer símbolo de la parte derecha de la regla

if (isr.Cursor->Dato.NoTerminal) { // Símbolo no terminal Ent8 cont = 1; // cont: continuar while (cont) { psr = & isr.Cursor->Dato; // para A --> B C agrega Primero(B) a Primero(A) (B es noterminal) agreg = prim[i].Agregar( prim[psr->Codigo - 1] ); if (! iterar) iterar = agreg; // si se agregó se vuelve aiterar

// Si el símbolo actual de la derecha (B en el ejemplo) esanulable se // avanza al siguiente (C en el ejemplo) para agregar // Primero(símbolo siguiente) a Primero(símbolo actual) // ( Primero(C) en el ejemplo ) y se continua iterando if ( Anul[ psr->Codigo - 1 ] ) { if (++isr == 0) cont = 0; else if (! isr.Cursor->Dato.NoTerminal) { agreg = prim[i].AgregarSinCad(isr.Cursor->Dato); if (! iterar) iterar = agreg; cont = 0; // símbolo terminal, fin del while (cont)

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

315

Page 316: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} } else cont = 0; // símbolo no anulable, fin del while (cont) } // while (cont) } else { // Es un símbolo terminal if (! numpas) { // si es la primera pasada agreg = prim[i].AgregarSinCad(isr.Cursor->Dato); if (! iterar) iterar = agreg; } } } } // segundo for } // primer for ++numpas; }

if (vanul == 0) delete [] Anul;

return numpas;}

19.15 GRAM03.CMM

// gram03.cmm viernes 22 de octubre de 1993

// Copyright (c) 1993 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"

Ent16ns Gramatica::CalcSiguiente( Alfabeto * sig, Alfabeto * primero, Ent8 * vanul ) const { if (! Reglas.NumElem() || sig == 0) return 0;

Ent16ns nt; if ( ! (nt = NoTerm.NumSimb()) ) return 0; // ¿ siguiente de quién ?

// Primero se calcula el vector de banderas Anul (anulable) Ent8 * Anul; Anul = vanul != 0 ? vanul : new Ent8[nt]; if (Anul == 0) return 0; if (vanul == 0) Anulable(Anul); // calcular sólo si no viene dado

// Luego se calculan los conjuntos primero Alfabeto * prim = primero != 0 ? primero : new Alfabeto[nt]; if (prim == 0) { if (vanul == 0) delete [] Anul; return 0; // falta memoria } if (! CalcPrimeroSinLambda(prim, Anul)) { if (primero == 0) delete [] prim; if (vanul == 0) delete [] Anul; return 0; }

IterLSE<ReglaLC> ir;

ReglaLC * pr; Ent8 iterar = 1, agreg; Ent16ns numpas = 0;

while (iterar) {

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

316

Page 317: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

iterar = 0; // se agrega FA a Siguiente(O) donde O es el símbolo inicial if (! numpas) iterar = sig[0].Agregar(SimbFA);

for (ir = Reglas; ir != 0; ++ir) {

// En adelante, el código es dependiente de las estructuras de datos // que se usan.

if ( ir.Cursor->Dato.SimboloI(1) != 0 ) { // si la regla no deriva en lambda ('A -> ') register NodoLSE<Simbolo> * ps1, * ps2; ps1 = ir.Cursor->Dato.lse.Entrada->pSig; while (ps1 != 0) { if (ps1->Dato.NoTerminal) { // si A --> B Y con B no terminal if (ps1->pSig == 0) { // si Y de la regla de arriba era lambda Ent16ns cod = ir.Cursor->Dato.lse.Entrada->Dato.Codigo; //del // símbolo de la izquierda de la regla if (cod) { agreg = sig[ps1->Dato.Codigo - 1].Agregar( sig[cod - 1] ); if (! iterar) iterar = agreg; } } else { ps2 = ps1->pSig; // Se agrega Primero de los no terminales que siguen hastaque // haya un símbolo terminal o un no terminal no anulable. while (ps2 != 0) { if (ps2->Dato.NoTerminal) { agreg = sig[ps1->Dato.Codigo - 1].Agregar(prim[ps2->Dato.Codigo - 1] ); if (! iterar) iterar = agreg; if ( Anul[ps2->Dato.Codigo - 1] ) { ps2 = ps2->pSig; if (ps2 == 0) { // todos los de la derecha sonanulables // Agregar siguiente del de la izquierda de la reglaactual agreg = sig[ps1->Dato.Codigo - 1].Agregar( sig[ir.Cursor->Dato.lse.Entrada->Dato.Codigo - 1]); if (! iterar) iterar = agreg; } } else ps2 = 0; // para salir del while } else { // es terminal if (! numpas) { // si estamos en la primera pasada agreg = sig[ps1->Dato.Codigo - 1].AgregarSinCad(ps2->Dato ); if (! iterar) iterar = agreg; } ps2 = 0; // se llegó a un terminal, salir del while } } // while } // else } // if (ps1->Dato.NoTerminal) ps1 = ps1->pSig; // avanzar al siguiente símbolo de la regla } // while } // if la regla no deriva en lambda

// Fin del código dependiente de las estr. de datos que se usan.

} // for

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

317

Page 318: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

++numpas; } // while (iterar)

if (primero == 0) delete[] prim; if (vanul == 0) delete [] Anul;

return numpas;}

19.16 GRAM04.CMM

// gram04.cmm Lun 30 Ene 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "gram.cmm" // generado por SLR1 v 2, son las acciones semánticas

Ent16ns Gramatica::CodError;

Ent8 Gramatica::Reasignar( const char * TxtGram, Ascii0 & CadPosErr ) { if (TxtGram == 0 || ! *TxtGram) return 0; Vaciar(); InicVarGlob(); pGram = this; ClaseElemPila = "ElemPila";// AnalSLR1<ElemPila> analizador(ntlpdGram, accionGram, ir_aGram,AccSemGram); alGram.Reiniciar(TxtGram); if (! asGram.Analizar(alGram, CadPosErr)) { CodError = asGram.CodError; return 0; } InicVarGlob(); return 1;}

19.17 GRAM05.CMM

// gram05.cmm Vie 27 Ene 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include <archivo.h>

Archivo & operator << ( Archivo & arch, const Gramatica & gram ) { if (! gram.NumNoTerm()) return arch;

arch << "NoTerm = " << gram.NoTerm << "\nTerm = " << gram.Term << "\nGramática:\n";

IterLSE<ReglaLC> i; for (i = gram.Reglas; i != 0; ++i) arch << i.Cursor->Dato << "\n";

return arch;}

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

318

Page 319: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

19.18 GRAM06.CMM

// gram06.cmm Lun 30 Ene 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "gramlc.h"# include <archivo.h># include <string.h>

void ImprBlqAccSem( Archivo & arch, const char * pblqcod ) { register const char * p;

if ((p = pblqcod) == 0) return; ++p; while (*p && *p != '%') { if (*p == '$') { arch << "Pila[PP+"; ++p; if (*p == '$') { arch << "1"; ++p; } else while ( Aceptar(*p, "0-9") ) arch << *p++; arch << "]"; } else arch << *p++; } arch << " break;\n";}

Ent8 Gramatica::ImprAccSem( Archivo & arch, const char * sufijo ) const { int est; est = arch.Estado(); if (est != MA_E && est != MA_L_E || ! Reglas.NumElem() ) return 0;

arch << "\n// Código de acciones semánticas.\n" "// Código generado por Gramatica::ImprAccSem versión 2.\n" "// Domingo Eduardo Becker.\n\n";

// La siguiente línea es necesario para compilar arch << "# ifndef __SLR1_H\n# include \"slr1.h\"\n# endif\n\n";

if (sufijo == 0) sufijo = "";

// Impresión del código previo a las acciones semánticas unsigned n; if ((n = BlqCodInic.Long()) != 0) { char * p; p = (char *) (const char *) BlqCodInic; p += n - 2; *p = *(p+1) = ' '; p = (char *) (const char *) BlqCodInic; p += 2; // saltea los primeros %{ arch << "\n// Código fuente previo a las acciones semánticas.\n" << p << "\n// Fin del código fuente previo a las accionessemánticas.\n\n"; }

// Impresión de las acciones semánticas. arch << "void AccSem" << sufijo << "( Ent16ns NumRegla, "

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

319

Page 320: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

<< (const char *) ClaseElemPila << " * Pila, Ent16ns PP ) {\n switch (NumRegla) { ";

IterLSE<ReglaLC> ir; IterLSE<DescrAccSem> ias; register const char * pas, * pident; register Ent16ns numregla; Ent8 imprimir; Ascii0 cad;

// Primero las acciones semánticas no repetidas for (ir = Reglas, numregla = 1; ir != 0; ++ir, ++numregla) { pas = ir.Cursor->Dato.AccSem; if (pas == 0 || *pas != '%') continue; cad = numregla; arch << "\n case " << (char *) cad << ": // " << ir.Cursor->Dato << "\n "; ImprBlqAccSem(arch, pas); }

// Luego las acciones semánticas comunes a una o más reglas: for (ias = TablaAccSem; ias != 0; ++ias) { imprimir = 0; pident = ias.Cursor->Dato.Ident; for (ir = Reglas, numregla = 1; ir != 0; ++ir, ++numregla) { pas = ir.Cursor->Dato.AccSem; if (pas == 0 || *pas == '%') continue; if (! strcmp(pas, pident)) { imprimir = 1; cad = numregla; arch << "\n case " << (char *) cad << ": // " <<ir.Cursor->Dato; } } if (imprimir) { arch << "\n "; ImprBlqAccSem(arch, ias.Cursor->Dato.TxtAccSem); } else arch << "// Acción semántica referenciada por " << pident << " ignorada.\n"; }

arch << " } // switch (NumRegla)\n} // Fin de AccSem" << sufijo << "\n\n// Fin del código de acciones semánticas.\n";

return 1;}

Ent8 Gramatica::ImprAnaLex( Archivo & arch, const char * sufijo ) const { int est; est = arch.Estado(); if (est != MA_E && est != MA_L_E || ! Term.NumSimb()) return 0;

arch << "// Analizador lexicográfico para la gramática.\n" "// Generado por Gramatica::ImprAnaLex versión 3.\n" "// Domingo Eduardo Becker.\n\n";

// La siguiente línea es necesario para compilar arch << "# ifndef __EXPREG_H\n# include \"expreg.h\"\n# endif\n";

if (sufijo == 0) sufijo = "";

IterLSE<DescrTerminal> it; IterLSE<Simbolo> is; register const Simbolo * ps;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

320

Page 321: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

register const char * nomarch; register char * cad; char aux, primero; Ent16ns numrs; Ascii0 NumCad;

// Primero imprimir los includes

for (it = TablaTerminal; it != 0; ++it) { nomarch = it.Cursor->Dato.NomArch.Long() ? it.Cursor->Dato.NomArch : it.Cursor->Dato.Cadena; arch << "\n# include \"" << NomExt(nomarch, ".cmm") << "\" // afd" << (const char *) it.Cursor->Dato.Cadena; }

// Después imprimir el vector de reconocedores de símbolos: arch << "\n\nstatic RecSimb vrs[] = {";

numrs = 0; for (is = Term.lse, primero = 1; is != 0; ++is) { if (primero) { arch << "\n "; primero = 0; } else arch << ",\n ";

NumCad = is.Cursor->Dato.Codigo; arch << (char *) NumCad << ", ";

cad = (char *) (const char *) is.Cursor->Dato.Cadena(); if (*cad == '\'' || *cad == '\"') { // es una cadena (literal) aux = *cad; *cad = *(cad + strlen(cad) - 1) = '\"'; arch << "0, 0, " << cad; *cad = *(cad + strlen(cad) - 1) = aux; } else { for (it = TablaTerminal; it != 0; ++it) if (! strcmp(it.Cursor->Dato.Cadena, cad)) break; // terminal encontrado.

if (it != 0) // terminal descripto por una expresión regular. arch << "1, & afd" << cad << ", 0"; else arch << "0, 0, \"" << cad << "\" /* Debe armar un descriptor" " adecuado para este terminal. */"; } ++numrs; }

// A continuación se imprimen los reconocedores para los símbolos // que serán ignorados por el analizador lexicográfico:

for (it = TablaTerminal; it != 0; ++it) { ps = Term.Buscar( cad = (char *) (const char *) it.Cursor->Dato.Cadena); if (ps != 0) continue;

if (primero) { arch << "\n "; primero = 0; } else arch << ",\n "; arch << "0, 1, & afd" << cad << ", 0"; ++numrs;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

321

Page 322: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

}

NumCad = numrs; arch << "\n};\n\n# define NUMRECSIMB " << (char *) NumCad << "\n\nAnaLex al" << sufijo << "(vrs, NUMRECSIMB"; if (MayIgualMin) arch << ", 1"; arch << ");\n";

return 1;}

19.19 GRAM07.CMM

// gram07.cmm Vie 02 Feb 96

// Copyright (c) 1996 by Domingo Eduardo Becker.// All rights reserved.

# include <vector.h># include <archivo.h># include "gramlc.h"

Ent16 Gramatica::ImprAnulPrimSig( Archivo & arch ) { Ent16ns nNoTerm = NumNoTerm();

Vector<Alfabeto> Prim(nNoTerm), Sig(nNoTerm); Vector<Ent8> Anul(nNoTerm);

if (! Sig.Tam || ! Prim.Tam || ! Anul.Tam) return CodError = E_NOHAYMEMORIA;

Anulable(Anul); CalcSiguiente(Sig, Prim, Anul);

Ent8 b = Simbolo::Mostrar(Simbolo::CAD);

// Impresión de Anulable IterLSE<Simbolo> nt; Ent16ns i; for (nt = NoTerm.lse, i = 0; nt != 0; ++nt, ++i) arch << "Anulable(" << nt.Cursor->Dato << "): " << (Anul[i] ? "Si" : "No") << "\n";

// Impresión de Primero IterLSE<Simbolo> e; const Simbolo * ps; for (nt = NoTerm.lse, i = 0; nt != 0; ++nt, ++i) { arch << "Primero(" << nt.Cursor->Dato << ") = {"; for (e = Prim[i].lse; e != 0; ++e) { ps = Term.Buscar(e.Cursor->Dato.CodigoCompuesto()); if (ps != 0) arch << " " << *ps; } arch << " }\n"; }

// Impresión de Siguiente: for (nt = NoTerm.lse, i = 0; nt != 0; ++nt, ++i) { arch << "Siguiente(" << nt.Cursor->Dato << ") = {"; for (e = Sig[i].lse; e != 0; ++e) { ps = Term.Buscar(e.Cursor->Dato.CodigoCompuesto()); if (ps != 0)

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

322

Page 323: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

arch << " " << *ps; } arch << " }\n"; }

Simbolo::Mostrar(b); return CodError;}

19.20 CELEM01.CMM

// celem01.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"

Ent8 ConjElem::Agregar( const NodoLSE<ReglaLC> * Pr, const NodoLSE<Simbolo> * ps ) { register NodoLSE<ElemCanonLR0> * p; register Ent8 b; p = lse.Entrada; b = 1; // por si lse está vacía if (p != 0) { while ( (b = p->Dato.pr != Pr || p->Dato.punto != ps) != 0 && p->pSig!= 0) p = p->pSig; // Si no se repite el nodo y se pueda avanzar seavanza. // Al salir p apuntará al último nodo si el elemento noexiste. } if (b) { NodoLSE<ElemCanonLR0> * nn = new NodoLSE<ElemCanonLR0>; if (nn == 0) return 0; nn->Dato.pr = Pr; nn->Dato.punto = ps; if (p != 0) p->pSig = nn; else lse.Entrada = nn; ++numelem; // se agregó un Elemento Canónico LR0 }

return b; // b != 0 si agrega}

19.21 CELEM02.CMM

// celem02.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"

Ent16ns ConjElem::AgregCerradura( const Gramatica & g ) { register NodoLSE<ElemCanonLR0> * q; register const NodoLSE<ReglaLC> * pr; Ent16ns n = 0; q = lse.Entrada; while (q != 0) {

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

323

Page 324: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (q->Dato.punto != 0 && // si el punto no está al final de la partederecha de la regla y q->Dato.punto->Dato.NoTerminal ) { // el símbolo apuntado es un noterminal pr = g.Reglas.Entrada; while (pr != 0) { // Se busca en la gramática alguna regla queempiece con tal símbolo register const NodoLSE<Simbolo> * pns; // n de nodo const Simbolo * ps; pns = pr->Dato.lse.Entrada; ps = & q->Dato.punto->Dato; if (ps->CodigoCompuesto() == pns->Dato.CodigoCompuesto() ) { // Si la regla empieza con el símbolo en cuestión if ( Agregar(pr, pns->pSig) ) // dir. de la regla y posición delpunto ++n; // se acaba de agregar un elemento (si Agregar() nofalló) } pr = pr->pSig; // avanzar a la siguiente regla } } q = q->pSig; // avanzar al siguiente elemento (nodo de la lista) } return n;}

19.22 CELEM03.CMM

// celem03.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"

Ent8 ConjElem::operator == ( const ConjElem & ce ) const { if (numelem != ce.numelem) return 0; register NodoLSE<ElemCanonLR0> * q1, * q2; Ent8 b; q1 = lse.Entrada; while (q1 != 0) { // buscar si los elementos de *this están en ce q2 = ce.lse.Entrada; while (q2 != 0) { if (q1->Dato == q2->Dato) break; q2 = q2->pSig; } if (q2 == 0) break; // elemento q1->Dato no encontrado en ce q1 = q1->pSig; } return q1 == 0; // son iguales si q1 vale 0}

19.23 CELEM04.CMM

// celem04.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

324

Page 325: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# include <archabst.h>

Archivo & operator << ( Archivo & a, const ElemCanonLR0 & eclr0 ) { register const NodoLSE<Simbolo> * pns;

if ( (pns = eclr0.pr->Dato.lse.Entrada) != 0 ) { a << (const char *) pns->Dato.Cadena() << " ---> "; while (pns->pSig != 0) { pns = pns->pSig; if (eclr0.punto == pns) a << "• "; // caracter 249 a << (const char *) pns->Dato.Cadena() << " "; } if (eclr0.punto == 0) a << "• "; } return a;}

Archivo & operator << ( Archivo & a, const ConjElem & ce ) { register const NodoLSE<ElemCanonLR0> * q = ce.lse.Entrada; while (q != 0) { a << q->Dato << "\n"; if (CodError) break; // si hay error se sale. q = q->pSig; } return a;}

19.24 CEST01.CMM

// cest01.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include <string.h># include "genslr.h"

static void limpiar( Ent16ns * v, register Ent16ns tam ) { if (v == 0) return; register Ent16ns * p = v; while (tam--) *p++ = 0;}

Ent8 ConjEst::Armar( Gramatica & g, Ent8 (* funcerror) ( Ent16ns e, Ent16ns vp, Ent16nsnr, const Simbolo & s) ) { if (g.Reglas.Entrada == 0) return 0; if (numest) Vaciar();

// Calcular los conjuntos Siguiente de cada no terminal. Ent16ns n = g.NumNoTerm(); Alfabeto * sig = new Alfabeto[n]; if (sig == 0) return 0; g.CalcSiguiente(sig); // calcula los conj. Siguiente para todos los noterm.

NodoLSE<ReglaLC> * rn; const Simbolo * ps; char * cad1;

// Buscar el símbolo inicial y generar el nuevo inicial. ps = & g.Reglas.Entrada->Dato.lse.Entrada->Dato;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

325

Page 326: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (ps != 0) { // ps apunta al símbolo inicial Ent16ns lon = ps->Cadena().Long() + 2; cad1 = new char [lon]; if (cad1 == 0) return 0; strncpy(cad1, ps->Cadena(), lon); cad1[lon-2] = '\''; // le agrega la ' cad1[lon-1] = 0; // terminación en 0 } else return 0;

// Una vez individualizado el símbolo inicial, se crea una regla que // aumentará la gramática. Si O es el símbolo, la regla a agregar será: // O' ---> O rn = new NodoLSE<ReglaLC>; if (rn == 0) return 0; rn->Dato.Agregar(cad1, 0, 1); // símbolo parte izq de la regla (O', cod0, no terminal) rn->Dato.Agregar(*ps); rn->pSig = g.Reglas.Entrada; // se engancha la regla nueva al comienzodel g.Reglas.Entrada = rn; // conjunto de reglas de la gramática

// devolver memoria usada por cad1. Ya no se usará más. delete cad1;

// Hasta ahora tenemos la gramática aumentada. Hay que generar el estado0 // e iterar armando los estados siguientes (función ir_a(estado,símbolo)) // para cada estado y para todos los símbolos de la gramática, hasta queno // se generen nuevos estados. (Recordar que un estado es un conjunto de // elementos canónicos LR(0). )

ConjElem * estn, *esta; // estado nuevo, estado actual estn = new ConjElem; if (estn == 0) return 0; estn->Agregar( rn, rn->Dato.lse.Entrada->pSig); // se agrega O' --> • Oal estado 0 estn->AgregCerradura(g); // se agrega la cerradura del conjunto { O' -->• O }

NodoLSE<Estado> * pestn, * pesta, // puntero al estado nuevo, punt. alest. actual * pestaux; // puntero auxiliar pestn = new NodoLSE<Estado>; // crea nodo del estado 0 if (pestn == 0) return 0; pestn->Dato.pce = estn; pestn->Dato.n = 0;

Ent16ns numsimbG = g.NumNoTerm() + g.NumTerm(); pestn->Dato.ves = new Ent16ns [numsimbG + 1]; if (pestn->Dato.ves == 0) return 0; limpiar(pestn->Dato.ves, numsimbG + 1); // ves[numsimbG] se reserva para reducciones y aceptar con FA (fin de // archivo) en ves[0] a ves[numsimbG-1] se colocan los valores de // ir_a(est, simb) para cada símbolo de la gramática, primero los // terminales y luego los no terminales.

lse.Entrada = pesta = pestn; // pone el estado 0 al comienzo de la listade estados

NodoLSE<ElemCanonLR0> * pelem; NodoLSE<Simbolo> * psimb; Ent16ns * pves; // para los vectores de estados siguientes (funciónir_a() )

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

326

Page 327: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

numest = 1; // campo numest del nodo actual while (pesta != 0) { // para cada estado (conj. de elementos) // El vector de estados siguientes (ves) tiene m + 1 entradas con // m = g.NumTerm() + g.NumNoTerm(). Las primeras g.NumTerm() entradas // corresponden a la operación desplazar para cada terminal en elestado // actual, en particular la entrada ves[m] (elemento m+1) correspondeal // símb FA, y no tiene operación de desplazamiento (sólo reducción ó // aceptar). Las g.NumNoTerm() entradas que están a partir delelemento // ves[g.NumTerm()] corresponden a la operación ir_a para cada no // terminal desde el estado actual.

pves = pesta->Dato.ves;

// A continuación se procede a construir las operaciones desplazar // para el estado actual. psimb = g.Term.lse.Entrada; while (psimb != 0) { // para cada símbolo terminal estn = new ConjElem; if (estn == 0) return 0; pelem = pesta->Dato.pce->lse.Entrada; while (pelem != 0) { // para cada elemento del estado actual if (pelem->Dato.punto != 0 && pelem->Dato.punto->Dato.CodigoCompuesto() ==psimb->Dato.CodigoCompuesto()) { // si el • está antes del // terminal actual agregar elemento al conj. de est. nuevo estn->Agregar( pelem->Dato.pr, pelem->Dato.punto->pSig); // siera A --> • a A agrega A --> a • A } // la regla es la misma y el punto se corre al siguiente símbolo pelem = pelem->pSig; // Avanzar al siguiente elemento del estadoactual } if (! estn->numelem) delete estn; // estado nuevo no usado, no seagregaron elementos else { // se agregaron elementos estn->AgregCerradura(g); // agregar la cerradura del conjunto pestn = new NodoLSE<Estado>; if (pestn == 0) return 0; pestn->Dato.pce = estn; pestn->Dato.n = numest; pestn->Dato.ves = new Ent16ns[numsimbG + 1]; if (pestn->Dato.ves == 0) return 0; limpiar(pestn->Dato.ves, numsimbG + 1); pestaux = lse.Entrada; while (pestaux != 0) { // buscar si el estado nuevo no estaba, sies así agregarlo al final if ( *(pestaux->Dato.pce) == *estn) break; // salir del while,estado repetido else if (pestaux->pSig == 0) { // pestaux apunta al último nodo,que tiene un conj. de elem. distinto al nuevo pestaux->pSig = pestn; // agregar al final *pves = numest++; // del actual se transiciona al estadonuevo con el símbolo terminal actual pestaux = 0; // para salir del while } else pestaux = pestaux->pSig; } if (pestaux != 0) { // si el nodo ya existía delete pestn->Dato.ves; delete pestn; delete estn; *pves = pestaux->Dato.n; }

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

327

Page 328: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} ++pves; // *pves vale 0 por defecto, o bien puede valer numest psimb = psimb->pSig; // avanzar al siguiente símbolo terminal } // while que itera en el alfabeto terminal

// Luego se construyen las operaciones ir_a para el estado actual. psimb = g.NoTerm.lse.Entrada; while (psimb != 0) { // para cada símbolo no terminal estn = new ConjElem; if (estn == 0) return 0; pelem = pesta->Dato.pce->lse.Entrada; while (pelem != 0) { // para cada elemento del estado actual if (pelem->Dato.punto != 0 && pelem->Dato.punto->Dato.CodigoCompuesto() ==psimb->Dato.CodigoCompuesto() ) { // agregar elemento al conj. de est. nuevo estn->Agregar( pelem->Dato.pr, pelem->Dato.punto->pSig); // si era A --> a • A agrega A --> a A • } // la regla es la misma y el punto se corre al siguiente símbolo pelem = pelem->pSig; // Avanzar al siguiente elemento del estadoactual } if (! estn->numelem) delete estn; // estado nuevo no usado else { estn->AgregCerradura(g); pestn = new NodoLSE<Estado>; if (pestn == 0) return 0; pestn->Dato.pce = estn; pestn->Dato.n = numest; pestn->Dato.ves = new Ent16ns[numsimbG + 1]; if (pestn->Dato.ves == 0) return 0; limpiar(pestn->Dato.ves, numsimbG + 1); pestaux = lse.Entrada; while (pestaux != 0) { // buscar si el estado nuevo no estaba, sies así agregarlo al final if ( *(pestaux->Dato.pce) == *estn) break; // salir del while else if (pestaux->pSig == 0) { // pestaux apunta al último nodo,que tiene un conj. de elem. distinto al nuevo pestaux->pSig = pestn; // agregar al final *pves = numest++; // del actual se transiciona al estadonuevo con el símbolo terminal actual pestaux = 0; // para salir del while } else pestaux = pestaux->pSig; } if (pestaux != 0) { // si el nodo (estado nuevo) ya existía delete pestn->Dato.ves; delete pestn; delete estn; *pves = pestaux->Dato.n; // enganchar con la primera copia } } ++pves; // *pves vale 0 por defecto, o bien puede valer numest psimb = psimb->pSig; // avanzar al siguiente símbolo terminal } // while que itera en el alfabeto no terminal pesta = pesta->pSig; // avanzar al siguiente conjunto de elementos }

// Hasta aquí está armado el conjunto de estado con las operaciones de // desplazamiento e ir_a ya colocados. Ahora hay que colocar las // reducciones y la aceptación. En los lugares donde en ves quede 0 son // de error.

pesta = lse.Entrada; while (pesta != 0) { pelem = pesta->Dato.pce->lse.Entrada;

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

328

Page 329: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

while (pelem != 0) { if (pelem->Dato.punto == 0) { // si el elemento es " A -> X Y • " // Buscar la regla en la gramática Ent16ns numregla; for (rn = g.Reglas.Entrada, numregla = 0; rn != 0; rn = rn->pSig, ++numregla) if (rn == pelem->Dato.pr) break; // salir cuando la encuentre

if ( numregla ) { // Si no es la regla 0, A' -> A // se agrega "reducir por regla numregla" a pesta->ves[i] paratodo // símb i en Siguiente(A) donde A está en la parte izq. de laregla. Ent8ns cnt = pelem->Dato.pr->Dato.lse.Entrada->Dato.Codigo; // cnt código del no terminal de la parte izq. de la regla --cnt; // y ahora tiene cod. del no term. menos 1 puesto que no // existe reducir por regla 0 (A' -> A). cnt indexa asig[] psimb = sig[cnt].lse.Entrada; char i; while (psimb != 0) { // Mientras hayan símbolos enSiguiente(cnt) i = psimb->Dato.Codigo; if (i) --i; else i = numsimbG; // Si la entrada no está definida o bien si funcerror dicehacer la // reducción, se asigna reducción por regla numregla apesta->ves[i] if ( ! pesta->Dato.ves[i] || funcerror != 0 && (*funcerror)(pesta->Dato.n, pesta->Dato.ves[i], numregla, *g.Term.Buscar(psimb->Dato.Codigo) ) ) pesta->Dato.ves[i] = 0x8000 | numregla; // 10 en los dosúltimos bits es reducir psimb = psimb->pSig; } } else { // La regla es A' -> A, la número 0 pesta->Dato.ves[numsimbG] = 0x4000; // 01 en los dos últ bits esaceptar // y se coloca para el símbolo terminal FA (entrada numsimbG) } } pelem = pelem->pSig; } pesta = pesta->pSig; }

// Llamar explícitamente a los destructores de los alfabetos Siguiente()// for (int c = 0; c < n; ++c ) sig[c].Alfabeto::~Alfabeto(); delete [] sig;

// En los dos últimos bits en el vector de estados siguientes (ves) decada // estado se da la acción. La estructura puede representarse por laclase // siguiente, la que sirve para las tablas ir_a y acción: // class ElemTabla { // Ent16ns n : 14; // 14 bits // Ent16ns a : 2; // 2 bits para indicar acción. // } // En a pueden haber los siguientes valores: // 0 (00): si n == 0 entonces hay error de sintaxis. // si n != 0 entonces acción = desplazar y pasar al estado n. // 1 (01): n valdrá 0 y no es usado. Acción = aceptar. // 2 (10): acción = reducir por regla n. Siempre n != 0.

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

329

Page 330: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Nunca se presenta el valor 3 (11).

return numest; // se devuelve el número de estados generados.}

19.25 CEST02.CMM

// cest02.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"# include <archabst.h>

Archivo & operator << ( Archivo & a, const ConjEst & ce ) { if (! ce.numest) return a; register const NodoLSE<Estado> * q = ce.lse.Entrada; while (q != 0) { a << "Estado " << q->Dato.n << ":\n" << *(q->Dato.pce) << "\n"; q = q->pSig; } return a;}

19.26 CEST03.CMM

// cest02.cmm

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "genslr.h"# include <archabst.h>

Archivo & operator << ( Archivo & a, const ConjEst & ce ) { if (! ce.numest) return a; register const NodoLSE<Estado> * q = ce.lse.Entrada; while (q != 0) { a << "Estado " << q->Dato.n << ":\n" << *(q->Dato.pce) << "\n"; q = q->pSig; } return a;}

19.27 CEST04.CMM

// cest04.cmm

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "genslr.h"# include <archivo.h>

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

330

Page 331: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Ent8 ConjEst::ImprTablaC( const char *, const Gramatica &,// const char * ) const// Imprime la tabla en formato de declaración del C

Ent8 ConjEst::ImprTablaC( const char * nom, const Gramatica & g, const char * sufijo ) const { if (! numest || g.Reglas.Entrada == 0) return 0; ArchivoSO a; if ( a.Abrir(nom, MA_E, MD_TXT) ) return 0; if (sufijo == 0) sufijo = ""; Ent16ns numnt = g.NumNoTerm(), numt = g.NumTerm(), c;

// noterm_long_pd tiene en [0] número de term y no term en la parte // baja y alta respectivamente. // en [1] en adelante las longitudes de las partes derechas de lasreglas // en la parte baja y el código del no terminal en la parte alta. a << "// Tablas generadas por ConjEst::ImprTablaC versión 2 (Nov 95).\n" "// Domingo Eduardo Becker.\n\n" "# ifndef __TIPOS_H\n# include <tipos.h>\n# endif\n" "\nEnt16ns ntlpd" << sufijo << "[] = {\n"; a.printf(" 0x%x,", numnt << 8 | numt ); const NodoLSE<ReglaLC> * pr = g.Reglas.Entrada->pSig; Ent16ns n = 0, x; const NodoLSE<Simbolo> * ps; Ascii0 cad; while (pr != 0) { if (! n) a << "\n "; x = pr->Dato.lse.Entrada->Dato.Codigo << 8 | pr->Dato.LongParteDer(); cad.printf("0x%x", x); a.printf(" %6s%c", (char *) cad, pr->pSig != 0 ? ',' : '\n' ); n += 8; if (n > 70) n = 0; pr = pr->pSig; } a << "};\n\n";

// accion[] tiene las acciones. en las posiciones 0 de la matriz tiene // la acción para FA. a << "Ent16ns accion" << sufijo << "[] = {\n "; const NodoLSE<Estado> * q = lse.Entrada; Ent16ns * ves; while (q != 0) { ves = q->Dato.ves; a.printf(" %5u,", ves[numt + numnt]); n = 7; for (c = 0; c < numt; ++c) { a.printf(" %5u", ves[c]); if (c < numt - 1) a << ","; n += 7; if (n > 70) n = 0; if (! n) a << "\n "; } q = q->pSig; if (q != 0) a << ",\n "; } a << "\n};\n\n";

// ir_a[] tiene la función ir_a para cada no terminal a << "Ent16ns ir_a" << sufijo << "[] = {\n "; q = lse.Entrada; while (q != 0) { ves = q->Dato.ves + numt; // saltea los primeros numt elementos for (c = 0, n = 0; c < numnt; ++c) { a.printf(" %5u", ves[c]);

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

331

Page 332: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (c < numnt - 1) a << ","; n += 7; if (n > 70) n = 0; if (! n) a << "\n "; } q = q->pSig; if (q != 0) a << ",\n "; } a << "\n};\n\n";

a.Cerrar(); return 1;}

19.28 CEST05.CMM

// cest05.cmm

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "genslr.h"# include <archivo.h>

// Ent8 ConjEst::ImprTabla( const char *, const Gramatica & g ) const// Imprime la tabla en formato texto en un archivo de texto.

Ent8 ConjEst::ImprTabla( const char * nom, const Gramatica & g ) const { if (! numest || g.Reglas.Entrada == 0) return 0; ArchivoSO a; if ( a.Abrir(nom, MA_E, MD_TXT) ) return 0; return ImprTabla(a, g);}

Códigos Fuentes de la Biblioteca de Soporte de SLR1 v 2.x

332

Page 333: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 20: Códigos Fuentes de SLR1 v 2.x

SLR1 v 2.x, al igual que la primera versión de SLR1, ha sido diseñadocomo un programa del usuario que hace uso de la biblioteca de soporte para lageneración de analizadores sintácticos SLR. De esta manera es posible lareutilización del generador de analizadores sintácticos en cualquier programadel usuario.

A diferencia de la biblioteca de soporte, esta implementación esdependiente del sistema operativo. Los módulos fuente aquí presentadospueden ser compilados con Borland C++ para Windows (4.02 o posterior) opara OS/2 (2.0 o posterior). Para el modo gráfico se utiliza la biblioteca OWLv 2.x que viene incluida en esos compiladores, ganando así portabilidad entreWindows y Presentation Manager. Para el modo caracter se utiliza labiblioteca BCE, ganando así la portabilidad a cualquier sistema operativo quedisponga de una versión de BCE.

La versión 2.x de SLR1 incluye todas las opciones de SLR1 v 1.x, portal razón no se incluyen los fuentes de SLR1 v 1.x puesto que son muysimilares y sería redundante.

A los efectos de no repetir código fuente dentro de este trabajo, cuandosea aplicable, se introducirán referencias hacia otras partes dentro de estedocumento, en donde era oportuno incluirlos.

20.1 GENSLR1D.CMM

El código fuente de este módulo es una implementación basada en lopropuesto en la sección 7.4.

Se puede generar una aplicación a partir de éste, compilándolo yencadenandolo con la biblioteca BCE, la biblioteca de soporte de SLR1 v 2.x ylas bibliotecas estándar.

Este módulo no debe ser incluido junto con GENSLR1.CMM.

// genslr1d.cmm Lun 27 Nov 95// Creado a partir de genslr1.cmm y modificado el 23 Feb 96 para que// funcione bajo DOS y OS/2 modo caracter.

// Copyright (c) 1996 by Domingo Eduardo Becker.// All rights reserved.

# include <dir.h> // fnsplit y fnmerge# include <string.h>

Códigos Fuentes de SLR1 v 2.x

333

Page 334: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# include <archivo.h># include "genslr.h"

static Ent8 FuncError ( Ent16ns estado, Ent16ns val_previo, Ent16nsnum_regla,

const Simbolo & s ) { Ent16ns n = val_previo & 0x2fff,

AntesRed = val_previo & 0xc000; Ascii0 antes, ahora; const char * CadTipoConf = AntesRed ? "Conflicto de reduccion/reduccion"

: "Conflicto de desplazamiento/reduccion"; antes.printf("%c%u", AntesRed ? 'r' : 'd', n); ahora.printf("r%u", num_regla); salida << "\n" << CadTipoConf << " en (" << estado << ", " << s << "): "

<< antes << " / " << ahora;

return 0; // siempre dejar acción previa.}

const char * NomExtSinDir( const char * NomArchCompleto, const char *ExtNueva ) { char disco[MAXDRIVE], dir[MAXDIR], nomarch[MAXFILE], extfue[MAXEXT],nulo[] = ""; static char NombreNuevo[MAXPATH]; fnsplit(NomArchCompleto, disco,dir,nomarch,extfue); fnmerge(NombreNuevo, nulo, nulo, nomarch, ExtNueva); return NombreNuevo;}

Ent8 GenerarSLR1( const char * NomArch, const char * Sufijo ) { salida << "SLR1 v 2.3 para modo caracter - Feb 96\n"

"D.E.Becker Tel (085) 22-2488/39-0567\n\n";

if (NomArch == 0 || ! strlen(NomArch)) { salida << "ERROR: Nombre no especificado o falta memoria."; return 1;

}

Gramatica G; ConjEst AutomataSLR1; Ascii0 CadPosErr, GramTxt; const char * nom,

cmm[] = ".cmm", est[] = ".est", tab[] = ".tab";

ArchivoSO a;

// Cargar la gramática en la memoria: salida << "Cargando gramatica en memoria . . . "; if ( a.Abrir(NomArch, MA_L) ) {

salida << "\nNo se puede abrir '" << NomArch << "' para lectura."; return 4;

} if (! GramTxt.Reasignar(a.Tam()+1)) {

salida << "Falta memoria para cargar archivo."; return 5;

} if ( ! a.Leer( (char *) GramTxt, a.Tam() ) ) {

salida << "ERROR: No se pudo leer el archivo."; return 6;

} a.Cerrar(); // Realizar análisis sintáctico y reasignar a objeto Gramatica salida << "\nRealizando analisis sintactico . . . "; if (! G.Reasignar(GramTxt, CadPosErr)) {

Códigos Fuentes de SLR1 v 2.x

334

Page 335: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

salida << "ERROR en la posicion: \n" << CadPosErr; return 7;

} G.ArmarAlfabetos(); // terminal y no terminal

// Generar el código fuente con las acciones semánticas: salida << "\nGenerando codigo C++ de acciones semanticas . . . "; nom = NomExt(NomArch, cmm); if (a.Abrir(nom, MA_E)) {

salida << "ERROR: No se puede abrir '" << nom << "' paraescritura.";

return 8; } a << "// Codigo fuente generado por SLR1 version 2.3 para modo caracter(Feb 96)\n"

"// Domingo Eduardo Becker, Sgo. del Estero, Tel (085)22-2488\n"; G.ImprAccSem(a, Sufijo); a << "\n";

// Generar codigo para el analizador lexico: salida << "\nGenerando codigo C++ de los analizadores lexico ysintactico . . . "; G.ImprAnaLex(a, Sufijo);

// Imprimir analizador sintactico: a << "\n// Definicion del analizador sintactico (SLR1 v 2.3).\n"

"// Cambiar de lugar la definicion si es necesario.\n\n" "# include \"" << NomExtSinDir(NomArch, tab)

<< "\" // tablas del analizador sintactico\n\nAnalSLR1<"<< (const char *) G.ClaseElemPila << "> as" << Sufijo

<< "(ntlpd" << Sufijo << ", accion" << Sufijo << ", ir_a" << Sufijo << ", AccSem" << Sufijo << ");";

a.Cerrar();

// Imprimir la gramatica en archivo .est salida << "\nImprimiendo la gramatica en archivo .EST . . . "; nom = NomExt(NomArch, est); if ( a.Abrir(nom, MA_E, MD_TXT) ) {

salida << "ERROR: No se puede abrir '" << nom << "' para escritura"; return 9;

} a << G;

// Imprimir Anulable, Primero y Siguiente: G.ImprAnulPrimSig(a);

// Armar las tablas de analisis sintactico salida << "\nGenerando las tablas SLR(1) . . . "; AutomataSLR1.Armar(G, FuncError);

// Imprimir las tablas en archivo .est salida << "\nImprimiendo las tablas SLR(1) en archivo .EST . . . "; a << "\n\nEstados: \n\n" << AutomataSLR1; AutomataSLR1.ImprTabla(a, G); a.Cerrar();

// Imprimir las tablas en archivo .tab salida << "\nImprimiendo las tablas SLR(1) en archivo .TAB . . . "; AutomataSLR1.ImprTablaC(NomExt(NomArch, tab), G, Sufijo); salida << "\n\nAnalizador sintactico y lexicografico generados sinproblemas."

<< "\nTablas en C++ en: " <<NomExt(NomArch, tab);

Códigos Fuentes de SLR1 v 2.x

335

Page 336: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

salida << "\nTablas y estados en texto en: " << NomExt(NomArch,est); salida << "\nAcciones semanticas y analizadores: " << NomExt(NomArch,cmm);

return 0;}

int main(int nArg, char * cArg[]) { if (nArg < 2) {

salida << "Falta el nombre del archivo con la gramatica."; return 1;

}

return GenerarSLR1(cArg[1], cArg[2]);}

20.2 GENSLR1.CMM

El código fuente de este módulo es una implementación basada en lopropuesto en la sección 7.4. Se agregó un diálogo en donde se presenta elprogreso de la generación y otro en donde se informan los conflictos y se daposibilidad de corregirlos. Si hay error de sintaxis, se muestra la posición endonde se produjo el error en otro diálogo.

// genslr1.cmm Lun 27 Nov 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

# include "progreso.h"# include "dlgerror.h"# include "dlgconf.h"# include <archivo.h># include "genslr.h"# include <dir.h> // fnsplit y fnmerge

static TProgreso * pDlgProgreso = 0;

static Ent8 FuncError ( Ent16ns estado, Ent16ns val_previo, Ent16nsnum_regla, const Simbolo & s ) { Ent16ns n = val_previo & 0x2fff, AntesRed = val_previo & 0xc000; Ascii0 cad; const char * CadTipoConf = AntesRed ? "Conflicto de reducción/reducción" : "Conflicto dedesplazamiento/reducción"; TDlgConflicto dlg(pDlgProgreso); dlg.Titulo = CadTipoConf; dlg.Estado = estado; dlg.Terminal = s.Cadena(); dlg.AccPrevia.printf("%c%u", AntesRed ? 'r' : 'd', n); dlg.AccNueva.printf("r%u", num_regla);

return dlg.Execute() != IDOK; // si ==IDOK se elige acción previa.}

const char * NomExtSinDir( const char * NomArchCompleto, const char *ExtNueva ) {

Códigos Fuentes de SLR1 v 2.x

336

Page 337: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

char disco[MAXDRIVE], dir[MAXDIR], nomarch[MAXFILE], extfue[MAXEXT],nulo[] = ""; static char NombreNuevo[MAXPATH]; fnsplit(NomArchCompleto, disco,dir,nomarch,extfue); fnmerge(NombreNuevo, nulo, nulo, nomarch, ExtNueva); return NombreNuevo;}

Ent8 GenerarSLR1( const char * NomArch, const char * Sufijo, TWindow * VentPadre ) { // Crear ventana diálogo de progreso pDlgProgreso = new TProgreso(VentPadre); if (pDlgProgreso == 0) return 1;

if (! pDlgProgreso->Create()) { delete pDlgProgreso; return 2; }

pDlgProgreso->SetCaption("SLR1 v 2.3 - Dic 95");

if (NomArch == 0 || ! strlen(NomArch)) { pDlgProgreso->MessageBox("Nombre no especificado o falta memoria.","ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 1; }

Gramatica G; ConjEst AutomataSLR1; Ascii0 CadPosErr, GramTxt; const char * nom, cmm[] = ".cmm", est[] = ".est", tab[] = ".tab"; ArchivoSO a;

// Cargar la gramática en la memoria:

pDlgProgreso->SetDlgItemText(TXT_1, "Cargando gramática en memoria . .."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

if ( a.Abrir(NomArch, MA_L) ) { CadPosErr.printf("No se puede abrir '%s'\npara lectura.", NomArch); pDlgProgreso->MessageBox(CadPosErr, "ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 4; } if (! GramTxt.Reasignar(a.Tam()+1)) { pDlgProgreso->MessageBox("Falta memoria para cargar archivo.","ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 5; } if ( ! a.Leer( (char *) GramTxt, a.Tam() ) ) { pDlgProgreso->MessageBox("No se pudo leer el archivo.", "ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 6; } a.Cerrar();

Códigos Fuentes de SLR1 v 2.x

337

Page 338: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Realizar análisis sintáctico y reasignar a objeto Gramatica

pDlgProgreso->SetDlgItemText(TXT_1, "Gramática cargada en memoria."); pDlgProgreso->SetDlgItemText(TXT_2, "Realizando análisis sintáctico . .."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

if (! G.Reasignar(GramTxt, CadPosErr)) { TDlgError * pDlgError = new TDlgError(pDlgProgreso); pDlgError->Cad = CadPosErr; pDlgError->Execute(); delete pDlgError; delete pDlgProgreso; return 7; } G.ArmarAlfabetos(); // terminal y no terminal

// Generar el código fuente con las acciones semánticas:

pDlgProgreso->SetDlgItemText(TXT_2, "No hay problemas de sintaxis."); pDlgProgreso->SetDlgItemText(TXT_3, "Generando código C++ de accionessemánticas . . ."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

nom = NomExt(NomArch, cmm); if (a.Abrir(nom, MA_E/*, MD_TXT*/)) { CadPosErr.printf("No se puede abrir '%s'\npara escritura.", nom); pDlgProgreso->MessageBox(CadPosErr, "ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 8; } a << "// Código fuente generado por SLR1 versión 2.3 (Dic 95)\n" "// Domingo Eduardo Becker, Sgo. del Estero, Tel (085) 22-2488\n"; G.ImprAccSem(a, Sufijo); a << "\n";

// Generar código para el analizador léxico:

pDlgProgreso->SetDlgItemText(TXT_3, "Código C++ de acciones semánticasgenerado."); pDlgProgreso->SetDlgItemText(TXT_4, "Generando código C++ de losanalizadores léxico y sintáctico . . ."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

G.ImprAnaLex(a, Sufijo);

// Imprimir analizador sintáctico: a << "\n// Definición del analizador sintáctico (SLR1 v 2.3).\n" "// Cambiar de lugar la definición si es necesario.\n\n" "# include \"" << NomExtSinDir(NomArch, tab) << "\" // tablas del analizador sintáctico\n\nAnalSLR1<" << (const char *) G.ClaseElemPila << "> as" << Sufijo << "(ntlpd" <<Sufijo << ", accion" << Sufijo << ", ir_a" << Sufijo << ", AccSem" << Sufijo<< ");";

a.Cerrar();

// Imprimir la gramática en archivo .est

pDlgProgreso->SetDlgItemText(TXT_4, "Código C++ de los analizadoresléxico y sintáctico generado.");

Códigos Fuentes de SLR1 v 2.x

338

Page 339: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

pDlgProgreso->SetDlgItemText(TXT_5, "Imprimiendo la gramática en archivo.EST . . ."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

nom = NomExt(NomArch, est); if ( a.Abrir(nom, MA_E, MD_TXT) ) { CadPosErr.printf("No se puede abrir '%s'\npara escritura.", nom); pDlgProgreso->MessageBox(CadPosErr, "ERROR", MB_OK | MB_ICONHAND); delete pDlgProgreso; return 9; } a << G;

// Imprimir Anulable, Primero y Siguiente: G.ImprAnulPrimSig(a);

// Armar las tablas de análisis sintáctico

pDlgProgreso->SetDlgItemText(TXT_5, "Gramática impresa en archivo.EST."); pDlgProgreso->SetDlgItemText(TXT_6, "Generando las tablas SLR(1) . .."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

AutomataSLR1.Armar(G, FuncError);

// Imprimir las tablas en archivo .est

pDlgProgreso->SetDlgItemText(TXT_6, "Tablas de análisis SLR(1)generadas."); pDlgProgreso->SetDlgItemText(TXT_7, "Imprimiendo las tablas SLR(1) enarchivo .EST . . ."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

a << "\n\nEstados: \n\n" << AutomataSLR1; AutomataSLR1.ImprTabla(a, G); a.Cerrar();

// Imprimir las tablas en archivo .tab

pDlgProgreso->SetDlgItemText(TXT_7, "Tablas de análisis SLR(1) impresasen archivo .EST."); pDlgProgreso->SetDlgItemText(TXT_8, "Imprimiendo las tablas SLR(1) enarchivo .TAB . . ."); pDlgProgreso->GetApplication()->PumpWaitingMessages(); // (pseudomultitarea)

AutomataSLR1.ImprTablaC(NomExt(NomArch, tab), G, Sufijo);

delete pDlgProgreso;

return 0;}

20.3 PROGRESO.CMM

El diseño de la ventana donde se muestra el progreso es el siguiente:

Códigos Fuentes de SLR1 v 2.x

339

Page 340: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 34 Diseño de la ventana donde se muestra el progreso de lageneración con SLR1 v 2.x

/* Project slr1 Copyright © 1995 by Domingo Eduardo Becker. All Rights Reserved.

SUBSYSTEM: slr1.apx Application FILE: progreso.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of TProgreso (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "progreso.h"

//{{TProgreso Implementation}}

TProgreso::TProgreso (TWindow* parent, TResId resId, TModule* module): TDialog(parent, resId, module){ // INSERT>> Your constructor code here.

}

TProgreso::~TProgreso (){ Destroy();

// INSERT>> Your destructor code here.

}

Códigos Fuentes de SLR1 v 2.x

340

Page 341: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

20.4 DLGCONF.CMM

Diseño del diálogo donde se muestra un conflicto y donde se da laposibilidad de corregirlo:

Fig. 35 Diseño del diálogo donde se muestran los conflictos.

/* Project slr1 Copyright © 1995 by Domingo Eduardo Becker. All Rights Reserved.

SUBSYSTEM: slr1.apx Application FILE: dlgconf.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of TDlgConflicto (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "dlgconf.h"

//{{TDlgConflicto Implementation}}

TDlgConflicto::TDlgConflicto (TWindow* parent, TResId resId, TModule*module): TDialog(parent, resId, module){ // INSERT>> Your constructor code here.

Códigos Fuentes de SLR1 v 2.x

341

Page 342: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

}

TDlgConflicto::~TDlgConflicto (){ Destroy();

// INSERT>> Your destructor code here.

}

void TDlgConflicto::SetupWindow (){ TDialog::SetupWindow();

// INSERT>> Your code here. if (Titulo.Long()) SetCaption(Titulo); if (Estado.Long()) SetDlgItemText(TXT_1, Estado); if (Terminal.Long()) SetDlgItemText(TXT_2, Terminal); if (AccPrevia.Long()) SetDlgItemText(TXT_3, AccPrevia); if (AccNueva.Long()) SetDlgItemText(TXT_4, AccNueva);}

20.5 DLGERROR.CMM

El diseño del diálogo donde se muestran los errores de sintaxis es elsiguiente:

Fig. 36 Diseño del diálogo donde se muestran los errores desintaxis.

/* Project afd Copyright © 1995. All Rights Reserved.

SUBSYSTEM: afd.apx Application

Códigos Fuentes de SLR1 v 2.x

342

Page 343: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

FILE: dlgerror.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of TDlgError (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "dlgerror.h"

//{{TDlgError Implementation}}

TDlgError::TDlgError (TWindow* parent, TResId resId, TModule* module): TDialog(parent, resId, module){ // INSERT>> Your constructor code here.

}

TDlgError::~TDlgError (){ Destroy();

// INSERT>> Your destructor code here.

}

void TDlgError::SetupWindow (){ TDialog::SetupWindow();

// INSERT>> Your code here. if (Cad.Long()) SetDlgItemText(IDC_CADENADLGERROR, Cad);}

20.6 SL1TDLGC.CMM

El diseño de la ventana principal es el siguiente:

Códigos Fuentes de SLR1 v 2.x

343

Page 344: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Fig. 37 Diseño de la ventana principal de SLR1 v 2.x para modográfico.

/* Project slr1 Copyright © 1995 by Domingo Eduardo Becker. All Rights Reserved.

SUBSYSTEM: slr1.exe Application FILE: sl1tdlgc.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of slr1TDLGClient (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "slr1app.h"#include "sl1tdlgc.h"

# include <owl\opensave.h># include <ascii0.h>

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(slr1TDLGClient, TDialog)//{{slr1TDLGClientRSP_TBL_BEGIN}} EV_BN_CLICKED(IDOK, Procesar), EV_BN_CLICKED(IDC_BUSCAR, BuscarArchivo),//{{slr1TDLGClientRSP_TBL_END}}END_RESPONSE_TABLE;

//{{slr1TDLGClient Implementation}}

//////////////////////////////////////////////////////////// slr1TDLGClient// ==========// Construction/Destruction handling.

Códigos Fuentes de SLR1 v 2.x

344

Page 345: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

slr1TDLGClient::slr1TDLGClient (TWindow *parent, TResId resId, TModule*module) : TDialog(parent, resId, module){ // INSERT>> Your constructor code here.}

slr1TDLGClient::~slr1TDLGClient (){ Destroy();

// INSERT>> Your destructor code here.}

Ent8 GenerarSLR1( const char * NomArch, const char * Sufijo, TWindow *VentPadre );

void slr1TDLGClient::Procesar (){ // INSERT>> Your code here. Ascii0 NomArch(100), Sufijo(50); GetDlgItemText(IDC_NOMARCH, NomArch, NomArch.TamBlq()); GetDlgItemText(IDC_SUFIJO, Sufijo, Sufijo.TamBlq()); if (GenerarSLR1(NomArch, Sufijo, this)) MessageBox("Error", "ERROR", MB_OK | MB_ICONHAND); else MessageBox("No hay problemas", "Observación", MB_OK |MB_ICONINFORMATION);}

void slr1TDLGClient::BuscarArchivo (){ // INSERT>> Your code here. TOpenSaveDialog::TData DatosDlg(OFN_HIDEREADONLY | OFN_FILEMUSTEXIST |OFN_NOCHANGEDIR, "Gramáticas (*.GLC)|*.glc|", 0,0,"glc");

TFileOpenDialog dlg(this, DatosDlg); if (dlg.Execute() == IDOK) SetDlgItemText(IDC_NOMARCH, DatosDlg.FileName);}

Códigos Fuentes de SLR1 v 2.x

345

Page 346: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 21: Códigos Fuentes de la Biblioteca ExpReg v 1.x

Los módulos fuentes presentados en este capítulo son independientesdel sistema operativo y del compilador con el cual se trabaje.

A los efectos de no repetir código fuente dentro de este trabajo, cuandosea aplicable, se introducirán referencias hacia otras partes dentro de estedocumento, en donde era oportuno incluirlos.

21.1 EXPREG.H

Este módulo se presenta en la sección 12.14.2.

21.2 GENAFD.H

# ifndef __GENAFD_H# define __GENAFD_H

// genafd.h: clases para el generador de autómatas finitos determinísticos// a partir de expresiones regulares.// Creación: Lun 09 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# ifndef __TIPOS_H# include <tipos.h> // independencia de la implementación de los tipos# endif // de datos fundamentales como por ejemplo el int.

# ifndef __LSE_H# include "lse.h"# endif

class NodoArbol {public: Ent16ns Tipo; Ent8 PrimUltCalc; NodoArbol * pIzq, * pDer; LSE<Ent16ns> Prim, Ult;

NodoArbol() { Tipo = PrimUltCalc = 0; pIzq = pDer = 0; } ~NodoArbol() { Vaciar(); } Ent8 Anulable() const; // para el árbol cuya raíz es éste nodo void CalcPrimUltSig( LSE<Ent16ns> * Sig ); Ent16ns AgregPrim( const LSE<Ent16ns> & prim ); Ent16ns AgregUlt( const LSE<Ent16ns> & ult ); void BorrarSubarboles(); void Vaciar();};

Códigos Fuentes de la Biblioteca ExpReg v 1.x

346

Page 347: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Tipo: indica el tipo de nodo. Para las hojas, este campo tiene elnúmero// de hoja (no puede haber 2 hojas con el mismo número), valor que// est  entre 0 y N_HOJA ambos inclusive. Para este campo se definen// constantes más adelante.// IdCar: identificador del caracter, es un índice para acceder a unvector// donde está la descripción de la expresión monocaracter.// PrimUltCalc: tiene 0 si PrimeraPos (Prim) y UltimaPos (Ult) no han sido// calculados, != 0 si ya se calcularon.// pIzq: subárbol de la izquierda del actual. Para los nodos '*', '+' y'?'// el subárbol se engancha en este campo. Para las hojas == 0.// pDer: subárbol de la derecha del actual. Se usa solamente para nodosdel// tipo '.' y '|'. Para los nodos '*', '+', '?' y hojas vale 0.// Prim y Ult: son listas de identificadores de las hojas (valor del campo// Tipo de las mismas) que son PrimeraPos y UltimaPosrespecti-// vamente, del nodo actual.

// Para el campo Tipo:// N_DIS: nodo disyunción, '|'// N_CON: nodo concatenación, '.'// N_AST: nodo asterisco, '*'// N_MAS: nodo más, '+'// N_OPC: nodo opcional, '?'// N_HOJA: nodo hoja, las hojas se numeran desde 0 hasta N_HOJA.# define N_DIS 0xffff# define N_CON 0xfffe# define N_AST 0xfffd# define N_MAS 0xfffc# define N_OPC 0xfffb# define N_HOJA 0xfffa

class DescrHoja {public: Ent16ns Id; Ent8ns IdCar;

DescrHoja() { Id = IdCar = 0; }};

// Id: número de hoja en el árbol sintáctico.// IdCar: número de elemento en la lista de caracteres.

// La tabla de descripciones de hoja es una LSE<DescrHoja>.// Con el campo IdCar se accede a una lista de cadenas donde se encuentrala// descripción del caracter o rango de caracteres aceptables como unidad.// La lista de cadenas se implementar  como LSE<Ascii0>

Ent16ns AgregLSE( LSE<Ent16ns> & des, const LSE<Ent16ns> & fue );// agrega a des una copia de los elementos de fue

class Estado {public: Ent16ns Id, * Tran; LSE<Ent16ns> * Pos; Estado() { Id = 0; Tran = 0; Pos = 0; }};

// Id: identificador del estado (0..n-1 si hay n estados).

Códigos Fuentes de la Biblioteca ExpReg v 1.x

347

Page 348: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// Tran: vector de transiciones a estados siguientes. Este vector es de// NumHojas elementos donde NumHojas es el número de hojas del árbol// sintáctico de la expresión regular.// Pos: lista de las hojas del árbol sintáctico que se agrupan en este// estado.

# endif // # ifndef __GENAFD_H

21.3 AFD01.CMM

// afd01.cmm Vie 13 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <archivo.h>

int ImprimirAFD( Archivo & arch, const AutomFinDet & afd ) { arch << "Expresión regular: " << (afd.ExpRegular != 0 ? afd.ExpRegular : "Desconocida"); if (afd.NumCar > 1) arch << "\nCaracteres y/o rangos: "; else if (afd.NumCar == 1) arch << "\nCaracter o rango: "; if (! afd.NumCar) { arch << "ERROR en el autómata, campo NumCar == 0.\n"; return 0; } Ent16ns i, j, estmayor, numcol, t; if (afd.Caracter != 0) for (i = 0; i < afd.NumCar; ++i) { if (i) arch << ", "; arch << "(" << i << ", \""; if (afd.Caracter[i] == 0) arch << "?#@!"; else ImprCadena(arch, afd.Caracter[i]); arch << "\")"; } arch << "\nTabla de transiciones:\n"; if (afd.Transicion == 0) { arch << "ERROR en el autómata, campo Transicion == 0.\n"; return 0; } estmayor = 1; arch << " "; numcol = afd.NumCar; for (i = 0; i < numcol; ++i) arch.printf("%3d ", i); arch << "\n"; for (i = 0; i < estmayor; ++i) { arch.printf("%3d ", i); for (j = 0; j < numcol; ++j) { t = afd.Transicion[i * numcol + j]; if (t == TNDEF) arch << " - "; else { arch.printf("%3d ", t); if (t >= estmayor) estmayor = t + 1; } } arch << "\n"; }

if (afd.EstFinales == 0) { arch << "ERROR en el autómata, campo EstFinales == 0.\n"; return 0;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

348

Page 349: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} if (afd.EstFinales[0] > 1) arch << "Estados finales: "; else arch << "Estado final: "; if (afd.EstFinales[0]) { for (i = 1; i <= afd.EstFinales[0]; ++i) { if (i > 1) arch << ", "; arch << (Ent16ns) afd.EstFinales[i]; } arch << "\n"; } else arch << "ERROR: EstFinales[0] == 0, no hay estados finales.\n";

return 1;}

21.4 AFD02.CMM

// afd02.cmm Lun 16 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <archivo.h># include <string.h>

int ImprFuenteAFD( Archivo & arch, const AutomFinDet & afd, const char * NomObj, const char * NomSubobj ) { if (NomObj == 0) NomObj = ""; if (NomSubobj == 0) NomSubobj = NomObj;

arch << "// AFD generado por la versión 3.4 de ExpReg::Reasignar (Nov95)\n" "// Domingo Eduardo Becker, Sgo. del Estero, (085) 22-2488/1088.\n" "\n# ifndef __EXPREG_H\n# include \"expreg.h\"\n# endif\n\n"; arch << "static const char er" << NomSubobj << "[] = \""; if (afd.ExpRegular != 0) ImprCadena(arch, afd.ExpRegular); arch << "\";\n"; if (! afd.NumCar) { arch << "ERROR en el autómata, campo NumCar == 0.\n"; return 0; } unsigned i, j, estmayor, numcol, t, lon; if (afd.Caracter != 0) { arch << "static const char * vc" << NomSubobj << "[] = {\n "; for (i = lon = 0; i < afd.NumCar; ++i) { if (i) { arch << ", "; lon += 2; } if (lon >= 80) { arch << "\n "; lon = 0; } arch << "\""; if (afd.Caracter[i] != 0) ImprCadena(arch, afd.Caracter[i]); arch << "\""; lon += 2 + strlen(afd.Caracter[i]); } arch << "\n};\n"; } if (afd.Transicion == 0) { arch << "ERROR en el autómata, campo Transicion == 0.\n";

Códigos Fuentes de la Biblioteca ExpReg v 1.x

349

Page 350: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

return 0; }

arch << "static const Ent16ns t" << NomSubobj << "[] = {\n"; estmayor = 1; numcol = afd.NumCar; for (i = 0; i < estmayor; ++i) { if (i) arch << ",\n"; arch << " "; for (j = 0; j < numcol; ++j) { t = afd.Transicion[i * numcol + j]; if (j) arch << ", "; if (t == TNDEF) arch << "TNDEF"; else { arch.printf("%5d", t); if (t >= estmayor) estmayor = t + 1; } } } arch << "\n};\n";

if (afd.EstFinales == 0) { arch << "ERROR en el autómata, campo EstFinales == 0.\n"; return 0; } if (afd.EstFinales[0]) { arch << "static const Ent16ns ef" << NomSubobj << "[] = {\n "; for (i = 0; i <= afd.EstFinales[0]; ++i) { if (i) arch << ", "; arch << (Ent16ns) afd.EstFinales[i]; } arch << "\n};\n"; } else { arch << "ERROR: EstFinales[0] == 0, no hay estados finales.\n"; return 0; }

arch << "AutomFinDet afd" << NomObj << " = { er" << NomSubobj << ", vc" << NomSubobj << ", " << (Ent16ns) afd.NumCar << ", t" << NomSubobj << ", ef" << NomSubobj << " };\n";

return 1;}

21.5 ANALEX01.CMM

// analex01.cmm Mar 17 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <ascii0.h># include <string.h>

unsigned AnaLex::Examinar( Ascii0 & CadSimb, int may ) { Ent8 aux = MayIgualMin; MayIgualMin = may; unsigned r = Examinar(CadSimb); MayIgualMin = aux; return r;}

Códigos Fuentes de la Biblioteca ExpReg v 1.x

350

Page 351: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

unsigned AnaLex::Examinar( Ascii0 & CadSimb ) { unsigned i, tama, tamafd, iafd, tamcad, icad, Cod; ExpReg er; char Ignorar, HayUnAFD, HayUnLiteral; Ignorar = 1; CadSimb.Vaciar(); do { if (Tama) { register const char * p; // ver si en el símbolo anterior habían '\n' for (i = 0, p = pTxt + Inic; i < Tama; ++i) if (*p++ == '\n') { ++NumLin; ComLin = Inic + i + 1; } // ahora avanzar Inic Inic += Tama; Tama = 0; } // Si no hay más que analizar, salir. if (! pTxt[Inic]) { CodError = 0; return 0; }

iafd = icad = tvrs; tamafd = tamcad = 0; // Buscar si hay algún AFD que reconozca el símbolo siguiente for (i = 0; i < tvrs; ++i) if (vrs[i].EsAFD) { er.Reasignar( * vrs[i].pAFD ); if (! er.Examinar(pTxt, Inic, tama) && tama > tamafd) { tamafd = tama; iafd = i; } }

// Sea o no que haya un AFD que reconozca al símbolo, verificar // si corresponde a una constante. for (i = 0; i < tvrs; ++i) if (! vrs[i].EsAFD) { tama = strlen(vrs[i].pCad); if ((! MayIgualMin && ! strncmp(vrs[i].pCad, pTxt + Inic, tama) || MayIgualMin && ! strnicmp(vrs[i].pCad, pTxt + Inic, tama) )&& tama > tamcad) { tamcad = tama; icad = i; } }

HayUnLiteral = icad < tvrs; HayUnAFD = iafd < tvrs; // Si hay una cadena literal y un AFD que reconocen a la cadena de // caracteres siguiente, elegir entre los dos el más largo. Si ambostienen // igual longitud o el literal es más largo que la cadena reconocidapor el // AFD entonces elegir el literal. if (HayUnLiteral && HayUnAFD) { if (tamafd > tamcad) { Cod = vrs[iafd].Id; Ignorar = ! Cod; CodError = 0; Tama = tamafd;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

351

Page 352: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (! Ignorar) Simbolo(CadSimb); } else { Cod = vrs[icad].Id; Ignorar = ! Cod; CodError = 0; Tama = tamcad; if (! Ignorar) Simbolo(CadSimb); } } else if (HayUnLiteral) { Cod = vrs[icad].Id; Ignorar = ! Cod; CodError = 0; Tama = tamcad; if (! Ignorar) Simbolo(CadSimb); } else if (HayUnAFD) { Cod = vrs[iafd].Id; Ignorar = ! Cod; CodError = 0; Tama = tamafd; if (! Ignorar) Simbolo(CadSimb); } else { Cod = fErrorLex != 0 ? (*fErrorLex)(MayIgualMin, *this, CadSimb) :0xffff; CodError = Cod == 0xffff ? 1 : 0; Ignorar = ! Cod; } } while (Ignorar);

return Cod;}

21.6 ANALEX02.CMM

// analex02.cmm Mié 18 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <ascii0.h># include <string.h>

unsigned AnaLex::Simbolo( Ascii0 & Simb ) const { if (! Tama) return 0; if (! Simb.Reasignar(Tama + 1)) return 0; strncpy(Simb, pTxt + Inic, Tama); return Tama;}

21.7 ANALEX03.CMM

// analex03.cmm Sáb 21 Ene 95

// Copyright (c) 1995 by Domingo Eduardo Becker.// All rights reserved.

Códigos Fuentes de la Biblioteca ExpReg v 1.x

352

Page 353: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# include "blanco.cmm"# include "coment.cmm"# include "caract.cmm"# include "rango.cmm"# include "idafd.cmm"

static RecSimb vrs[] = { 0, 1, & afdBlanco, 0, // ignora los blancos (Id == 0) 0, 1, & afdComent, 0, // ignora los comentarios (Id ==0) _id_CteCar, 1, & afdCaract, 0, _id_Rango, 1, & afdRango, 0, _id_Ident, 1, & afdIdent, 0, _id_Disyuncion, 0, 0, "|", _id_Uno_o_Mas, 0, 0, "+", _id_Cero_o_Mas, 0, 0, "*", _id_Opcional, 0, 0, "?", _id_Abre_Paren, 0, 0, "(", _id_Cierra_Paren, 0, 0, ")", _id_Numeral, 0, 0, "#", _id_CteCar, 0, 0, ".",};

# ifndef __ASCII0_H# include <ascii0.h># endif

static unsigned CorregirErrLex( int , AnaLex & analex, Ascii0 & cad ) { register char car, * p;

if ( ! (car = analex.Saltear()) ) return 0; // 0 == Fin de archivo if (! cad.Reasignar(2)) return 0; // ?? falta memoria p = (char *) cad; *p++ = car; *p = 0; // terminaci¢n en 0

return _id_CteCar;}

// El analizador léxico es el objeto AnaLexExpReg siguiente:

AnaLex AnaLexExpReg(vrs, 13, 0, CorregirErrLex);// 13 elementos RecSimb en vrs.

21.8 ANALEX04.CMM

// analex04.cmm Jue 26 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"

unsigned AnaLex::Saltear( unsigned tam ) { if (! tam || Tama || pTxt == 0 || ! pTxt[Inic]) return 0; register unsigned t; register const char * p; for (t = 0, p = pTxt + Inic; t < tam; ++t, ++p) if (! *p) break;

return Tama = t;}

Códigos Fuentes de la Biblioteca ExpReg v 1.x

353

Page 354: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

21.9 ANALEX05.CMM

// analex05.cmm Jue 26 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <ascii0.h># include <string.h>

unsigned AnaLex::CadError( Ascii0 & Cad ) const { register char * p; register unsigned t, n;

// Contar la cantidad de caracteres hasta el siguiente '\n' o fin dearchivo for (t = 0, p = (char *) pTxt + ComLin; *p && *p != '\n'; ++t, ++p);

Cad.Vaciar(); if (! t) return 0;

if (! Cad.Reasignar(t * 2 + 2)) return 0; strncpy(Cad, pTxt + ComLin, t); p = (char *) Cad + t; *p++ = '\n';

for (n = ComLin; t; --t, ++n) *p++ = n != Inic ? ' ' : '^';

*p = 0;

return Cad.Long();}

21.10 ER01.CMM

// er01.cmm Lun 16 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"

void ExpReg::Vaciar() { if (afd == 0) return; if (! apu) { if (afd->Transicion != 0) delete (void *) afd->Transicion; if (afd->EstFinales != 0) delete (void *) afd->EstFinales; delete afd; } afd = 0; apu = 0;}

Códigos Fuentes de la Biblioteca ExpReg v 1.x

354

Page 355: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

21.11 ER02.CMM

// er02.cmm Lun 16 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <fvarias.h># include <string.h>

int ExpReg::Examinar( const char * Cadena, unsigned Inicio, unsigned & Tam ) const { Ent16ns Estado, NumCar, Car, EstadoNuevo, i; const char * * Caracter, * pCad; const Ent16ns * Transicion, * EstFinales; Tam = 0; if (afd == 0) return AFDNDEF; Caracter = afd->Caracter; Transicion = afd->Transicion; EstFinales = afd->EstFinales; NumCar = afd->NumCar; Estado = 0; if (Caracter == 0 || Transicion == 0 ||EstFinales == 0 || ! NumCar) return AFDERR; if (Cadena == 0 || Inicio >= strlen(Cadena)) return CADNULA; pCad = Cadena + Inicio;

do { // Primero buscar qué caracter es for (Car = 0; Car < NumCar; ++Car) if (Aceptar(*pCad, Caracter[Car])) break;

if (Car == NumCar) break; // salir del bucle, posible parada en // estado final // Luego ver si hay transición para ese caracter y el estado actual EstadoNuevo = Transicion[Estado * NumCar + Car]; if (EstadoNuevo != TNDEF) { // si hay, avanzar un caracter ++Tam; ++pCad; Estado = EstadoNuevo; } } while (EstadoNuevo != TNDEF || ! *pCad);

// Finalmente ver si el estado en el que se qued¢ es estado final for (i = 1; i <= EstFinales[0]; ++i) if (Estado == EstFinales[i]) break;

if (i > EstFinales[0]) if (Car == NumCar) return CARINESP; // caracter inesperado else return TRANSNDEF; // es caracter esperado pero no hay transici¢n

return 0;}

21.12 ER03.CMM

// er03.cmm Mar 17 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

Códigos Fuentes de la Biblioteca ExpReg v 1.x

355

Page 356: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

# include "expreg.h"# include <string.h>

int ExpReg::Buscar( const char * Cadena, unsigned & Inicio, unsigned & Tam, unsigned Desde ) const { unsigned inicio, loncad; loncad = Cadena != 0 && *Cadena ? strlen(Cadena) : 0; if (Desde >= loncad) return CADNULA; inicio = Desde; Tam = 0; while (inicio < loncad && Examinar(Cadena, inicio, Tam)) ++inicio; Inicio = inicio < loncad ? inicio : Desde; return 0;}

21.13 ER04.CMM

// er04.cmm Mié 25 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"# include <archivo.h>

int ExpReg::ImprFuente( const char * NomArch, const char * NomObj , const char * NomSubobj ) const { register int r; ArchivoSO arch; if ( arch.Abrir(NomArch, MA_E, MD_TXT) ) return 0; r = ImprFuente(arch, NomObj, NomSubobj); arch.Cerrar(); return r;}

21.14 NARBOL01.CMM

// narbol01.cmm Mié 11 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "genafd.h"

Ent8 NodoArbol::Anulable() const { register char r; switch (Tipo) { case N_AST: // '*' case N_OPC: // '?' r = 1; break;

case N_DIS: // '|' r = pIzq->Anulable() || pDer->Anulable(); break;

case N_CON: // '.' r = pIzq->Anulable() && pDer->Anulable(); break;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

356

Page 357: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

default: // Tipo <= N_HOJA || Tipo == N_MAS '+' r = 0; } return r;}

Ent16ns AgregLSE( LSE<Ent16ns> & des, const LSE<Ent16ns> & fue ) { register NodoLSE<Ent16ns> * p, * q; Ent16ns c; for (p = fue.Entrada, c = 0; p != 0; p = p->pSig) { for (q = des.Entrada; q != 0; q = q->pSig) if (q->Dato == p->Dato) break; // si lo encuentra salir

if (q != 0) continue; // nodo existente, no agregar des.AgregComienzo(p->Dato); // lo agrega ++c; } return c;}

Ent16ns NodoArbol::AgregPrim( const LSE<Ent16ns> & primfue ) { return AgregLSE(Prim, primfue);}

Ent16ns NodoArbol::AgregUlt( const LSE<Ent16ns> & ultfue ) { return AgregLSE(Ult, ultfue);}

void AgregSig( LSE<Ent16ns> * Sig, const LSE<Ent16ns> & Desde, const LSE<Ent16ns> & Hacia ) { // Todas las hojas que hay en Hacia son SiguientePos de todas las hojas // que hay en Desde. register NodoLSE<Ent16ns> * p; for (p = Desde.Entrada; p != 0; p = p->pSig) AgregLSE(Sig[p->Dato], Hacia);}

void NodoArbol::CalcPrimUltSig( LSE<Ent16ns> * Sig ) { if (PrimUltCalc) return; // ya fue realizado switch (Tipo) { case N_AST: // '*' case N_OPC: // '?' case N_MAS: // '+' pIzq->CalcPrimUltSig(Sig); AgregPrim(pIzq->Prim); AgregUlt(pIzq->Ult); PrimUltCalc = 1; break;

case N_DIS: // '|' pIzq->CalcPrimUltSig(Sig); pDer->CalcPrimUltSig(Sig); AgregPrim(pIzq->Prim); AgregPrim(pDer->Prim); AgregUlt(pIzq->Ult); AgregUlt(pDer->Ult); PrimUltCalc = 1; break;

case N_CON: // '.' pIzq->CalcPrimUltSig(Sig); pDer->CalcPrimUltSig(Sig); // PrimeraPos AgregPrim(pIzq->Prim); if (pIzq->Anulable()) AgregPrim(pDer->Prim);

Códigos Fuentes de la Biblioteca ExpReg v 1.x

357

Page 358: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

// UltimaPos AgregUlt(pDer->Ult); if (pDer->Anulable()) AgregUlt(pIzq->Ult); // Ahora se calcula SiguientePos para nodos '.' AgregSig(Sig, pIzq->Ult, pDer->Prim); // todas las posiciones dentrode // Prim del hijo derecho están en SiguientePos de todas lasposiciones // dentro Ult del hijo izquierdo del actual. break;

default: // Tipo <= N_HOJA Prim.AgregComienzo(Tipo); Ult.AgregComienzo(Tipo); } PrimUltCalc = 1;

// Se calcula SiguientePos para nodos '*' y nodos '+' if (Tipo == N_AST || Tipo == N_MAS) AgregSig(Sig, Ult, Prim); // todas las posiciones de Prim son // siguientes a las posiciones de Ult}

void NodoArbol::BorrarSubarboles() { if (pIzq != 0) { delete pIzq; pIzq = 0; } if (pDer != 0) { delete pDer; pDer = 0; }}

void NodoArbol::Vaciar() { BorrarSubarboles(); Prim.Vaciar(); Ult.Vaciar();}

// El conjunto T de terminales fue generado por SLR1.EXE versión 1.// El analizador lexicográfico debe devolver los códigos cuyos números// se especifican para que funcione correctamente el analizador// sintáctico que aquí se utiliza (generado por SLR1 v1).// T = { ('#', 1), (Ident, 2), (CteCar, 3), (Rango, 4), ('|', 5),// ('?', 6), ('+', 7), ('*', 8), ('(', 9), (')', 10) }// Ver definición de las constantes en expreg.h.

// A continuación, el código para cargar la expresión regular en memoria// y armar el árbol sintáctico, previo análisis sintáctico de la misma.// Se utiliza el generador de analizadores sintácticos SLR1 v 1.// Para realizar el análisis sintáctico se utiliza la implementación de// analizadores sintácticos SLR(1) preparada para SLR1 v 2.

# include "expreg.cmm" // tablas de análisis sintáctico de una exp reg.# include "slr1.h" // analizador SLR(1).

class ElemPilaER : public ElemPila { // elemento de la pila para exp regpublic: NodoArbol * pNodo;

ElemPilaER() { pNodo = 0; } ~ElemPilaER();};

Códigos Fuentes de la Biblioteca ExpReg v 1.x

358

Page 359: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

ElemPilaER::~ElemPilaER() { if (pNodo != 0) { delete pNodo; pNodo = 0; }}

// AccSem implementa las acciones semánticas.// Si la regla es Simb0 --> Simb1 Simb2, las posiciones en pila son:// Simb0 y Simb1 están ambos en pila[pp+1], por lo que primero se debe// trabajar sobre Simb1 para luego dejar el resultado al final en Simb0.// Simb2 se encuentra en la posición pila[pp+2], y así sucesivamente.// pila y pp son variables globales.

class DescrIdent {public: Ascii0 Cad; Ent8ns Id; DescrIdent() { Id = 0; }};

// Variables globales:static LSE<DescrHoja> Hoja; // lista de descripciones de hojas del árbolstatic LSE<Ascii0> Caracter; // lista de cadenas descriptoras decaracteresstatic Ent8ns MaxCar;static Ent16ns NumHoja; // número actual de hojasstatic LSE<DescrIdent> TablaIdent;static NodoArbol * RaizAnalSint;

static void InicVariablesGlob() { Hoja.Vaciar(); Caracter.Vaciar(); MaxCar = 0; NumHoja = 0; TablaIdent.Vaciar(); RaizAnalSint = 0;}

static void ElimComillaCambSecEsc( char * pCad ) { register char * p; if ((p = pCad) == 0 || ! *p) return; while (*p) { *p = *(p+1); // desplazar uno a la izquierda if (*p) ++p; } *(p-1) = 0; // elimina último caracter CambSecEsc(pCad);}

# include <string.h>

static void AccSem( Ent16ns numregla, ElemPilaER * pila, Ent16ns pp ) { NodoArbol * pn; NodoLSE<Ascii0> * pCar, * pFinal; Ent8ns c; DescrHoja dh; NodoLSE<DescrIdent> * pDI;

if (numregla == 1) { // 1: ExpReg ----> Defs Disy RaizAnalSint = pila[pp+2].pNodo; pila[pp+2].pNodo = 0; }

Códigos Fuentes de la Biblioteca ExpReg v 1.x

359

Page 360: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

else if (numregla == 2) { // 2: ExpReg ----> Disy RaizAnalSint = pila[pp+1].pNodo; pila[pp+1].pNodo = 0; } else if (numregla == 5 || numregla == 6) { // 5: Def -------> '#' Ident CteCar // 6: Def -------> '#' Ident Rango for (pDI = TablaIdent.Entrada; pDI != 0; pDI = pDI->pSig) if (! strcmp(pila[pp+2].CadTerm, pDI->Dato.Cad)) break;

if (pDI == 0) { pDI = new NodoLSE<DescrIdent>; if (pDI != 0) { pDI->Dato.Cad << pila[pp+2].CadTerm; if (pila[pp+3].CadTerm.Long() >= 3) ElimComillaCambSecEsc(pila[pp+3].CadTerm); // Agregar CteCar o Rango a la lista Caracter, si no existe. // Obtener el correspondiente Id del mismo. for (c = 0, pCar = pFinal = Caracter.Entrada; pCar != 0; pCar = pCar->pSig, ++c) { if (! strcmp(pila[pp+3].CadTerm, pCar->Dato)) break; if (pCar->pSig != 0) pFinal = pCar->pSig; } if (pCar == 0) { // agregar si no existe pCar = new NodoLSE<Ascii0>; if (pCar != 0) { pCar->Dato << pila[pp+3].CadTerm; if (pFinal != 0) pFinal->pSig = pCar; else Caracter.Entrada = pCar; // c queda con el valor que tenía ++MaxCar; // hay un caracter más en la lista } else c = 0; } pDI->Dato.Id = c; // Enganchar el descriptor del Ident a la entrada de TablaIdent pDI->pSig = TablaIdent.Entrada; TablaIdent.Entrada = pDI; } } // else ... si pDI != 0, la definición de Ident es incorrecta, // se la ingorará pila[pp+2].CadTerm.Vaciar(); pila[pp+3].CadTerm.Vaciar(); } else if (numregla == 7 || numregla == 9) { // 7: Disy ------> Disy '|' Concat // 9: Concat ----> Concat Unario char indice; indice = numregla == 7 ? 3 : 2; pn = new NodoArbol; if (pn == 0) return; pn->Tipo = numregla == 7 ? N_DIS : N_CON; // '|' o '.' pn->pIzq = pila[pp+1].pNodo; pn->pDer = pila[pp + indice].pNodo; pila[pp+1].pNodo = pn; pila[pp + indice].pNodo = 0; // no se usa hasta nuevo aviso } else if (numregla == 11 || numregla == 12 || numregla == 13) { // 11: Unario ----> Par_Car '?' // 12: Unario ----> Par_Car '+' // 13: Unario ----> Par_Car '*' pn = new NodoArbol; if (pn == 0) return; pn->Tipo = numregla == 11 ? N_OPC : (numregla == 12 ? N_MAS : N_AST);

Códigos Fuentes de la Biblioteca ExpReg v 1.x

360

Page 361: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

pn->pIzq = pila[pp+1].pNodo; pila[pp+1].pNodo = pn; } else if (numregla == 15) { // 15: Par_Car ---> '(' Disy ')' pila[pp+1].pNodo = pila[pp+2].pNodo; pila[pp+2].pNodo = 0; } else if (numregla == 16) { // 16: Par_Car ---> Caracter pn = new NodoArbol; if (pn == 0) return; pn->Tipo = NumHoja++; // asigna número de hoja e incrementa NumHoja // Agrega descriptor de hoja: // primero busca caracter en la lista Caracter for (c = 0, pCar = pFinal = Caracter.Entrada; pCar != 0; pCar = pCar->pSig, ++c) { if (! strcmp(pila[pp+1].CadTerm, pCar->Dato)) break; if (pCar->pSig != 0) pFinal = pCar->pSig; } if (pCar == 0) { // agregar si no existe pCar = new NodoLSE<Ascii0>; if (pCar != 0) { pCar->Dato << pila[pp+1].CadTerm; if (pFinal != 0) pFinal->pSig = pCar; else Caracter.Entrada = pCar; // c queda con el valor que tenía ++MaxCar; // hay un caracter más en la lista } else c = 0; } dh.Id = pn->Tipo; dh.IdCar = c; Hoja.AgregFinal(dh); // enganchar con elemento actual de la pila LR pila[pp+1].pNodo = pn; // anular campo CadTerm del elemento actual de la pila LR para que no // use memoria pila[pp+1].CadTerm.Vaciar(); } else if (numregla == 17) { // 17: Caracter --> Ident for (pDI = TablaIdent.Entrada; pDI != 0; pDI = pDI->pSig) if (! strcmp(pila[pp+1].CadTerm, pDI->Dato.Cad)) break;

if (pDI != 0) // si Ident fue definido, se cambia Ident por su def. pila[pp+1].CadTerm = * Caracter.DatoNodoI( pDI->Dato.Id ); // sino queda Ident como cte. caracter. } else if (numregla == 18) { // 18: Caracter --> CteCar if (pila[pp+1].CadTerm.Long() >= 3) ElimComillaCambSecEsc(pila[pp+1].CadTerm); else { char * pCad; pCad = (char *) pila[pp+1].CadTerm; if (*pCad == '.' && ! *(pCad+1)) { pila[pp+1].CadTerm = "^\n"; pila[pp+1].CadTerm.Reasignar(pila[pp+1].CadTerm.TamBlq()); } } } else if (numregla == 19) { // 19: Caracter --> Rango if (pila[pp+1].CadTerm.Long() >= 3) ElimComillaCambSecEsc(pila[pp+1].CadTerm);

Códigos Fuentes de la Biblioteca ExpReg v 1.x

361

Page 362: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

}}

// La función que genera el autómata finito determinístico es lasiguiente:

# ifndef __EXPREG_H# include "expreg.h"# endif

int ExpReg::Reasignar( const char * ExpRegular, Ascii0 & CadPosErr ) { if (ExpRegular == 0 || *ExpRegular == 0) return 0; Vaciar(); // Iniciar el analizador lexicográfico: AnaLexExpReg.Reiniciar(ExpRegular); // Iniciar variables del analizador sintáctico: InicVariablesGlob(); // Analizador sintáctico SLR(1) AnalSLR1<ElemPilaER> analizador(noterm_long_pd, accion, ir_a, AccSem);

// Generar el árbol sintáctico usando el analizador sintáctico: if (! analizador.Analizar(AnaLexExpReg, CadPosErr)) { // Los siguientes objetos son tablas generadas por AccSem. // Se debe devolver la memoria usada por ellas. // lista de descriptores de hojas del árbol sintáctico Hoja.Vaciar(); // conjunto de caracteres que aparecieron en la expresión regular Caracter.Vaciar(); // Tabla de identificadores TablaIdent.Vaciar();

return 0; // la memoria del arbol generado la devuelve el destructor } // de la clase ElemPilaER al hacer 'delete pNodo'.

// RaizAnalSint es la raíz del árbol sintáctico generado por el // analizador. Se debe agregar la concatenación con caracter '#'FinArch. NodoArbol * raiz, * HojaFinal; Ent8ns c; DescrHoja dh; int resultado; resultado = 0; // por defecto, resultado indica que hay problemas.

// Primero crear la hoja para el caracter de fin de expresión regular'#' HojaFinal = new NodoArbol; if (HojaFinal == 0) { delete RaizAnalSint; // árbol generado por el analizador sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); return 0; } HojaFinal->Tipo = NumHoja; // asigna número de hoja sin incrementarNumHoja // Agrega descriptor de hoja: dh.Id = HojaFinal->Tipo; dh.IdCar = MaxCar; Hoja.AgregFinal(dh);

// Luego crear el nodo raiz raiz = new NodoArbol; if (raiz == 0) { delete RaizAnalSint; // árbol generado por el analizador sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico

Códigos Fuentes de la Biblioteca ExpReg v 1.x

362

Page 363: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Caracter.Vaciar(); TablaIdent.Vaciar(); return 0; } raiz->Tipo = N_CON; // '.' raiz->pIzq = RaizAnalSint; raiz->pDer = HojaFinal; RaizAnalSint = 0;

// Ahora se calcula SiguientePos para todas las hojas del árbol LSE<Ent16ns> * Sig; Sig = new LSE<Ent16ns>[ NumHoja ]; // pide un vector de LSE de NumHojaelem if (Sig == 0) { delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); return 0; } raiz->CalcPrimUltSig(Sig);

LSE<Estado> EstadosD; NodoLSE<Estado> * pEstAct, * pFinal, * pAuxEst; LSE<Ent16ns> * U; NodoLSE<Ent16ns> * pPos, * pPos2; NodoLSE<DescrHoja> * pHoja; Ent16ns NumEst, i, j;

// El estado inicial es PrimeraPos(raiz) pEstAct = new NodoLSE<Estado>; if (pEstAct == 0) { // falta memoria delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } pEstAct->Dato.Pos = new LSE<Ent16ns>; if (pEstAct->Dato.Pos == 0) { // falta memoria delete pEstAct; delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } AgregLSE(* pEstAct->Dato.Pos, raiz->Prim); pEstAct->Dato.Tran = new Ent16ns[NumHoja]; if (pEstAct->Dato.Tran == 0) { // falta memoria delete pEstAct->Dato.Pos; delete pEstAct; delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } for (i = 0; i < NumHoja; ++i) pEstAct->Dato.Tran[i] = TNDEF; // se agrega el estado inicial a la lista de estados pFinal = EstadosD.Entrada = pEstAct; NumEst = 1;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

363

Page 364: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

while (pEstAct != 0) { for (c = 0; c < MaxCar; ++c) { // para cada símbolo de entrada c hacer U = new LSE<Ent16ns>; if (U == 0) { delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbolsintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } // en U se guardará la unión de todos los conjuntosSiguientePos(pPos) // para las posiciones pPos del estado actual tales que el símboloen // esa posición pPos es c. // Se recorre el estado actual para ver si alguna posicióncorresponde // al símbolo actual c. for (pPos = pEstAct->Dato.Pos->Entrada; pPos != 0; pPos =pPos->pSig) { // Para cada posición, se busca la misma en la lista descriptorade // hojas; es allí donde dice a qué caracter corresponde. for (pHoja = Hoja.Entrada; pHoja != 0; pHoja = pHoja->pSig) // si encuentra el descriptor de la hoja salir if (pPos->Dato == pHoja->Dato.Id) break; // Si la hoja corresponde al caracter c, agregar SiguientePos de // esa hoja a U. if (pHoja != 0 && pHoja->Dato.IdCar == c) AgregLSE(*U, Sig[pHoja->Dato.Id]); } if (U->Entrada != 0) { // Si U es un conjunto no vacío, haytransición // Buscar si el estado se repite. Si se repite, pAuxEst apuntaráal // estado previamente agregado, sino pAuxEst valdrá 0. for (pAuxEst = EstadosD.Entrada; pAuxEst != 0; pAuxEst = pAuxEst->pSig) { // Para cada estado ya agregado... // si el número de elementos de U es distinto se continua elbucle if (pAuxEst->Dato.Pos->NumElem() != U->NumElem()) continue;

// sino se busca si cada elemento de U se repite en ese estado. for (pPos2 = U->Entrada; pPos2 != 0; pPos2 = pPos2->pSig) { for (pPos = pAuxEst->Dato.Pos->Entrada; pPos != 0; pPos = pPos->pSig) // Si se encuentra el elemento de U en el estado se sale if (pPos->Dato == pPos2->Dato) break; // sino, pPos valdrá 0 al salir del for y al menos unelemento // de U no está en el actual

if (pPos == 0) break; // salir, este estado no es igual alactual } // si U coincide con el estado actual, el estado no es nuevo if (pPos2 == 0) { // si todos los elementos de U están en elestado U->Vaciar(); // apuntado por pAuxEst, eliminar U y usarése. delete U; U = 0;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

364

Page 365: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

break; // salir del for, estado repetido } } // si pAuxEst == 0 el estado es nuevo if (pAuxEst == 0) { // crear un estado nuevo pAuxEst = new NodoLSE<Estado>; if (pAuxEst == 0) { // falta memoria delete U; delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbolsintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } pAuxEst->Dato.Pos = U; // se usa U, posiciones del estado U = 0; // y U se pone a 0 para la siguiente iteración pAuxEst->Dato.Id = NumEst++; pAuxEst->Dato.Tran = new Ent16ns[NumHoja]; if (pAuxEst->Dato.Tran == 0) { // falta memoria delete pAuxEst->Dato.Pos; // antes era U delete pAuxEst; delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbolsintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } for (i = 0; i < NumHoja; ++i) pAuxEst->Dato.Tran[i] = TNDEF; // enganchar estado al final de la lista de estados pFinal->pSig = pAuxEst; pFinal = pAuxEst; } // Del actual se transiciona al estado apuntado por pAuxEst. pEstAct->Dato.Tran[c] = pAuxEst->Dato.Id; } else { // no hay transición para el caracter c, U es vacío delete U; U = 0; } } // for (c = ...

pEstAct = pEstAct->pSig; // avanzar al siguiente estado } // while

afd = new AutomFinDet; if (afd == 0) { delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } apu = 0;

afd->ExpRegular = ExpRegular; afd->Caracter = 0; afd->NumCar = MaxCar;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

365

Page 366: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

afd->Transicion = 0; // AutomFinDet no tiene constructor por defecto afd->EstFinales = 0; // " " Ent16ns * Transicion, * EstFinales, NumEstFinales, * TranEstAct;

Transicion = new Ent16ns[NumEst * MaxCar]; if (Transicion == 0) { Vaciar(); delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } afd->Transicion = Transicion;

EstFinales = new Ent16ns[NumEst + 1]; if (EstFinales == 0) { Vaciar(); delete raiz; // árbol sintáctico Hoja.Vaciar(); // lista de descriptores de hojas del árbol sintáctico Caracter.Vaciar(); TablaIdent.Vaciar(); EstadosD.Vaciar(); // Conjunto de estados delete [] Sig; // Vector de SiguientePos(h) para cada hoja h return 0; } afd->EstFinales = EstFinales;

for (pEstAct = EstadosD.Entrada, i = 0, NumEstFinales = 0; pEstAct != 0; pEstAct = pEstAct->pSig) { // Copiar el vector de transiciones del estado actual a la // tabla de transiciones que se está armando. TranEstAct = pEstAct->Dato.Tran; for (j = 0; j < MaxCar; ++j, ++i) Transicion[i] = TranEstAct[j];

// Luego verificar si el estado actual es un estado final for (pPos = pEstAct->Dato.Pos->Entrada; pPos != 0; pPos = pPos->pSig){ for (pHoja = Hoja.Entrada; pHoja != 0; pHoja = pHoja->pSig) // si encuentra el descriptor de la hoja salir if (pPos->Dato == pHoja->Dato.Id) break; if (pHoja != 0 && pHoja->Dato.IdCar == MaxCar) { // se incrementa el número de estados finales y se guarda envector // de estados finales. EstFinales[++NumEstFinales] = pEstAct->Dato.Id; break; // salir del for, ya se sabe que el estado actual es final } } }

EstFinales[0] = NumEstFinales;

// ahora realizar una copia de los caracteres encontrados en la exp reg char ** pvcar; Ascii0 * pCarI; pvcar = new char *[MaxCar]; if (pvcar != 0) { for (i = 0; i < MaxCar; ++i) { pCarI = Caracter.DatoNodoI(i); if (pCarI != 0) { pvcar[i] = new char[pCarI->Long() + 1]; if (pvcar[i] != 0)

Códigos Fuentes de la Biblioteca ExpReg v 1.x

366

Page 367: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

strncpy(pvcar[i], *pCarI, pCarI->Long() + 1); } } afd->Caracter = (const char **) pvcar; }

resultado = 1;

// Eliminación de la memoria utilizada por este módulo (se realiza en // orden inverso al que aparecieron las variables):

// Conjunto de estados EstadosD.Vaciar(); // Vector de conjuntos SiguientePos(h) para cada hoja h delete [] Sig; // árbol sintáctico delete raiz; // lista de descriptores de hojas del árbol sintáctico Hoja.Vaciar(); // conjunto de caracteres que aparecieron en la expresión regular Caracter.Vaciar(); // Tabla de identificadores TablaIdent.Vaciar();

return resultado;}

21.15 SECESC1.CMM

// secesc1.cmm Jue 19 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

static const char * cad[] = { "\\a", // campana, 7 "\\b", // backspace, 8 "\\t", // tab, 9 "\\n", // nueva l¡nea, 10 "\\v", // tab vertical, 11 "\\f", // salto de p gina, 12 "\\r", // retorno de carro, 13 "\\\\", // \, 92 "\\\'", // comilla simple, 39 "\\\"" // comilla doble, 34};

const char * CadSecEscape( char c ) { register const char * res; if (c >= 7 && c <= 13) res = cad[c-7]; else if (c == '\\') res = cad[7]; else if (c == '\'') res = cad[8]; else if (c == '\"') res = cad[9]; else res = 0; return res;}

char CarSecEscape( const char * pCad ) { if (*pCad != '\\') return 0; register char c; switch ( *(pCad+1) ) { case 'a': c = '\a'; break; case 'b': c = '\b'; break;

Códigos Fuentes de la Biblioteca ExpReg v 1.x

367

Page 368: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

case 't': c = '\t'; break; case 'n': c = '\n'; break; case 'v': c = '\v'; break; case 'f': c = '\f'; break; case 'r': c = '\r'; break; case '\\': c = '\\'; break; case '\'': c = '\''; break; case '\"': c = '\"'; break; default: c = 0; } return c;}

21.16 SECESC2.CMM

// secesc2.cmm Jue 19 Ene 95

// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include <archivo.h># include "expreg.h"

int ImprCaracter( Archivo & arch, char c ) { const char * carsecesc; if (! c) return 0; carsecesc = CadSecEscape(c); if (carsecesc != 0) arch << carsecesc; else arch << c;

return CodError;}

int ImprCadena( Archivo & arch, const char * cad ) { register const char * p; if ((p = cad) == 0) return 0; while (*p) ImprCaracter(arch, *p++); return 0;}

21.17 SECESC3.CMM

// secesc3.cmm Vie 20 Ene 95// Copyright (c) 1995 by Domingo Becker.// All rights reserved.

# include "expreg.h"

int CambSecEsc( char * pCad ) { if (pCad == 0) return 0; register char * p, * q, carsecesc;

for (p = pCad; *p; ++p) if (*p == '\\') { // cambiar '\Eabc' a 'eabc' carsecesc = CarSecEscape(p); // cambia \E en e if (carsecesc) { *p = carsecesc; // cambia '\Eabc' en 'eEabc' for (q = p+1; *q; ++q) // cambia 'eEabc' en 'eabc' *q = *(q+1); }

Códigos Fuentes de la Biblioteca ExpReg v 1.x

368

Page 369: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

} return 1;}

Códigos Fuentes de la Biblioteca ExpReg v 1.x

369

Page 370: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 22: Códigos Fuentes de AFD v 3.x

AFD v 3.x, al igual que las versiones anteriores, ha sido diseñado comoun programa del usuario que hace uso de la biblioteca ExpReg de soporte parala generación de autómatas finitos determinísticos. De esta manera es posiblela reutilización del generador de AFDs en cualquier programa del usuario.

Esta implementación es dependiente del sistema operativo. Los módulosfuente aquí presentados pueden ser compilados con Borland C++ paraWindows (4.02 o posterior) o para OS/2 (2.0 o posterior). Para el modo gráficose utiliza la biblioteca OWL v 2.x que viene incluida en esos compiladores,ganando así portabilidad entre Windows y Presentation Manager. Para el modocaracter se utiliza la biblioteca BCE, ganando así la portabilidad a cualquiersistema operativo que disponga de una versión de BCE.

A los efectos de no repetir código fuente dentro de este trabajo, cuandosea aplicable, se introducirán referencias hacia otras partes dentro de estedocumento, en donde era oportuno incluirlos.

22.1 AFDD.CMM

Se puede generar una aplicación a partir de este módulo, compilándolo yencadenándolo con la biblioteca BCE, la biblioteca de soporte ExpReg y lasbibliotecas estándar.

Este módulo no debe ser incluídos con el resto de módulos presentadoen este capítulo.

Esta implementación está basada en la que se propone en la sección 6.7.

// afdd.cmm 23Feb96// Implementación de la versión para DOS, OS/2 modo caracter y Windows 95// y NT modo caracter de AFD

# include "expreg.h"# include <archivo.h>

int main(int nArg, char * cArg[]) { salida << "AFD v 3.4 para modo caracter (Feb 96)\nD.E.Becker Tel (085)22-2488/39-0567\n";

if (nArg < 2) { salida << "Falta el nombre del archivo con la expresion regular"; return 1;

}

// Determinar cadenas postfijos de los nombres: const char * PostfijoObj, * PostfijoSubObj;

Códigos Fuentes de AFD v 3.x

370

Page 371: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

PostfijoObj = cArg[2]; PostfijoSubObj = nArg > 3 ? cArg[3] : PostfijoObj;

// Cargar archivo en memoria: ArchivoSO arch; Ent16ns tam; Ascii0 texto; if (arch.Abrir(cArg[1], MA_L, MD_BIN)) {

salida << "ERROR al intentar abrir " << cArg[1] << "\n"; return 1;

}

tam = (Ent16ns) arch.Tam(); if (! texto.Reasignar(tam + 1)) {

salida << "Falta memoria para cargar la expresión regular enmemoria.\n";

return 1; }

if (arch.Leer(texto, tam), CodError) { salida << "ERROR al intentar leer el archivo de entrada."; return 1;

} *texto[tam] = 0;

if (! texto.Long()) { salida << "ERROR: el archivo no contiene una expresion regular."; return 1;

}

// Probar generar el AFD a partir del texto fuente: ExpReg er; Ascii0 CadPosErr; if (! er.Reasignar(texto, CadPosErr)) {

salida << "ERROR de sintaxis en la expresion regular:\n" <<CadPosErr;

return 1; }

// Guardar fuente C++ if (! er.ImprFuente(NomExt(cArg[1], ".cmm"), PostfijoObj,PostfijoSubObj))

salida << "Error al abrir archivo C++.\n";

// Guardar archivo de texto con autómata arch.Cerrar(); if (arch.Abrir(NomExt(cArg[1], ".txt"), MA_E, MD_TXT))

salida << "No se genero archivo de texto.\n"; else {

er.Imprimir(arch); arch.Cerrar();

}

// Mensajes finales: salida << "Automata generado sin problemas.\n"; salida << NomExt(cArg[1], ".cmm") << " contiene el fuente C++.\n"; salida << NomExt(cArg[1], ".txt") << " contiene el AFD en formatolegible.\n";

salida << "\nGracias por usar AFD.";

return 0;}

Códigos Fuentes de AFD v 3.x

371

Page 372: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

22.2 AFDEDTVW.CMM

/* Project AFD Copyright © 1995. All Rights Reserved.

SUBSYSTEM: afd.exe Application FILE: afdedtvw.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Source file for implementation of AFDEditView (TEditView). */

#include <owl\owlpch.h>#pragma hdrstop

#include "afdapp.h"#include "afdedtvw.h"

#include <stdio.h>

# include "dlgdatos.h"# include "dlgerror.h"

# ifndef __ASCII0_H# include <ascii0.h># endif

# ifndef __ARCHIVO_H# include <archivo.h># endif

# ifndef __EXPREG_H# include "expreg.h"# endif

//{{AFDEditView Implementation}}

//// Build a response table for all messages/commands handled// by AFDEditView derived from TEditView.//DEFINE_RESPONSE_TABLE1(AFDEditView, TEditView)//{{AFDEditViewRSP_TBL_BEGIN}} EV_WM_GETMINMAXINFO, EV_COMMAND(CM_GENERARAFD, GenerarAFD),//{{AFDEditViewRSP_TBL_END}}END_RESPONSE_TABLE;

//////////////////////////////////////////////////////////// AFDEditView// ==========// Construction/Destruction handling.AFDEditView::AFDEditView (TDocument& doc, TWindow* parent) : TEditView(doc, parent){ // INSERT>> Your constructor code here.

}

Códigos Fuentes de AFD v 3.x

372

Page 373: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

AFDEditView::~AFDEditView (){ // INSERT>> Your destructor code here.

}

//// Paint routine for Window, Printer, and PrintPreview for a TEditViewclient.//void AFDEditView::Paint (TDC& dc, bool, TRect& rect){ AFDApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), AFDApp); if (theApp) { // Only paint if we're printing and we have something to paint,otherwise do nothing. if (theApp->Printing && theApp->Printer && !rect.IsEmpty()) { // Use pageSize to get the size of the window to render into.For a Window it's the client area, // for a printer it's the printer DC dimensions and for printpreview it's the layout window. TSize pageSize(rect.right - rect.left, rect.bottom -rect.top);

HFONT hFont = (HFONT)GetWindowFont(); TFont font("Arial", -12); if (hFont == 0) dc.SelectObject(font); else dc.SelectObject(TFont(hFont)); TEXTMETRIC tm; int fHeight = (dc.GetTextMetrics(tm) == true) ? tm.tmHeight +tm.tmExternalLeading : 10; // How many lines of this font can we fit on a page. int linesPerPage = MulDiv(pageSize.cy, 1, fHeight); if (linesPerPage) { TPrintDialog::TData &printerData =theApp->Printer->GetSetup();

int maxPg = ((GetNumLines() / linesPerPage) + 1.0);

// Compute the number of pages to print. printerData.MinPage = 1; printerData.MaxPage = maxPg;

// Do the text stuff: int fromPage = printerData.FromPage == -1 ? 1 :printerData.FromPage; int toPage = printerData.ToPage == -1 ? 1 :printerData.ToPage; char buffer[255]; int currentPage = fromPage;

while (currentPage <= toPage) { int startLine = (currentPage - 1) * linesPerPage; int lineIdx = 0; while (lineIdx < linesPerPage) { // If the string is no longer valid then there'snothing more to display. if (!GetLine(buffer, sizeof(buffer), startLine +lineIdx))

Códigos Fuentes de AFD v 3.x

373

Page 374: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

break; dc.TabbedTextOut(TPoint(0, lineIdx * fHeight),buffer, strlen(buffer), 0, NULL, 0); lineIdx++; } currentPage++; } } } }}

void AFDEditView::EvGetMinMaxInfo (MINMAXINFO far& minmaxinfo){ AFDApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), AFDApp); if (theApp) { if (theApp->Printing) { minmaxinfo.ptMaxSize = TPoint(32000, 32000); minmaxinfo.ptMaxTrackSize = TPoint(32000, 32000); return; } } TEditView::EvGetMinMaxInfo(minmaxinfo);}

void AFDEditView::GenerarAFD (){ // INSERT>> Your code here. // Primero sacar el texto del TEditView Ent16ns tam = GetTextLen() + 1; Ascii0 cad(tam), CadPosErr; if (! GetText(cad, tam)) return; // si no hay texto editado

// Crear una ventana de diálogo para pregunar más datos: OtrosDatosAFD * pdlg = new OtrosDatosAFD(this); Parent->GetWindowTextTitle(); pdlg->ArchTXT = Parent->Title; if (pdlg->Execute() == IDCANCEL) { MessageBox("Autómata no generado.", "OBSERVACION", MB_OK | MB_ICONINFORMATION); return; }

// Probar generar el AFD a partir del texto fuente: ExpReg er; if (! er.Reasignar(cad, CadPosErr)) { TDlgError * pDlgError = new TDlgError(this); pDlgError->Cad = CadPosErr; pDlgError->Execute(); delete pDlgError; return; }

// Guardar fuente C++ if (pdlg->GenerarCMM && pdlg->ArchCMM.Long() && ! er.ImprFuente(pdlg->ArchCMM, pdlg->PostfijoAFD,pdlg->PostfijoResto)) { MessageBox("Error al abrir archivo C++.", "ERROR", MB_ICONHAND | MB_OK); return; }

// Guardar archivo de texto con autómata ArchivoSO arch;

Códigos Fuentes de AFD v 3.x

374

Page 375: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

if (! pdlg->ArchTXT.Long() || arch.Abrir(pdlg->ArchTXT, MA_E, MD_TXT)){ MessageBox("No se generó archivo de texto.", "ERROR", MB_ICONHAND | MB_OK); return; } er.Imprimir(arch); arch.Cerrar();

// Mensaje final MessageBox("Autómata Finito Determinístico\ngenerado sin problemas.", "Resultado", MB_OK | MB_ICONINFORMATION);}

22.3 DLGDATOS.H

#if !defined(__dlgdatos_h) // Sentry, use file only if it'snot already included.#define __dlgdatos_h

/* Project afd Copyright © 1995. All Rights Reserved.

SUBSYSTEM: afd.apx Application FILE: dlgdatos.h AUTHOR: Domingo Eduardo Becker

OVERVIEW ======== Class definition for OtrosDatosAFD (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include <owl\checkbox.h>

#include "afdapp.rh" // Definition of all resources.

# ifndef __ASCII0_H# include <ascii0.h># endif

//{{TDialog = OtrosDatosAFD}}struct OtrosDatosAFDXfer {//{{OtrosDatosAFDXFER_DATA}} bool ChkGenCMM;//{{OtrosDatosAFDXFER_DATA_END}}};

class OtrosDatosAFD : public TDialog {public: OtrosDatosAFD (TWindow* parent, TResId resId = IDD_DLGMASDATOS,TModule* module = 0); virtual ~OtrosDatosAFD ();

Ascii0 ArchCMM, ArchTXT, PostfijoAFD, PostfijoResto; Ent8 GenerarCMM;

Códigos Fuentes de AFD v 3.x

375

Page 376: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

//{{OtrosDatosAFDVIRTUAL_BEGIN}}public: virtual void SetupWindow ();//{{OtrosDatosAFDVIRTUAL_END}}

//{{OtrosDatosAFDXFER_DEF}}protected: TCheckBox *ChkGenCMM;

//{{OtrosDatosAFDXFER_DEF_END}}

//{{OtrosDatosAFDRSP_TBL_BEGIN}}protected: void Aceptar ();//{{OtrosDatosAFDRSP_TBL_END}}DECLARE_RESPONSE_TABLE(OtrosDatosAFD);}; //{{OtrosDatosAFD}}

#endif // __dlgdatos_h sentry.

22.4 DLGDATOS.CMM

El diseño del diálogo donde se introducen los datos faltantes es elsiguiente:

Fig. 38 Diseño del diálogo para la entrada de datos adicionalesusados por AFD v 3.x

/* Project afd Copyright © 1995. All Rights Reserved.

SUBSYSTEM: afd.apx Application FILE: dlgdatos.cmm AUTHOR: Domingo Eduardo Becker

OVERVIEW

Códigos Fuentes de AFD v 3.x

376

Page 377: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

======== Source file for implementation of OtrosDatosAFD (TDialog). */

#include <owl\owlpch.h>#pragma hdrstop

#include "dlgdatos.h"

# include <archivo.h>

//// Build a response table for all messages/commands handled// by the application.//DEFINE_RESPONSE_TABLE1(OtrosDatosAFD, TDialog)//{{OtrosDatosAFDRSP_TBL_BEGIN}} EV_BN_CLICKED(IDOK, Aceptar),//{{OtrosDatosAFDRSP_TBL_END}}END_RESPONSE_TABLE;

//{{OtrosDatosAFD Implementation}}

static OtrosDatosAFDXfer OtrosDatosAFDData;

OtrosDatosAFD::OtrosDatosAFD (TWindow* parent, TResId resId, TModule*module): TDialog(parent, resId, module){//{{OtrosDatosAFDXFER_USE}} ChkGenCMM = new TCheckBox(this, IDC_GENCMM, 0);

SetTransferBuffer(&OtrosDatosAFDData);//{{OtrosDatosAFDXFER_USE_END}}

// INSERT>> Your constructor code here.

}

OtrosDatosAFD::~OtrosDatosAFD (){ Destroy();

// INSERT>> Your destructor code here.

}

void OtrosDatosAFD::SetupWindow (){ TDialog::SetupWindow();

// INSERT>> Your code here. ArchTXT = NomExt(ArchTXT, ".TXT"); ArchCMM = NomExt(ArchTXT, ".CMM"); SetDlgItemText(IDC_ARCHTXT, ArchTXT); SetDlgItemText(IDC_FUENTECMM, ArchCMM); ChkGenCMM->SetCheck(BF_CHECKED);}

void OtrosDatosAFD::Aceptar ()

Códigos Fuentes de AFD v 3.x

377

Page 378: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

{ // INSERT>> Your code here. ArchTXT.Reasignar(200); GetDlgItemText(IDC_ARCHTXT, ArchTXT, ArchTXT.TamBlq()); ArchCMM.Reasignar(200); GetDlgItemText(IDC_FUENTECMM, ArchCMM, ArchCMM.TamBlq()); if (PostfijoAFD.Reasignar(50)) GetDlgItemText(IDC_POSTFIJOAFD, PostfijoAFD, PostfijoAFD.TamBlq()); if (PostfijoResto.Reasignar(50)) GetDlgItemText(IDC_POSTFIJORESTO, PostfijoResto,PostfijoResto.TamBlq()); if (! PostfijoResto.Long()) PostfijoResto = PostfijoAFD; GenerarCMM = ChkGenCMM->GetCheck() == BF_CHECKED;

CmOk();}

22.5 DLGERROR.CMM

Fue incluido en la sección 20.4.

Códigos Fuentes de AFD v 3.x

378

Page 379: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 23: Bibliografía

23.1 Principales (por orden de importancia)

Alfred Aho - Ravi Sethi - Jeffrey Ullman [1990]. "Compiladores: PrincipiosTécnicas y Herramientas". Addison-Wesley Iberoamericana.

Sanchis Llorca - Galán Pascual [1986]. "Compiladores: Teoría yConstrucción". Paraninfo.

Alfred Aho - Jeffrey Ullman [1977]. "Principles of Compiler Design".Addison-Wesley.

Manuales del Programador del Sistema Operativo XENIX. Microsoft Corp.

Bjarne Stroustrup [1992]. "The C++ Programming Language - 2nd Edition".Addison-Wesley.

Manuales del Programador del Borland C++ 4.02 para Windows. Borland Intl.Inc.

Manuales del Programador del Borland C++ 2.0 para OS/2. Borland Intl. Inc.

Manuales del Programador del Borland C++ 4.5 para Windows. Borland Intl.Inc.

Manuales del Programador de Paradox 4.5 para Windows. Borland Intl. Inc.

Manuales del Programador de dBase V para Windows. Borland Intl. Inc.

"Reference Guide" del Borland Visual Solutions Pack Volume 1 paraWindows. Capítulo 51: "SQL Primer", págs. 665 a 674. Borland Intl. Inc.

J. Tamagnini [1994]. "Un generador de analizadores sintácticos recursivosdescendentes". Tesis de Grado. Universidad Católica de Santiago del Estero.

Allen Holub [1990]. "Compiler Design in C". Prentice Hall.

Christian Nique [1985]. "Introducción metódica a la gramática generativa".Ediciones Cátedra.

Bibliografía

379

Page 380: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Bjarne Stroustrup [1994]. "The design and Evolution of C++". AddisonWesley. Págs. 337 a 381.

23.2 Secundarios (por orden alfabético)

A. V. Aho y S. C. Johnson [1974]. "LR Parsing". Computing Surveys 6:2,págs 99-124.

A. V. Aho, S. C. Johnson y J. D. Ullman [1977]. "Code generation forexpressions with common subexpressions". Journal ACM 14:1, págs. 146-160.

A. V. Aho, B. W. Kernighan y P. J. Weinberger [1979]. "AWK - a patternscanning and processing language". Software - Practice and Experience 9:4,págs. 267-280.

A. V. Aho y J. D. Ullman [1972]. "The Theory of Parsing, Translation andCompiling, Vol I: Parsing". Prentice-Hall.

A. V. Aho y J. D. Ullman [1973a]. "The Theory of Parsing, Translation andCompiling, Vol II: Compiling". Prentice-Hall.

A. V. Aho y J. D. Ullman [1973b]. "A technique for speeding up LR(k)parsers". SIAM J. Computing 2:2, págs. 106-127.

T. Anderson, J. Eve y J. J. Horning [1973]. "Efficient LR(1) Parsers". ActaInformatica 2:1, págs. 12-39.

R. C. Backhouse [1976]. "An alternative aproach to the improvement of LRparsers". Acta Informatica 6:3, págs. 277-296.

J. W. Backus [1981]. "Transcript of presentation on the history of Fortran I, IIand III". En Wexelblat [1981], págs 45-66.

F. L. Bauer [1976]. "Historical remarks on compiler construction". en Bauer yEichel [1976], págs 603-621. Suplemento de Ershov. A. P. págs 622-626.

F. L. Bauer y J. Eichel [1976]. "Compiler Construction: An AdvancedCourse". 2da Edición. Lecture Notes in Computer Science 21,Springer-Verlag, Berlín.

Bibliografía

380

Page 381: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

B. M. Brosgol [1974]. "Deterministic Translation Grammars". Tesis doctoral,TR 3-74. Universidad de Harvard, Cambridge, Massachusetts.

Noam Chomsky [1956]. "Three models for the description of language". IRETrans. on Information Theory IT-2:3, págs. 113-124.

M. E. Conway y W. L. Maxwell [1963]. "CORC - the Cornell computinglanguage". Comm. ACM 6:6, págs. 317-321.

M. E. Conway y T. R. Wilcox [1973]. "Design and implementation of adiagnostic compiler for PL/I". Comm. ACM 16:3, págs. 169-179.

A. J. Demers [1975]. "Elimination of single productions and merging ofnonterminal symbols in LR(1) grammars". Journal of Computer Languages1:2, págs. 105-119.

F. DeRemer [1969]. "Practical Translators for LR(k) Languages". Tesisdoctoral, M.I.T., Cambridge, Massachusetts.

F. DeRemer [1971]. "Simple LR(k) grammars". Comm. ACM 14:7, págs.453-460.

J. Earley [1970]. "An efficient context-free parsing algorithm". Comm. ACM13:2, págs. 94-102.

J. Earley [1975]. "Ambiguity and precedence in syntax description". ActaInformática 4:2, págs. 183-192.

S. I. Feldman [1979]. "Implementation of a portable Fortran 77 compilerusing modern tools". ACM SIGPLAN Notices 14:8, págs 255-265.

J. M. Foster [1968]. "A syntax improving program". Computer Journal 11:1,págs. 31-34.

C. A. R. Hoare [1962]. "Report on the Elliott ALGOL translator". ComputerJournal 5:2, págs. 127-129.

D. A. Huffman [1954]. "The synthesis of sequential machines". J. FranklinInst. 257, págs. 3-4, 161, 190, 275-303.

P. Z. Ingerman [1967]. "Panini-Backus form suggested". Comm. ACM 10:3,pág. 137.

Bibliografía

381

Page 382: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

E. T. Irons [1961]. "A syntax directed compiler for ALGOL 60". Comm.ACM 4:1, págs 51-55.

J. F. Jarvis [1976]. "Feature recognition in line drawings using regularexpressions". Proc. 3rd Intl. Joint Conf. on Pattern Recognition, págs.189-192.

W. L. Johnson, J. H. Porter, S. I. Ackley y D. T. Ross [1968]. "Automaticgeneration of efficient lexical processors using finite state techniques".

M. L. Joliat [1976]. "A simple technique for partial elimination of unitproductions from LR(k) parser tables". IEEE Trans. on Computers C-25:7,págs. 763-764.

T. Kasami [1965]. "An efficient recognition and syntax analysis algorithm forcontext-free languages". AFCRL-65-758, Air Force Cambridge ResearchLaboratory, Bedford, Massachusetts.

B. W. Kernigan y R. Pike [1984]. "The UNIX Programming Environment".Prentice-Hall.

S. C. Kleene [1956]. "Representation of events in nerve nets". en Shannon yMcCarthy [1956], págs. 3-40.

D. E. Knuth [1964]. "Backus Normal Form vs. Backus Naur Form". Comm.ACM 7:12, págs. 735 y 736.

D.E. Knuth[1965]. "On the translation of languages from left to right".Information and Control 8:6, págs. 607-639.

D.E. Knuth [1971]. "Top-down syntax analysis". Acta Informatica 1:2, págs.79-110.

D.E. Knuth [1973]. "The Art of Computer Programming: Vol 1 2nd Edition,Fundamental Algorithms", Addison-Wesley.

A. J. Korenjak [1969]. "A practical method for constructing LR(k)processors". Comm ACM 12:11, págs. 613-623.

M. E. Lesk [1975]. "Lex - a lexical analyzer generator". Computing ScienceTechnical Report 39, AT&T Bell Laboratories.

Bibliografía

382

Page 383: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

J. K. Levy [1975]. "Automatic correction of syntax errors in programminglanguages". Acta Informatica 4, págs. 271-292.

P. M. Lewis II, D. J. Rosenkrantz y R. E. Stearns [1976]. "Compiler DesignTheory". Addison-Wesley.

P. M. Lewis II y R. E. Stearns [1968]. "Syntax-directed transduction". J.ACM 15:3, págs. 465-488.

P. Lucas [1961]. "The structure of formula translators". ElektronischeRechenanlagen 3, págs 159-166.

J. McCarthy [1963]. "Towards a mathematical science of computation".Information Processing 1962, págs 21-28.

R. M. McClure [1965]. "TMG - a syntax-directed compiler". Proc. 20th ACMNational Conf., págs. 262-274.

W. S. McCullough y W. Pitts [1943]. "A logical calculus of the ideasimmanent in nervous activity". Bulletin of Math. Biophysics 5, págs. 115-133.

R. McNaughton y H. Yamada [1960]. "Regular expressions and state graphsfor automata". IRE Trans. on Electronic Computers EC-9:1, págs. 38-47.

E. F. Moore [1956]. "Gedanken experiments in sequential machines". EnShannon y McCarthy [1956], págs 129-153.

P. G. Moulton y M. E. Muller [1967]. "DITRAN - a compiler emphasizingdiagnostics". Comm. ACM 10:1, págs. 52-54.

P. Naur [1963]. "Revised report on the algorithmic language ALGOL 60".Comm. ACM 6:1, págs. 1-17.

D. Pager [1977]. "Eliminating unit productions from LR(k) parsers". ActaInformatica 9, págs. 249-268.

V. R. Pratt [1973]. "Top-down operator precedence". ACM Symposium onPrinciples of Programming Languages, págs. 41-51.

P. Purdom y C. A. Brown [1980]. "Semantic routines and LR(k) parsers".Acta Informatica 14:4, págs. 299-315.

Bibliografía

383

Page 384: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

M. O. Rabin y D. Scott [1959]. "Finite automata and their decisionproblems". IBM Journal of Research and Development 3:2, págs. 114-125.

J. Röhrich [1980]. "Methods for the automatic construction of error correctingparsers". Acta Informatica 13:2, págs. 115-139.

D. J. Rosenkrantz y R. E. Stearns [1970]. "Properties of Deterministicstop-down grammars". Information and Control 17:3, págs. 226-256.

D. V. Schorre [1964]. "Meta-II: a syntax-oriented compiler writing language".Proc. 19th ACM National Conf., DI., 3-1 - DI. 3-11.

C. Shannon y J. McCarthy [1956]. "Automata Studies". Princeton UniversityPress.

E. Soisalon-Soininem [1980]. "On the space optimizing effect of eliminatingsingle productions from LR parsers". Acta Informatica 12, págs. 157-174.

E. Soisalon-Soininem y E. Ukkonen [1979]. "A method for transforminggrammars into LL(k) form". Acta Informatica 12, págs. 339-369.

R. E. Stearns [1971]. "Deterministic top-down parsing". Proc. 5th AnnualPrinceton Conf. on Information Sciences and Systems, págs. 182-188.

J. Strong, J. H. Wegstein, A. Tritter, J. Olsztyn, O. Mock y T. Steel [1958]."The problem of programming communication with changing machines: aproposed solution". Comm. ACM 1:8 (agosto), págs 12-18. Segunda parte 1:9(setiembre), págs 9-15. Informe del Comité sobre lenguas universales.

K. C. Tai [1978]. "Syntactic error correction in programming languages".IEEE Trans. Software Engineering SE-4:5, págs. 414-425.

T. Tokuda [1981]. "Eliminating unit reductions from LR(k) parsers usingminimum contexts". Acta Informatica 15, págs. 447-470.

D. A. Watt [1977]. "The parsing problem for affix grammars". ActaInformatica 8, págs. 1-20.

J. H. Wegstein [1981]. "Notes on ALGOL 60". en Wexelblat [1981], págs.126-127.

R. L. Wexelblat [1981]. "History of Programming Languages". AcademicPress. New York.

Bibliografía

384

Page 385: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

D. Wood [1969]. "The Theory of left factored languages". Computer Journal12:4, págs. 349-356.

D. H. Younger [1967]. "Recognition and parsing of context-free languages intime n3 ". Information and Control 10:2, págs. 189-208.

Bibliografía

385

Page 386: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

Capítulo 24: Conclusiones

Muchos trabajos de programación, incluyendo los trabajos complejoscomo por ejemplo el desarrollo de analizadores sintácticos, son tareasrepetitivas cuya ejecución podría automatizarse. Por ejemplo, nadie escribiríahoy en día en forma directa el código fuente para una interfase de un programaque trabaje en modo gráfico, sino que más bien usaría un programa que logenere a partir de especificaciones de alto nivel. Lo único que haría "a mano"es el desarrollo de las partes de la interfase que no fueron automatizadas por elgenerador de interfases. En el desarrollo de interfases es normal olvidarse deciertas restricciones de la interfase para el desarrollo de aplicaciones, lo queprovocará, en el mejor de los casos, que el programa se "cuelgue", y en el peor,que provoque una caida de toda una red (si se está trabajando en red).

Entonces, es evidente que, por más compleja que sea una tarea dedesarrollo de software, si la misma es automatizable se la debe automatizar.Pero, para que esto sea posible, el desarrollo de esos generadores de softwaretambién debe ser una tarea medianamente simple, de manera que no se pierdademasiado tiempo en su desarrollo (se debe recordar que los programadoresconstantemente trabajan contra reloj). Es poco común ver programadores denuestro medio que sigan esta técnica de trabajo (esto es, construir ungenerador para automatizar el desarrollo de software en las áreas que seaposible), y esto se debe, principalmente, a que en nuestro medio no haydisponible una herramienta que simplifique el desarrollo de tales traductoresque generarán, a partir de especificaciones de alto nivel, código fuente queejecute tareas rutinarias. Por ejemplo, en un sistema de bases de datos, aunquela estructura del registro de un archivo sea distinto para diferentesaplicaciones, los módulos de alta-bajas-modificaciones son muy similares.

El aporte más grande de este trabajo quizás sea el de simplificar eldesarrollo de tales traductores para generar partes de programas. Antes, para laescritura de un traductor, un programador debía tener conocimientos de:gramáticas generativas, técnicas de análisis sintáctico, técnicas de análisislexicográfico, construcción de un analizador sintáctico, construcción de unanalizador lexicográfico y construcción del esquema de traducción, entre otrasde menor importancia. Mientras que, es objetivo de este trabajo que para eldesarrollo de un traductor, un programador solamente deba tenerconocimientos de: gramáticas generativas, construcción del esquema detraducción, conocimiento de la técnica de análisis sintáctico y de análisislexicográfico usada por los analizadores obtenidos a partir de los generadoresque se presentan, y conocimiento del lenguaje objeto usado (el C++). La parteteórica más compleja ha sido eliminada, y la que quedó requiere de poca

Conclusiones

386

Page 387: Ami Pro - TESISbce.no-ip.org/TesisDomingoBecker.pdf · generador de analizadores lexicográficos, que intentarán ser una buena ... En particular, se hace uso de templates (familias

inversión de tiempo para su aprendizaje; a tal efecto se incluye documentaciónlo suficientemente extensa en este trabajo como para poder orientar a cualquierprogramador que se inicie en el área, pero no se incluye el aprendizaje de C++,porque se asume que el mismo debe formar parte del conjunto de herramientasde cualquier programador universitario.

Los generadores presentados en este trabajo son, finalmente, un humildeaporte del autor a todos aquellos interesados en el uso de la Teoría de losLenguajes Formales en sus aplicaciones y para la simplificación del desarrollode las mismas.

Conclusiones

387