La implementación realizada consta de cinco clases. Tres
de ellas desarrollan una implementación genérica de los analizadores
ascendentes basados en tablas de desplazamiento/reducción. Las otras dos
clases desarrollan el analizador de tinto apoyándose en la implementación
genérica.
Las clases utilizadas en la implementación genérica son las siguientes:
-
tinto.ActionElement: Esta clase permite describir
el contenido de una celda de la tabla de acciones. Estas celdas pueden ser
acciones de desplazamiento, de reducción, de aceptación de la entrada o de
error. Los errores se representan en la tabla mediante referencias nulas.
Por tanto, la clase se utiliza para representar acciones de desplazamiento,
de reducción y de aceptación. La clase contiene dos campos: type,
que indica el tipo de acción (por medio de una de las tres constantes
definidas en la clase: ACCEPT, SHIFT o REDUCE), y value, que
contiene el valor asociado a la acción (estado a apilar en el caso de
desplazamiento e índice de la regla a reducir en caso de reducción). Los
valores de estos campos se fijan en el constructor y se obtienen de los
métodos getType() y getValue().
-
tinto.SintaxException: Esta clase describe
un error sintáctico. Los errores sintácticos se producen cuando el algoritmo
de desplazamiento/reducción lee una acción nula. El error contiene
información sobre la fila y columna del token en el que se produce el error,
la categoría del token encontrado y la lista de los tokens esperados.
-
tinto.SLRParser: Esta clase desarrolla el
algoritmo de desplazamiento/reducción de manera genérica. Los campos de la
clase son los siguientes:
-
lexer: contiene el analizador
léxico que proporciona los tokens a analizar.
-
nextToken:
contiene el último token leído del analizador léxico;
-
stack: contiene la pila de estados usada por el algoritmo de
desplazamiento/reducción. Los estados se representan en la pila por objetos
Integer;
-
actionTable: almacena la tabla de
acciones en forma de matriz de objetos ActionElement. La matriz tiene tantas
filas como estados y tantas columnas como categorías léxicas. Este campo es
protected para que las extensiones de la clase puedan dar contenido a
la tabla;
-
gotoTable: almacena la tabla de IrA en
forma de matriz de enteros. La matriz tiene tantas filas como estados y tantas columnas
como símbolos no terminales. Eeste campo es protected para que las
extensiones de la clase puedan dar contenido a la tabla;
-
rule: contiene la información sobre las reglas de la gramática
en forma de matriz de enteros. La matriz tiene tantas
filas como reglas y dos columnas. La primera columna contiene el símbolo no terminal de la parte izquierda
de la regla. La segunda columna conmtiene el número de símbolos en la parte derecha
de la regla. Este campo es protected para que las extensiones de la
clase puedan dar contenido a las reglas.
Los métodos de la clase son los siguientes:
-
parse(Lexer): desarrolla el funcionamiento
del analizador de desplazamiento/reducción. La llamada a este método
permite introducir la referencia al analizador léxico. El contenido del
método consiste en inicializar la pila con el estado 0 y realizar
iteraciones del algoritmo de desplazamiento/reducción hasta encontrar un
error o una acción de aceptar.
-
step(): realiza una iteración del algoritmo
de desplazamiento/reducción, es decir, lee el estado de la cima de la pila,
considera el siguiente token y busca la celda correspondiente en la tabla de
acción. Si la celda es nula lanza un error sintáctico. Si la celda es una
acción de desplazamiento ejecuta el método shiftAction() y devuelve
false (para que el bucle de análisis continúe su ejecución). Si la
celda contiene una acción de reducción ejecuta el método reduceAction()
y devuelve false (para que el bucle de análisis continúe su
ejecución). Si la celda contiene una acción de aceptar devuelve true
para que finalice el bucle de análisis.
-
shiftAction(): realiza una acción de
desplazamiento, es decir, lee el siguiente token del analizador léxico y
apila el estado correspondiente.
-
reduceAction(): realiza una acción de
reducción, es decir: busca la regla a reducir; desapila tantos estados como
símbolos tenga la regla; estudia el estado de la cima de la pila; busca en
la tabla IrA la celda correspondiente al estado de la cima y al símbolo no
terminal de la regla; y apila el valor de la celda de la tabla IrA.
La implementación del analizador ascendente de Tinto se
desarrolla en dos clases:
-
tinto.SymbolConstants: es una interfaz que
define los códigos de los símbolos no terminales de la gramática. Esta
interfaz, al igual que TokenConstants, permite importar todos estos
códigos a cualquier clase con solo implementar la interfaz.
-
tinto.TintoParser: desarrolla el analizador
ascendente del lenguaje Tinto. La gramática SLR utilizada es
ésta. El autómata reconocedor de
prefijos viables asociado a la gramática es
éste. Para generar la tabla SLR se
utilizan los conjuntos siguientes de cada símbolo, que son
éstos. La clase se limita a dar
contenido a los campos actionTable, gotoTable y rule de
la superclase SLRParser.
|