Tanto los analizadores LR (0) como los SLR (1) son analizadores predictivos, direccionales y de abajo hacia arriba . Esto significa que
- Los analizadores intentan aplicar producciones a la inversa para reducir la oración de entrada al símbolo de inicio (de abajo hacia arriba )
- Los analizadores analizan la entrada de izquierda a derecha ( direccional )
- Los analizadores intentan predecir qué reducciones aplicar sin ver necesariamente toda la entrada ( predictiva )
Tanto LR (0) como SLR (1) son analizadores sintácticos de desplazamiento / reducción , lo que significa que procesan los tokens del flujo de entrada colocándolos en una pila y, en cada punto, cambiando un token empujándolo a la pila o reduciendo algunos secuencia de terminales y no terminales encima de la pila de regreso a algún símbolo no terminal. Se puede demostrar que cualquier gramática se puede analizar de abajo hacia arriba utilizando un analizador shift / reduce, pero ese analizador puede no ser determinista . Es decir, el analizador puede tener que "adivinar" si aplicar un cambio o una reducción, y puede terminar teniendo que retroceder para darse cuenta de que tomó la decisión incorrecta. No importa cuán poderoso sea el analizador de cambios / reducción determinista que construya, nunca podrá analizar todas las gramáticas.
Cuando se usa un analizador de cambio / reducción determinista para analizar una gramática que no puede manejar, resulta en cambios / reducción de conflictos o reducción / reducción de conflictos , donde el analizador puede entrar en un estado en el que no puede decir qué acción tomar. En un conflicto de cambio / reducción, no puede decir si debe agregar otro símbolo a la pila o realizar alguna reducción en los símbolos superiores de la pila. En un conflicto de reducción / reducción, el analizador sabe que necesita reemplazar los símbolos superiores de la pila con algunos no terminales, pero no puede decir qué reducción usar.
Pido disculpas si esta es una exposición larga, pero la necesitamos para poder abordar la diferencia entre el análisis sintáctico LR (0) y SLR (1). Un analizador LR (0) es un analizador de cambio / reducción que usa cero tokens de anticipación para determinar qué acción tomar (de ahí el 0). Esto significa que en cualquier configuración del analizador, el analizador debe tener una acción inequívoca para elegir, ya sea desplaza un símbolo específico o aplica una reducción específica. Si alguna vez hay dos o más elecciones para hacer, el analizador falla y decimos que la gramática no es LR (0).
Recuerde que los dos posibles conflictos de LR son cambio / reducción y reducción / reducción. En ambos casos, hay al menos dos acciones que el autómata LR (0) podría estar realizando y no puede decir cuál de ellas utilizar. Dado que al menos una de las acciones en conflicto es una reducción, una línea de ataque razonable sería intentar que el analizador sea más cuidadoso cuando realiza una reducción en particular. Más específicamente, supongamos que al analizador se le permite mirar el siguiente token de entrada para determinar si debe cambiar o reducir. Si solo permitimos que el analizador se reduzca cuando "tiene sentido" hacerlo (para alguna definición de "tiene sentido"), entonces podemos eliminar el conflicto haciendo que el autómata elija específicamente cambiar o reducir en un paso particular.
En SLR (1) ("LR simplificado (1)"), el analizador puede mirar una ficha de anticipación al decidir si debe cambiar o reducir. En particular, cuando el analizador quiere intentar reducir algo de la forma A → w (para el no terminal A y la cadena w), mira el siguiente token de entrada. Si ese token pudiera aparecer legalmente después del no terminal A en alguna derivación, el analizador se reduce. De lo contrario, no es así. La intuición aquí es que en algunos casos no tiene sentido intentar una reducción, porque dados los tokens que hemos visto hasta ahora y el próximo token, no hay forma posible de que la reducción sea correcta.
La única diferencia entre LR (0) y SLR (1) es esta capacidad adicional para ayudar a decidir qué acción tomar cuando hay conflictos. Debido a esto, cualquier gramática que pueda ser analizada por un analizador LR (0) puede ser analizada por un analizador SLR (1). Sin embargo, los analizadores de SLR (1) pueden analizar una mayor cantidad de gramáticas que LR (0).
Sin embargo, en la práctica, SLR (1) sigue siendo un método de análisis bastante débil. Más comúnmente, verá que se utilizan analizadores LALR (1) ("Lookahead LR (1)"). También funcionan tratando de resolver conflictos en un analizador LR (0), pero las reglas que utilizan para resolver conflictos son mucho más precisas que las utilizadas en SLR (1) y, en consecuencia, un número mucho mayor de gramáticas son LALR (1). que SLR (1). Para ser un poco más específicos, los analizadores de SLR (1) intentan resolver conflictos observando la estructura de la gramática para obtener más información sobre cuándo cambiar y cuándo reducir. Los analizadores sintácticos LALR (1) miran tanto la gramática como el analizador LR (0) para obtener información aún más específica sobre cuándo cambiar y cuándo reducir. Debido a que LALR (1) puede observar la estructura del analizador LR (0), puede identificar con mayor precisión cuándo ciertos conflictos son espurios.yacc
y bison
, de forma predeterminada, producir analizadores LALR (1).
Históricamente, los analizadores sintácticos LALR (1) se construían normalmente a través de un método diferente que se basaba en el analizador LR (1) mucho más potente, por lo que a menudo verá que LALR (1) se describe de esa manera. Para entender esto, necesitamos hablar sobre analizadores sintácticos LR (1). En un analizador LR (0), el analizador funciona realizando un seguimiento de dónde podría estar en medio de una producción. Una vez que ha comprobado que ha llegado al final de una producción, sabe que debe intentar reducir. Sin embargo, es posible que el analizador no sea capaz de decir si está al final de una producción y a la mitad de otra, lo que lleva a un conflicto de cambio / reducción, o en cuál de dos producciones diferentes ha llegado al final (reducción / reducir el conflicto). En LR (0), esto conduce inmediatamente a un conflicto y el analizador falla. En SLR (1) o LALR (1),
En un analizador LR (1), el analizador realiza un seguimiento de la información adicional a medida que funciona. Además de realizar un seguimiento de la producción que el analizador cree que se está utilizando, realiza un seguimiento de los posibles tokens que podrían aparecer después de que se complete la producción. Debido a que el analizador realiza un seguimiento de esta información en cada paso, y no solo cuando necesita tomar la decisión, el analizador LR (1) es sustancialmente más poderoso y preciso que cualquiera de los LR (0), SLR (1) o Analizadores LALR (1) de los que hemos hablado hasta ahora. LR (1) es una técnica de análisis extremadamente poderosa, y se puede demostrar usando algunas matemáticas complicadas que cualquier lenguaje que pueda ser analizado de forma determinista por cualquier analizador de cambio / reducción tiene alguna gramática que podría analizarse con un autómata LR (1). (Tenga en cuenta que esto no significa que todas las gramáticasque se pueden analizar de forma determinista son LR (1); esto solo dice que un lenguaje que podría analizarse de manera determinista tiene algo de gramática LR (1)). Sin embargo, esta potencia tiene un precio, y un analizador LR (1) generado puede requerir tanta información para funcionar que no se puede utilizar en la práctica. Un analizador LR (1) para un lenguaje de programación real, por ejemplo, puede requerir decenas a cientos de megabytes de información adicional para funcionar correctamente. Por esta razón, LR (1) no se usa normalmente en la práctica, y en su lugar se usan analizadores más débiles como LALR (1) o SLR (1).
Más recientemente, un nuevo algoritmo de análisis denominado GLR (0) ("LR generalizado (0)") ha ganado popularidad. En lugar de intentar resolver los conflictos que aparecen en un analizador LR (0), el analizador GLR (0) funciona probando todas las opciones posibles en paralelo. Usando algunos trucos ingeniosos, esto se puede hacer para que se ejecute de manera muy eficiente para muchas gramáticas. Además, GLR (0) puede analizar cualquier gramática libre de contexto , incluso gramáticas que no pueden ser analizadas por un analizador LR (k) para cualquier k. Otros analizadores también pueden hacer esto (por ejemplo, el analizador Earley o el analizador CYK), aunque GLR (0) tiende a ser más rápido en la práctica.
Si está interesado en aprender más, durante este verano impartí un curso introductorio de compiladores y pasé poco menos de dos semanas hablando sobre técnicas de análisis sintáctico. Si desea obtener una introducción más rigurosa a LR (0), SLR (1) y una serie de otras poderosas técnicas de análisis, puede disfrutar de mis diapositivas de conferencias y asignaciones de tareas sobre análisis. Todos los materiales del curso están disponibles aquí en mi sitio personal .
¡Espero que esto ayude!