私はジョブコントロールシェルを作成しています。私は解析のためにYaccとLexを使う。私の文法の最上位のルールは、pipeline_list
です。これはコンマで区切られたパイプラインのリストです。yaccの解析とリセットを停止するには?
cmd1 | cmd2; cmd3; cmd4 | cmd5 <newline>
cmd1 <newline>
<nothing> <newline>
Iは(以下を示した)pipeline
ルールパイプラインを表す次のよう従って、pipelinelistsの例です。そのルールの中で、私は以下のようにします:
1.パイプラインを実行するにはexecute_pipeline()
を呼び出します。 execute_pipeline()
は、パイプラインの実行に問題があれば-1
を返します。
execute_pipeline()
の戻り値をチェックし、それが-1
であれば、入力の残りの部分を解析し、停止、および主な機能(下記参照)に再び呼び出されたときYACCは新鮮な始まりを確認してください。これを行うための論理的根拠は次のとおりです。 たとえば、次のパイプライン担当者を取る:cd ..; ls -al
。ここで私の意図は、1つのディレクトリを移動し、その内容を一覧表示することです。しかしながら、パイプラインリスト内の第1のパイプライン(すなわち、"cd .."
)の実行に失敗した場合、第2のパイプライン(すなわち、" ls -al"
)を実行するために続けて実行すると、カレントディレクトリの内容(親ではない)この理由から、長さがn
のパイプラインリストを解析するときに、あるパイプラインの実行が失敗した場合、残りのパイプラインリスト(パイプラインk+1..n
)を破棄して、yyparse()の次の呼び出しが真新しい(すなわち、readline()
から新しい入力を受け取ります - 下のコードを参照してください)。 場合は、次のことを試してみましたが、それは動作しません:
pipeline:
simple_command_list redirection_list background pipeline_terminator // ignore these
{
if (execute_pipeline() == -1)
{
// do some stuff
// then call YYABORT, YYACCEPT, or YYERROR, but none of them works
}
}
int main()
{
while(1)
{
char *buffer = readline("> ");
if (buffer)
{
struct yy_buffer_state *bp;
bp = yy_scan_string(buffer);
yy_switch_to_buffer(bp);
yyparse()
yy_delete_buffer(bp);
free(buffer);
} // end if
} // end while
return 0;
} // end main()
提案:パーサーでコマンドを実行しないでください。ツリーを構築し、パーサーエラーがない場合は別のパスで評価します。パーサの状態とのやりとりを心配することなくエラーを処理できます。 – Kaz