データは逆方向にファイルに書き込まれています
この特定のビットは、あなたが望んでいたものとは異なる構成を選択したように聞こえます. Yacc では、左と右の両方の再帰が可能です。これにより、(たとえば) 各項目が表示される順序 (左再帰) でリストを解析したり、その逆の順序でリストを解析したりできます。おそらく今やっている正しい再帰の例を次に示します。
list : ITEM
| ITEM list
このサブグラマーは、入力に ITEM が含まれている場合、それだけではこれら 2 つのプロダクションのどちらを使用すればよいかわからないことに注意してください。どちらも ITEM で始まります。したがって、パーサーは 1 トークン先を見ます。次のトークンが ITEM でない場合、最初のプロダクションを使用することがわかります。しかし、次のトークンが ITEM である場合、2 番目の生産を処理する必要があります。しかし、そのプロダクションには非終端記号list
が含まれています。つまり、パーサーは実際にはまったく削減しませんが、最初の ITEM をスタックにプッシュし、別の を探しに行きますlist
。
この結果、このサブグラマーに ITEM トークンのリストを与えると、別の ITEM が続いていない ITEM を最終的に確認するまで、それらをスタックにプッシュし続けます。その時点で、最後の ITEM は最初の生成によって削減されます (したがって に変わりlist
、他のすべての ITEM は 2 番目の生成によって 1 つずつ削減されます。左再帰に進みます。
list : ITEM /* matches first ITEM in list */
| list ITEM /* matches all other ITEMs in list */
今回、パーサーが ITEM を検出list
すると、ITEM で始まるプロダクションは 1 つだけなので、最初のプロダクションによってすぐに削減され、その ITEM が に変わりlist
ます。ここで、入力ストリームに別の ITEM がある場合、その後に続く ITEM と一致させようとしlist
、2 番目のプロダクションと正確に一致させます。
これらは、単純なリストを解析するための一般的なイディオムです。リストが「1 つ以上」ではなく「0 個以上」の場合、単一の ITEM を含むものではなく、単に空のプロダクションを使用することに注意してください。左再帰 (通常は必要) を使用すると、最初のアイテムに一致する別のプロダクションを使用すると、たとえば、後に続く (可能性のある) すべての ITEM を保持する配列を初期化するアクションを配置するのに便利な場所が得られます。