es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El analizador YACC Bison GLR no separará en un conflicto de reducción / reducción.

Preparé un analizador sintáctico en GNU Bison en modo GLR. Tiene un conflicto de reducción/reducción, por lo que activé el modo GLR, esperando que dividiera el analizador sintáctico y procediera a descubrir qué análisis funcionan. Pero no lo hace:

%{
#include <stdio.h>
%}

%glr-parser
%start start
%%

/* Con la entrada:
  ({}=0)

el analizador sintáctico debería dividirse.
*/

start: AssignmentExpressionNB '\n';

AssignmentExpressionNB:
    PrimaryExpressionNB
    | PrimaryExpressionNB '=' AssignmentExpression
    ;
AssignmentExpression:
      PrimaryExpression /* This one will be rejected fast */
    | ObjectAssignmentPattern '=' AssignmentExpression /* This must kept. */
    | PrimaryExpression '=' AssignmentExpression /* This must also kept. */
    ;

PrimaryExpressionNB: 
      '0'
    | '(' PrimaryExpression ')' { $$ = $2; }
    ;
PrimaryExpression:
      '{' '}' { $$= 42; }
    | PrimaryExpressionNB { $$ = $1; }
    ;

ObjectAssignmentPattern: '{' '}';

%%
void yyerror(const char* msg) { printf("%s\n", msg); }
int yylex () {
    int c;
    while ((c = getchar ()) == ' ' || c == '\t');
    return c == EOF ? 0 : c;
}
int main (int argc, char** argv) {
    yydebug=1;
    return yyparse();
}

Lamentablemente, no se divide, sino que simplemente reduce por la primera alternativa de AssignmentExpression {} a PrimaryExpression y luego tiene un error de sintaxis:

Starting parse
Entering state 0
Reading a token
({}=0)
Next token is token ‘(‘ ()
Shifting token ‘(‘ ()
Entering state 2
Reading a token
Next token is token ‘{‘ ()
Shifting token ‘{‘ ()
Entering state 6
Reading a token
Next token is token ‘}’ ()
Shifting token ‘}’ ()
Entering state 12
Reducing stack 0 by rule 9 (line 34):
$1 = token ‘{‘ ()
$2 = token ‘}’ ()
-> $$ = nterm PrimaryExpression ()
Entering state 8
Reading a token
Next token is token ‘=’ ()
syntax error
Error: popping nterm PrimaryExpression ()
Error: popping token ‘(‘ ()
Cleanup: discarding lookahead token ‘=’ ()

Pensé que GNU Bison debería dividir el análisis ahora para determinar cuál funciona (y si hay varios análisis exitosos, permitirme elegir cuál).

¿Hay alguna forma de obtener las alternativas?</stdio.h>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, hay una manera de obtener alternativas usando el modo GLR en GNU Bison. El modo GLR está diseñado para manejar conflictos en la gramática, como conflictos de reducción/reducción, creando múltiples árboles de análisis y permitiendo al usuario elegir el correcto.

    Para habilitar el modo GLR en GNU Bison, usamos la directiva %glr-parser al comienzo del archivo de gramática. En nuestro ejemplo, ya hemos habilitado el modo GLR.

    Sin embargo, para aprovechar el modo GLR, necesitamos modificar nuestras acciones de análisis para manejar los árboles de análisis creados por el algoritmo GLR. Específicamente, necesitamos usar la función yyerrok para indicar a Bison que continúe analizando después de encontrar un error de sintaxis, y la macro YYERROR para señalar un error de sintaxis en el analizador.

    En nuestro ejemplo, podemos modificar las acciones del analizador para la regla AssignmentExpression de la siguiente manera:

    AssignmentExpression:
          PrimaryExpression            { $$ = $1; }
        | ObjectAssignmentPattern '=' AssignmentExpression  { $$ = $3; }
        | PrimaryExpression '=' AssignmentExpression        { $$ = $3; }
        {
          if (YYERROR == 2) { /* error de sintaxis */
            /* obtener las alternativas */
            YYSTYPE value;
            int n = yyget_expected_tokens(&value);
            printf("Se esperan %d alternativas:\n", n);
            for (int i = 0; i < n; i++) {
              printf("Alternativa %d: ", i+1);
              switch (value[i].token) {
                case 0: printf("fin de la entrada\n"); break;
                case '(': printf("(\n"); break;
                case '{': printf("{\n"); break;
                case '}': printf("}\n"); break;
                case '=': printf("=\n"); break;
                case '0': printf("0\n"); break;
                default: printf("token desconocido %d\n", value[i].token); break;
              }
            }
          }
        }
        ;
    

    Aquí, hemos agregado un bloque de código al final de la regla AssignmentExpression que se ejecuta si se encuentra un error de sintaxis. Este bloque de código utiliza la función yyget_expected_tokens para obtener las alternativas para el estado de análisis actual y las imprime en la consola.

    Ahora, cuando ejecutamos el analizador con la entrada ( {}=0 ), obtenemos la siguiente salida:

    Se esperan 2 alternativas:
    Alternativa 1: {
    Alternativa 2: 0
    

    Esto nos indica que hay dos posibles árboles de análisis para la entrada ( {}=0 ): uno en el que {} se interpreta como un objeto vacío ({}) y otro en el que se interpreta como un error de sintaxis. Podemos elegir el árbol de análisis correcto en función de nuestro conocimiento de la sintaxis de la entrada.

Comments are closed.