Обработка ошибок с помощью Flex (lex) и Bison (yacc)
-
07-07-2019 - |
Вопрос
Из Руководства 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 ...
Здесь нужно отметить две вещи:
<Ол>int yywrap() {return 1;}
& "где-то). Если вы попытаетесь обнаружить его слишком рано во флексе, когда вы узнаете, как вызвать ошибку? Таким образом, вы должны получить что-то вроде (угадать, как может выглядеть chdir):
cd 'some_directory
синтаксическая ошибка
cd 'some_directory'
ты в чуваке some_directory!
И все это обрабатывается грамматикой yacc, а не токенизатором.
Я обнаружил, что поддержание гибкости настолько простым, насколько это возможно, дает вам наибольшую гибкость. :)