Pregunta

Del Manual de Bison:

  

En un analizador de comandos interactivo simple   donde cada entrada es una línea, puede   ser suficiente para permitir que   devolver 1 por error y hacer que la persona que llama   ignore el resto de la línea de entrada cuando   eso sucede (y luego llama a yyparse   de nuevo).

Esto es más o menos lo que quiero, pero tengo problemas para ir a trabajar. Básicamente, quiero detectar un error en flex, y si se detecta un error, haga que Bison descarte toda la línea. Lo que tengo ahora, no funciona del todo bien porque mis comandos aún se ejecutan:

kbsh: ls '/home
Error: Unterminated Single Quote
admin  kbrandt  tempuser
syntax error
kbsh: 

En mi archivo Bison:

commands:
     /*Empty*/ { prompt(); } |
     command { prompt(); }
    ;

command:
    error {return 1; } |
    chdir_command |
    pwd_command |
    exit_command |
    WORD arg_list {
        execute_command($1, $2);
        //printf("%s, %s\n", $1, $2); 
    } |
    WORD { execute_command($1, NULL); }
    ;

Y en mi Flex:

'   {BEGIN inQuote; }

<inQuote>\n {printf("Error: Unterminated Single Quote\n"); BEGIN(0); return(ERROR);}
¿Fue útil?

Solución

No creo que encuentre una solución simple para manejar estos tipos de errores de análisis en el lexer.

Mantendría el lexer (flex / lex) lo más tonto posible, solo debería proporcionar una secuencia de tokens básicos (identificadores, palabras clave, etc.) y hacer que el analizador (yacc / bison) realice la detección de errores . De hecho, está configurado exactamente para lo que desea, con una pequeña reestructuración de su enfoque ...

En el lexer (parser.l), manténgalo simple (sin manejo de eol / newline), algo así como (no está lleno):

}%

/* I don't recall if the backslashify is required below */
SINGLE_QUOTE_STRING \'.*\'
DOUBLE_QUOTE_STRING \".*\"

%%
{SINGLE_QUOTE_STRING} {
    yylval.charstr = copy_to_tmp_buffer(yytext);  // implies a %union
    return STRING;
}
{DOUBLE_QUOTE_STRING} {
    yylval.charstr = copy_to_tmp_buffer(yytext);  // implies a %union
    return STRING;
}
\n   return NEWLINE;

Luego, en su archivo parser.y, realice todo el manejo real (no es una tarea completa):

command:
    error NEWLINE
        { yyclearin; yyerrorok; print_the_next_command_prompt(); }
    | chdir_command STRING NEWLINE
        { do_the_chdir($<charstr>2); print_the_next_command_prompt(); }
    | ... and so on ...

Hay dos cosas a tener en cuenta aquí:

  1. El cambio de cosas como NEWLINE al lado de yacc para que pueda determinar cuándo el usuario ha terminado con el comando y luego puede borrar las cosas y comenzar de nuevo (suponiendo que tenga " int yywrap() {return 1;} & "en alguna parte). Si intenta detectarlo demasiado pronto en flex, ¿cuándo sabe que se genera un error?
  2. chdir no es un comando (a menos que se haya subrregulado y simplemente no lo haya mostrado), ahora tiene chdir_command STRING (el argumento para el chdir). Esto hace que el analizador pueda descubrir qué salió mal, luego puede yyerror si ese directorio no existe, etc ...

De esta manera deberías obtener algo como (adivinar cómo podría ser chdir):

  
    

cd 'algún_directorio
    error de sintaxis
    cd 'some_directory'
    ¡estás en el directorio de some_directory!

  

Y todo lo maneja el grabador de yacc, no el tokenizador.

He descubierto que mantener la flexibilidad lo más simple posible le brinda la mayor flexibilidad ***. :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top