yacc プログラムのエラー処理

パーサーが入力ストリームを読むとき、 その入力ストリームは文法ファイルの規則と一致しない可能性もあります。

パーサーは、可能な限り早く問題を検出します。 文法ファイルにエラー処理サブルーチンがある場合、 パーサーは、再びデータを入力するか、誤ったデータを無視するか、 またはクリーンアップおよびリカバリー・アクションを開始することを許可します。 パーサーは、エラーを発見すると、例えば、 構文解析ツリー・ストレージを再利用し、シンボル・テーブルの項目を削除または変更し、 さらにそれ以後の出力の生成を避けるために、スイッチを設定する必要が出てくる場合があります。

エラーが起こると、ユーザーがエラー処理サブルーチンを準備しておかなければ、 パーサーは停止します。 入力の処理を続行してさらにエラーを検索するには、入力ストリームの中の、 パーサーがそれ以上の入力の認識を試みることができるポイントで、パーサーを再始動します。 エラーが起きたときにパーサーを再始動する 1 つの方法は、 エラーに続くトークンの一部を破棄することです。 その後、入力ストリームの中のそのポイントからパーサーを再始動します。

yacc コマンドは、 エラー処理に特殊なトークン名 error を使用します。 このトークンを、 規則ファイルの入力エラーが発生した場所に書き込んで、 リカバリー・サブルーチンを提供できるようにします。 入力エラーがこの位置で起きた場合、パーサーは、 通常のアクションでなく error トークンのためのアクションを実行します。

以下のマクロを yacc アクションに追加し、エラー処理を補うこともできます。
マクロ 説明
YYERROR パーサーにエラー処理を開始させる。
YYABORT パーサーに値 1 で戻らせる。
YYACCEPT パーサーに値 0 で戻らせる。
YYRECOVERING() 構文エラーが検出され、パーサーがまだ完全にリカバリーしていない場合、値 1 を戻す。

単一エラーで多数のエラー・メッセージが出されるのを防ぐために、 パーサーはエラーに続いて 3 個のトークンを処理するまでエラー状態でいます。 パーサーがエラー状態の間に別のエラーが発生すると、 パーサーは入力トークンを破棄して、メッセージを作成しません。

例えば、次の形式の規則があるとします。
stat  :  error ';'

これは、エラーが起きたときはそのトークンとそれに続くすべてのトークンを、次のセミコロンが見つかるまで無視するように、パーサーに指示します。 エラーの後から次のセミコロンの前までの、すべてのトークンは破棄されます。 セミコロンを検出すると、パーサーはこの規則を縮小して、 関連するすべてのクリーンアップ・アクションを実行します。

エラー訂正の準備

対話環境で入力ストリームを入力している人が、 データ・ストリームに再び行を入力することによって、 任意の入力エラーを訂正できるようにすることができます。 次の例は、これを行う 1 つの方法を示しています。

input : error '¥n'
        {
          printf(" Reenter last line: " );
         }
         input
       {
         $$ = $4;
       }
       ;
ただし、この例ではパーサーはエラーに続く入力トークン 3 個の間、 エラー状態にとどまることになります。 訂正された行の中の最初の 3 個のトークンにエラーが入っている場合、 パーサーはそれらのトークンを削除しますが、メッセージを表示しません。 この状態に備えるために、次の yacc ステートメントを使用します。
yyerrok;

パーサーは、このステートメントを発見すると、エラー状態を離れて、 通常に処理を始めます。 エラー・リカバリーの例を、次に示します。

input : error '¥n'
        {
          yyerrok;
          printf(" Reenter last line: " );
         }
         input
       {
         $$ = $4;
       }
         ;

ルック・アヘッド・トークンのクリア

ルック・アヘッド・トークン は、 パーサーが次に調べるトークンです。 エラーが発生すると、ルック・アヘッド・トークンは、エラーが検出されたトークンになります。 ただし、エラー・リカバリー・アクションに処理を再開する正しい場所を見つけるコードが組み込まれている場合、 そのコードはルック・アヘッド・トークンの変更も行う必要があります。 ルック・アヘッド・トークンをクリアするには、 次のステートメントをエラー・リカバリー・アクションに組み込みます。

yyclearin ;