Pergunta

A partir do Bison Manual:

Em um analisador de comando interativo simples onde cada entrada é uma linha, que pode ser suficiente para permitir a yyparse retornar 1 em erro e que o chamador ignorar o resto da linha de entrada quando que acontece (e, em seguida, yyparse chamada de novo).

Isso é muito bonito o que eu quero, mas estou tendo problemas para chegar ao trabalho. Basicamente, eu quero detectar e erro em flex, e se for detectado um erro, tem Bison descartar a linha inteira. O que eu tenho agora, não está funcionando muito bem porque os meus comandos ainda são executadas:

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

No meu arquivo Vega:

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); }
    ;

E no meu Flex:

'   {BEGIN inQuote; }

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

Solução

Eu não acho que você vai encontrar uma solução simples para lidar com esses tipos de erros de análise no lexer.

Gostaria de manter o lexer (flex / lex) tão idiota quanto possível, ele deve apenas fornecer um fluxo de símbolos básicos (identificadores, palavras-chave, etc ...) e têm o analisador (yacc / bison) fazer a detecção de erros . Na verdade, é a configuração para exatamente o que você quer, com um pouco de reestruturação da sua abordagem ...

No lexer (parser.l), mantê-lo simples (sem eol / manipulação de nova linha), algo como (não é coisa completa):

}%

/* 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;

Em seguida, em seu arquivo parser.y fazer todo o tratamento real (não é coisa 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 ...

Há duas coisas a nota aqui:

  1. A mudança de coisas como NEWLINE para o lado do yacc para que você possa determinar quando o usuário é feito com o comando, em seguida, você pode limpar as coisas e começar de novo (supondo que você tem "int yywrap() {return 1;}" em algum lugar). Se você tentar detectá-lo cedo demais em flex, quando você sabe para gerar um erro?
  2. chdir não é um comando (a menos que foi sub governado e você simplesmente não mostrá-lo), ele agora tem STRING chdir_command (o argumento para o chdir). Isso faz com que o analisador pode descobrir o que deu errado, você pode então yyerror se esse diretório não existe, etc ...

Desta forma, você deve obter algo como (supondo que chdir pode parecer):

cd 'some_directory
erro de sintaxe
cd 'some_directory'
você está na cara some_directory!

E tudo é manipulado pela gramática yacc, não pelo tokenizer.

Eu descobri que manter flexível o mais simples possível dá-lhe a mais *** *** Flex lidade. :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top