Los analizadores sintácticos SLR, LALR y LR pueden implementarse utilizando exactamente la misma maquinaria impulsada por tablas.
Básicamente, el algoritmo de análisis recopila el siguiente token de entrada T y consulta el estado actual S (y las tablas de reducción, GOTO y de anticipación asociadas) para decidir qué hacer:
- SHIFT: si la tabla actual dice SHIFT en el token T, el par (S, T) se inserta en la pila de análisis, el estado cambia de acuerdo con lo que dice la tabla GOTO para el token actual (por ejemplo, GOTO (T) ), se obtiene otro token de entrada T 'y el proceso se repite
- REDUCIR: Cada estado tiene 0, 1 o muchas reducciones posibles que pueden ocurrir en el estado. Si el analizador es LR o LALR, el token se compara con conjuntos de anticipación para todas las reducciones válidas para el estado. Si el token coincide con un conjunto de búsqueda anticipada para una reducción para la regla gramatical G = R1 R2 .. Rn, se produce una reducción y un desplazamiento de la pila: se llama a la acción semántica para G, la pila se abre n (de Rn) veces, el par ( S, G) se inserta en la pila, el nuevo estado S 'se establece en GOTO (G) y el ciclo se repite con el mismo token T. Si el analizador es un analizador SLR, hay como máximo una regla de reducción para el estado y, por lo tanto, la acción de reducción se puede hacer a ciegas sin buscar para ver qué reducción se aplica. Es útil para un analizador SLR saber si hay esuna reducción o no; esto es fácil de decir si cada estado registra explícitamente el número de reducciones asociadas con él, y ese recuento es necesario para las versiones L (AL) R en la práctica de todos modos.
- ERROR: Si no es posible SHIFT ni REDUCE, se declara un error de sintaxis.
Entonces, si todos usan la misma maquinaria, ¿cuál es el punto?
El valor pretendido en SLR es su simplicidad en la implementación; no tiene que examinar las posibles reducciones comprobando los conjuntos de anticipación porque hay como máximo uno, y esta es la única acción viable si no hay salidas SHIFT del estado. La reducción que se aplica se puede adjuntar específicamente al estado, por lo que la maquinaria de análisis de SLR no tiene que buscarla. En la práctica, los analizadores sintácticos L (AL) R manejan un conjunto de idiomas útilmente más grande y es tan poco trabajo extra de implementar que nadie implementa SLR excepto como un ejercicio académico.
La diferencia entre LALR y LR tiene que ver con el generador de tablas. Los generadores de analizadores sintácticos LR realizan un seguimiento de todas las posibles reducciones de estados específicos y su conjunto de anticipación preciso; termina con estados en los que cada reducción está asociada con su conjunto de anticipación exacto de su contexto izquierdo. Esto tiende a construir conjuntos de estados bastante grandes. Los generadores de analizadores sintácticos LALR están dispuestos a combinar estados si las tablas GOTO y los conjuntos de cabezales de búsqueda para reducciones son compatibles y no entran en conflicto; esto produce un número considerablemente menor de estados, al precio de no poder distinguir ciertas secuencias de símbolos que LR puede distinguir. Por lo tanto, los analizadores LR pueden analizar un conjunto de idiomas más grande que los analizadores LALR, pero tienen tablas de analizadores mucho más grandes. En la práctica, se pueden encontrar gramáticas LALR que están lo suficientemente cerca de los idiomas de destino como para que valga la pena optimizar el tamaño de la máquina de estado;
Entonces: los tres usan la misma maquinaria. SLR es "fácil" en el sentido de que puede ignorar una pequeña parte de la maquinaria, pero simplemente no vale la pena. LR analiza un conjunto más amplio de idiomas, pero las tablas de estado tienden a ser bastante grandes. Eso deja a LALR como la opción práctica.
Habiendo dicho todo esto, vale la pena saber que los analizadores GLR pueden analizar cualquier lenguaje sin contexto, utilizando maquinaria más complicada pero exactamente las mismas tablas (incluida la versión más pequeña utilizada por LALR). Esto significa que GLR es estrictamente más potente que LR, LALR y SLR; más o menos si puede escribir una gramática BNF estándar, GLR la analizará de acuerdo con ella. La diferencia en la maquinaria es que GLR está dispuesto a probar varios análisis cuando hay conflictos entre la tabla GOTO o los conjuntos de anticipación. (La forma en que GLR hace esto de manera eficiente es pura genialidad [no mía] pero no encajará en esta publicación de SO).
Eso para mí es un hecho enormemente útil. Construyo analizadores de programas y transformadores de código y los analizadores son necesarios pero "poco interesantes"; el trabajo interesante es lo que haces con el resultado analizado, por lo que la atención se centra en hacer el trabajo posterior al análisis. Usar GLR significa que puedo construir gramáticas funcionales con relativa facilidad, en comparación con piratear una gramática para entrar en la forma utilizable de LALR. Esto es muy importante cuando se trata de lidiar con idiomas no académicos como C ++ o Fortran, donde literalmente necesita miles de reglas para manejar bien todo el idioma y no quiere pasar su vida tratando de piratear las reglas gramaticales para cumplir con las limitaciones de LALR (o incluso LR).
Como una especie de ejemplo famoso, C ++ se considera extremadamente difícil de analizar ... por personas que realizan análisis LALR. C ++ es sencillo de analizar utilizando maquinaria GLR utilizando prácticamente las reglas proporcionadas en la parte posterior del manual de referencia de C ++. (Tengo precisamente un analizador de este tipo, y maneja no solo C ++ vainilla, sino también una variedad de dialectos de proveedores. Esto solo es posible en la práctica porque estamos usando un analizador GLR, en mi humilde opinión).
[EDITAR noviembre de 2011: hemos ampliado nuestro analizador para manejar todo C ++ 11. GLR lo hizo mucho más fácil de hacer. EDITAR agosto de 2014: ahora manejando todo C ++ 17. Nada se rompió ni empeoró, GLR sigue siendo el maullido del gato.]