PL/0'コンパイラのJavaCC版


PL/0'コンパイラをJavaで書いたものをもとにして、JavaCCでparserを作り直してみました.

JavaCCでは、字句規則と構文規則を一つのファイルに記述する。構文規則は、recursive descent parser を記述するような形で書けばよく、その構文規則の途中に意味規則を書いていけばよい。 各非終端記号には一つのrecursiveな関数が対応する。 それをPL/0'用に書いたものがpl0.jjである。 (JavaCCの使い方を日本語で紹介しているホームページもある。)

yaccのようなLRパーサ生成系では、基本的には合成属性しか使えず、相続属性が書きにくい。 それに対して recursive descent parserでは、相続属性は非終端記号に対応する関数の引数とすればよい。 さらに、recursive descent parserとする場合は、構文規則を正規右辺文法の形で書くことが出来るので、 圧縮した形で書くことが出来る。

なお、JavaCCはLL(k)文法を扱うことが出来るが、デフォールトではlookaheadは1つしかしていない。 したがって、LL(1)文法になっていない部分についてはlookaheadの仕方を指定する必要がある。 PL/0'の文法では、非終端記号factorについて2トークンのlookaheadが必要であるので、 factorメソッドでそれを指定している。

このPL/0'では、変数名などの識別子に日本語の名前が使えるようになっている。 そのためにはpl0.jjの最初に
  options {
    UNICODE_INPUT=true;
  }
としておいて、識別子の定義の中で
  "\u3041"-"\u3093","\u4e00"-"\u9fa5"
などとして、平仮名や漢字のUNICODEの範囲を書けばよい。

Java版のプログラムファイルのうちTable.javaとCodeGen.java, CodeGenB.javaはほとんどそのまま使い、 GetSource.javaはそれらから使われている部分だけを残して、それ以外は削除しました。 ただし、JavaCCが生成するメソッドはstaticメソッドなので、それにあわせてTable.javaとGetSource.java のメソッドはstaticとしました。CodeGen.javaとCodeGenB.javaはそのどちらかのインスタンスを作る ことになるので、それらのメソッドはインスタンスメソッドのままとしました。

使い方はJava版と同じで

   $ java pl0/PL0 オプション指定 ソースファイル名

です.parser generatorを使うとJava版のようなきめ細かいエラーチェックや出力が難しいので、 それらは省略しています。

オプション指定は'-'で始まる1つの文字列で,その中に


Javaでは,目的コードの命令語をクラスのオブジェクトとして表現すると,目的コードの配列は各命令語の参照(ポインタ)の列となる.それがCodeGen.javaで作られる目的コードである.

それに対して,目的コードの配列をバイト(Javaのbyte型)の配列として,各命令語を1〜5バイトで表現するようにしたのがCodeGenB.javaである.オプションで'b'を指定すると,後者が使われる.


トレースでは,簡単のために,スタックのトップと実行する命令を交互に印字する.
ただし,演算のスタックに何も積まれていないときに,スタックのトップにあるように見えるのは,スタックに割当てられた最後の局所変数である.

PL/0'コンパイラのJavaCC版のソースリスト