■補講 7章レッスン24で出てきたスタックとは?  本書の7章レッスン24 (219ページ)の最後に「スタック」という単語がでてきます。マシン語やFORTH、PostScript言語などを使ったことがあればスタックというのは必須ですから、ああ、あれか…とわかるでしょう。しかし、最近の言語ではスタック自体が隠蔽されていて表に出て来ることはありません。  そこでビジュアル的に分かるように簡単なスタック式計算機を作ってみました。これは単純な加算しかしません。これはスタックに入れられた2つの値を加算してスタックに戻すというものです。  テキストフィールドに値を入力してから「スタックに入れる」ボタンをクリックしてみてください。すると、値がスタックに入ります。さらに他の値を入れてみて下さい。  2つの値を入れたら「2つの値を加算する」ボタンをクリックしてみてください。2つの値がスタックから取り出され、代わりに加算した結果がスタックに入ります。  通常JavaScriptなどの言語(アルゴル系言語)では、関数のパラメータは指定された数だけ必要です。しかし、スタック式言語の場合はスタックに値が入っていればよく、その数が多くても問題にはなりません。試しにテキストフィールドに値をたくさん入れてから「2つの値を加算する」ボタンをクリックしてみてください。最近入れられた2つの値が取り出され加算されます。その結果がスタックに入ります。スタックの一番上に加算結果が入ります。ここで、さらに「2つの値を加算する」ボタンを押してみましょう。一番上と、その次に値が取り出され加算されます。そして、その結果がスタックに入ります。  実際のプログラムは以下のようになります。 ------------------------------------------------------------------------------------------------ ■スタック式計算機 ------------------------------------------------------------------------------------------------ // スタックを用意する。ここでは配列で表現。 var stack = [ ]; // スタックポインタを用意する。最初は何もないので0 var stackPointer = 0; // スタックに入る限界値(ここでは10にしてある) var stackMax = 10; // ページの読み込みが完了したら処理をする window.addEventListener("load", function(){ // 「スタックに入れる」ボタンがクリックされた時の処理 document.getElementById("pushButton").addEventListener("click", function(){ var n = document.getElementById("num").value; // スタックに入れる値を読み出す pushValue(n); // スタックに値を入れる }, true); // 「2つの値を加算する」ボタンがクリックされた時の処理 document.getElementById("addButton").addEventListener("click", function(){ var n1 = popValue(); // スタックから1つ値を取り出す if (n1 === null){ return; } // nullなら失敗(エラー) var n2 = popValue(); // スタックから1つ値を取り出す if (n2 === null){ return; } // nullなら失敗(エラー) var n = parseFloat(n1)+ parseFloat(n2); // 値を加算 pushValue(n); // スタックに値を入れる }, true); }, true); // スタックの内容を表示 function viewStack(){ var text = ""; for(var i=0; i' + stack[i] + ''; } // スタックの内容を表示 document.getElementById("stackStatus").innerHTML = text; } // スタックに値を1つ入れる function pushValue(n){ if (stackPointer === stackMax){ alert("スタックオーバーフローです"); return; } stack.unshift(n); // スタックに入れる stackPointer = stackPointer + 1; // スタックポインタを1つ増やす viewStack(); } // スタックから値を1つ取り出す function popValue(){ if (stackPointer === 0){ alert("スタックアンダーフローです"); return null; } stackPointer = stackPointer - 1; // スタックポインタを1つ減らす return stack.shift(); // スタックポインタから値を1つ取り出す viewStack(); } ------------------------------------------------------------------------------------------------ ■スタック式での計算方法  サンプルプログラムではボタンを用意して2つの値を加算しました。実際のスタック式言語であるFORTHやPostScriptでは、処理を実行するものは「オペレータ」として定義されています。スタック式言語では、とりあえず何でもかんでもスタックに入れていきます。ただし、オペレータがスタックされたら処理を実行します。(実際の言語では、スタック内には入らないのですが、ここは説明の都合上スタックに入れてます)  例えば加算するオペレータが+だとすると以下のようにスタックに入ります。 ------------------------ スタック内容 ------------------------ + 1 2 6 9 ------------------------ +は2つの値を取り出して加算するので以下のような結果になります。 ------------------------ スタック内容 ------------------------ 3 6 9 ------------------------ これは簡単な足し算の例ですが、複雑な計算になった場合、スタック式では複雑な構文解析をしなくてもよいという大きなメリットがあります。例えば以下の計算式を見てみましょう。 4 × (2 + 3) この計算結果は20になります(4×5=20)。JavaScriptなどのプログラム言語では、この計算結果を導き出すのに構文を解析し計算の優先順位をつけていかなければなりません。これは面倒です。 それではスタック式の場合は、どうなるのでしょうか? 実はこうなります。 2 3 + 4 × はて?これは何?と思われるかもしれません。これは日本語で書き直すとよくわかります。 2と3を足して4を掛ける 実際にスタックの様子がどうなるかを以下に示します。オペレータが現れると、そこでスタックから値が取り出され処理され、再度スタックに積まれます。 ------------------------ スタック内容(1) ------------------------ + 3 2 ------------------------ スタック内容(2) ------------------------ 4 5 ------------------------ スタック内容(3) ------------------------ × 4 5 ------------------------ スタック内容(4) ------------------------ 20 ------------------------ このような方法でもちゃんと計算することができます。ちなみに、「2 3 + 4 ×」な書き方は「逆ポーランド記法」と呼ばれます。 スタック式言語は機構がシンプルで、機能は辞書として追加するだけで、どんどん増やせるというメリットがあります。スタック式言語で有名なのはFORTHですが、これは天体望遠鏡の制御に使われていました。 ちなみに身近で使われているスタック式言語としてはPostScriptがあります。PDFは、このPostScript言語のサブセットです。これらは印刷業界で多く使われています。WebでもPDFは多くみかけます。つまり、本書はスタック式言語であるPostScriptを使って印刷されているわけです。 つまり、本書自体がスタック式言語の成果物(?)でもあると言えます。