Flex(lex)およびBison(yacc)によるエラー処理
-
07-07-2019 - |
質問
Bisonマニュアルから:
シンプルなインタラクティブコマンドパーサー 各入力が1行の場合、 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); }
;
そして私のフレックス:
' {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(<*>lt;charstr>2); print_the_next_command_prompt(); }
| ... and so on ...
ここで注意すべき点が2つあります:
- NEWLINEのようなもののyacc側へのシフト。これにより、ユーザーがコマンドの実行を完了したかどうかを判断できるため、すべてをクリアしてやり直すことができます(&quot;
int yywrap(){return 1;}
&quot;どこかに)。フレックスで早期に検出しようとした場合、いつエラーが発生することを知っていますか? - chdirは1つのコマンドではなく(サブルールであり、表示しなかった場合を除く)、chdir_command STRING(chdirの引数)になりました。これにより、パーサーが何が間違っていたかを把握できるようになり、そのディレクトリが存在しない場合などにyyerrorを実行できます。
この方法で、次のようになります(chdirがどのように見えるかを推測します):
cd 'some_directory
構文エラー
cd 'some_directory'
あなたはsome_directory男にいます!
そして、すべてトークナイザーではなく、yaccグラマーによって処理されます。
フレックスを可能な限りシンプルに保つことで、最も柔軟性が得られることがわかりました。 :)