Hay una solución mucho más simple. Si usted sabe cómo funcionan los análisis de LR, entonces usted sabe que el conflicto que ocurre aquí:
if (expression) statement * else statement
donde la estrella marca la posición actual del cursor. La pregunta que el analizador debe responder es "¿Debería cambiar, o debería reducir?". Normalmente, desea vincular el else
al if
más cercano, lo que significa que desea cambiar el token else
ahora. Reducir ahora significaría que desea que el else
espere para estar vinculado a un "anterior" if
.
Ahora quiere "decirle" a su generador de analizadores que "cuando hay un conflicto de cambio/reducción entre el token "else"
y la regla" stm -> if (exp) stm ", entonces el token debe ganar". Para hacerlo, "dar un nombre" a la prioridad de su regla (por ejemplo, "then"
) y especifique que "then"
tiene menos prioridad que "else"
. Algo como:
// Precedences go increasing, so "then" < "else".
%nonassoc "then"
%nonassoc "else"
%%
stm: "if" "(" exp ")" stm %prec "then"
| "if" "(" exp ")" stm "else" stm
usando la sintaxis de Bison.
En realidad, mi respuesta favorita es incluso dar a "then"
y "else"
la misma precedencia. Cuando las precedencias son iguales, para romper el empate entre el token que quiere ser desplazado, y la regla que quiere ser reducida, Bison/Yacc observará la asociatividad. Aquí, usted quiere promover asociatividad por la derecha por así decirlo (más exactamente, que desea promover "cambio"), por lo que:
%right "then" "else" // Same precedence, but "shift" wins.
será suficiente.
Para las personas futuras, [esta página] (http://www.tldp.org/HOWTO/Lex-YACC-HOWTO-7. html) me ayudó a resolver un problema similar. Además, pase los modificadores '--debug' y' --verbose' a bison y mire los archivos generados. No toda la información está impresa en estándar. –