Вопрос

Из Руководства Bison:

  

В простом интерактивном парсере команд   где каждый вход - одна строка, это может   быть достаточным, чтобы позволить yyparse   верните 1 при ошибке и вызовите   игнорировать остальную часть строки ввода, когда   что происходит (а затем вызвать yyparse   снова).

Это в значительной степени то, что я хочу, но у меня проблемы с получением работы. По сути, я хочу обнаружить ошибку в flex, и если обнаружена ошибка, пусть Bison отбрасывает всю строку. То, что у меня есть сейчас, работает не совсем правильно, потому что мои команды все еще выполняются:

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

В моем файле 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); }
    ;

И в моем Flex:

'   {BEGIN inQuote; }

<inQuote>\n {printf("Error: Unterminated Single Quote\n"); BEGIN(0); return(ERROR);}
Это было полезно?

Решение

Я не думаю, что вы найдете простое решение для обработки этих типов ошибок синтаксического анализа в лексере.

Я бы хотел, чтобы лексер (flex / lex) был настолько тупым, насколько это возможно, он должен просто предоставлять поток базовых токенов (идентификаторы, ключевые слова и т. д.) и позволять анализатору (yacc / bison) обнаруживать ошибки. , На самом деле это настройка именно для того, что вы хотите, с небольшой перестройкой вашего подхода ...

В лексере (parser.l) сделайте его простым (без обработки eol / newline), что-то вроде (не полная вещь):

}%

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

Затем в вашем файле parser.y выполните всю реальную обработку (не полная вещь):

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

Здесь нужно отметить две вещи:

<Ол>
  • Перенос таких вещей, как NEWLINE, на сторону yacc, чтобы вы могли определить, когда пользователь завершил работу с командой, затем вы можете очистить вещи и начать все сначала (при условии, что у вас есть " int yywrap() {return 1;} & "где-то). Если вы попытаетесь обнаружить его слишком рано во флексе, когда вы узнаете, как вызвать ошибку?
  • chdir - это не одна команда (если она не подчинялась правилам, а вы ее просто не показывали), теперь она имеет chdir_command STRING (аргумент для chdir). Это позволяет парсеру выяснить, что пошло не так, затем вы можете yyerror, если такой директории не существует, и т. Д ...
  • Таким образом, вы должны получить что-то вроде (угадать, как может выглядеть chdir):

      
        

    cd 'some_directory
        синтаксическая ошибка
        cd 'some_directory'
        ты в чуваке some_directory!

      

    И все это обрабатывается грамматикой yacc, а не токенизатором.

    Я обнаружил, что поддержание гибкости настолько простым, насколько это возможно, дает вам наибольшую гибкость. :)

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top