2012-10-04 37 views
17

¿Cómo elimino el conflicto shift-reduce para bison para la gramática dada?Reformar la gramática para eliminar el cambio reducir el conflicto en if-then-else

selection-stmt -> if (expression) statement | 
         if (expression) statement else statement 

Una solución que ofrezca la gramática modificada sería muy apreciada.

+0

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. –

Respuesta

34

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.

+0

¿Cómo puedo hacer lo mismo si hay una instrucción posterior N no terminal como sigue: IF_KEYWORD '(' expresión N ')' Instrucción M N instrucción ELSE_KEYWORD M Aquí, M y N son símbolos no terminales. – Vishwas

+0

@VishwasJain Todo depende de su regla if-then. Si la parte '' else '' M' es opcional, entonces debería aplicarse el mismo enfoque. – akim

4

Debe reconocer que el medio statement en el caso if-else no puede ser (o finalizar con) un pendular (si no hay otro). La manera más fácil de hacerlo es dividir la regla stmt en dos:

stmt -> stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if 
stmt-not-ending-with-dangling-if -> 
    if (expression) stmt-not-ending-with-dangling-if else stmt-not-ending-with-dangling-if | 
    ...other statements not ending with dangling if... 
stmt-ending-with-dangling-if -> 
    if (expression) stmt | 
    if (expression) stmt-not-ending-with-dangling-if else stmt-ending-with-dangling-if | 
    ...other statements ending with dangling if... 

cualquier otro stmt -> whatever regla cuando whatever no termina con un stmt va en la regla stmt-not-ending-with-if, mientras que cualquier regla stmt que termina en stmt dividida ponerse en dos versiones; una versión not-ending-with-if en la regla not-ending-with-if y una versión dangling-if en la regla dangling-if.

edición

Una gramática más completa con otras producciones:

stmt : stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if 
stmt-not-ending-with-dangling-if : 
    IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-not-ending-with-dangling-if | 
    WHILE '(' expr ')' stmt-not-ending-with-dangling-if | 
    DO stmt WHILE '(' expr ')' ';' | 
    expr ';' | 
    '{' stmt-list '}' 
stmt-ending-with-dangling-if: 
    IF '(' expr ')' stmt | 
    IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-ending-with-dangling-if | 
    WHILE '(' expr ')' stmt-ending-with-dangling-if 

reglas como WHILE (expr) stmt dividida en dos (get, ya que terminan con stmt), mientras que las reglas como expr; no lo hacen.

+0

¿Puede explicar en mayor detalle las ... otras declaraciones .... No tengo otras producciones con la selección-prop, pero todavía estoy recibiendo un error diciendo que no terminales usando inútiles Esto es lo que hice: selección-prop \t : abierto \t \t | cerrado \t \t; abierto \t \t: IF expresión LFT_BRKT declaración RGT_BRKT \t \t | IF expresión LFT_BRKT RGT_BRKT cerrada ELSE abierta \t \t; cerrado \t \t: IF expresión LFT_BRKT RGT_BRKT cerrado ELSE cerrado \t \t; –

+0

por favor una mirada –

+0

http://stackoverflow.com/questions/12720219/bison-shift-reduce-conflict-unable-to-resolve/12720483#12720483 La gramática completa está aquí –

0

hacer otra cosa si un nivel más alto que las declaraciones normales, como:

statements: 
    statements lineEnd statement 
| statements lineEnd IfStat 
| statements lineEnd IfElseStat 
| IfStat 
| IfElseStat 
; 
IfStat: 
    if (statement) 
; 
IfElse: 
    IfStat else statement 
; 
+0

No creo que esto pueda solucionar el problema. –

Cuestiones relacionadas