Pコードマシン
pコードマシンとは、プロセッサの一種であるが、ハードウェアではなくソフトウェアで、すなわちエミュレータや仮想機械のようなインタプリタ型のプログラムで実装されることを目的としたものであり、p-code と呼ばれる中間コードを解釈実行する。この用語は、そのような仕様一般を指すこともあるが、多くの仕様はそれぞれ個々の名称を持っている。特にUCSD Pascalの p-Machine を指すことが多い。「p」の意味については、Pascal処理系の場合はPascalの頭文字ともされるが、他言語の場合はpseudo(マイクロソフトのサポート情報を参照)やportableなどとされる。
このコンセプトは1966年ごろ、BCPLのO-code(英語版)やニクラウス・ヴィルトのEuler(英語版)のPとして実装されたのが最初であるが、pコード (p-code) と呼ばれるようになったのは1970年代初期であった。pコードを生成する初期のコンパイラとしては、1973年、Nori、Ammann、Jensen、Hageli、Jacobi が開発した Pascal-P コンパイラと、ヴィルトが1975年に開発した Pascal-S コンパイラがある。
ソースコードからコンパイラのコード生成によってpコードが生成され、そのpコードはpコードマシンのエミュレータ、言い換えればインタプリタによって解釈実行される。商業的に十分意味があるとみて、pコードを直接実行するハードウェアが実装された例もある(例えば、Pascal MicroEngine)。
従って、i にはローカル変数用の領域サイズを指定し(引数および余分に5要素分も予約する)、j には命令実行でローカルに必要なスタック領域が指定される。メモリ不足が発生していないかはこの時点でチェックされる。
呼び出し側への復帰は次の命令で行われる。
Cにはリターン型(上述の基本型 i, r, c, b, a と何も返さない場合の p)が指定される。リターン値は適切なセルに格納される。p 以外の各型のリターンでは、その値がスタックに置かれたまま呼び出し側に復帰する。
ユーザープロシージャの呼び出し(cup)ではなく、標準プロシージャ q を呼び出す場合は次の命令を使用する。
標準プロシージャとは、Pascalの標準ライブラリのようなもので、例えば readln()("csp rln")、sin()("csp sin")などがある。ただし、eof() はpコードでは1つの命令となっている。
pコードマシンはスタックマシンであり、ほとんどの命令がスタックからオペランドを持ってきて、結果をスタックに戻す。例えば、add 命令はスタックの先頭2要素を取り出し、加算結果をスタックに戻す。一部の命令は即値オペランドを持つ。Pascalと同様、pコードも型があり、ブーリアン(b)、文字(c)、整数(i)、実数(r)、集合(s)、ポインタ(a)が最初から用意されている。
以下に簡単な命令を示す。命令名、実行前のスタック状態、実行後のスタック状態、解説の順に並んでいる。
adi: (i1 i2) ⇒ (i1+i2) - 2つの整数の加算
adr: (r1 r2) ⇒ (r1+r2) - 2つの実数の加算
dvi: (i1 i2) ⇒ (i1/i2) - 整数の除算
inn: (i1 s1) ⇒ (b1) - メンバーシップを設定。b1 には i1 が s1 のメンバーかどうかが設定される(true/false)。
idci i1: () ⇒ (i1) - 整数定数をスタック上にロードする。
mov: (a1 a2) ⇒ () - メモリ間のコピー
not: (b1) ⇒ (~b1) - ブーリアンの否定