フロントエンド

5. フロントエンド

フロントエンドはソースプログラムを解析して、それをHIRのツリーに変換するものである。

5.1. 既存のフロントエンド

COINSのリリースに入っているフロントエンドには以下のものがある。

5.1.1. Cフロントエンド

5.1.1.1. C言語仕様
言語仕様はISO規格の
   ISO/IEC 9899:1990 Programming Language C
に従っている。これは、1990年版ANSI Cと呼ばれているものと同じである。
ただし、以下のものはサポートしていない。

なお、long double型はdouble型と同じサイズである。 また、前処理とライブラリはgccのものが使われることを仮定している。

5.1.1.2. Cフロントエンドの使い方
Cフロントエンドは次の形のコマンドによって呼び出すことが出来る。
   java coins.driver.Driver オプション指定  ソースファイル名
「オプション指定」については 2.2. コンパイラ・ドライバの使い方 を参照されたい。

「ソースファイル名」は".c"で終わるものでなければならない。

必要なソフトウェア
以下のコマンドが実行出来るようになっていなければならない。

それらが使えず、代わりにものがある場合、たとえば、 アセンブラとして"gas"でなく"as"が使える場合は

   -coins:assembler=as
というオプション指定をすればよい。より詳しくは ここ
   -coins:preprocessor/assembler/linker
の記述を参照されたい。
5.1.1.3. Cフロントエンドの構成
C言語には演算と代入の機能を併せ持つ複合代入演算子などがあるので、そのようなC言語の演算子をそのまま表現できる機能をHIRに追加したHIR-Cを定め、HIR-Cを経由してHIRに変換する方式とした。また、HIRを作成する際に無駄を省くため、簡単な効率化機能も組み込んだ。したがって、HIRへの変換過程は次のようになっている。

  1. Cプログラムを抽象構文木ASTに変換
  2. このモジュールはcoins.cfrontとcoins.astパッケージにある。
  3. ASTをHIR-Cに変換
  4. このモジュールはcoins.casttohirパッケージにある。
  5. HIR-CをHIRに変換
  6. このモジュールはcoins.casttohirパッケージにある。
  7. HIRに対する最適化化変換

 Cの前処理系にはgccの前処理系cppを利用する。また、実行時ライブラリもgccのものを利用することにし、インタフェースをgccに合わせている。

-coins:hirOpt=fromc
というオプション指定をすると、HIR生成時に次のような最適化を行う。
ただし、この指定がなくても、同様な最適化がHIRの基本最適化や バックエンドの最適化で行われるので、生成されるコードに対する効果は あまりないが、生成されるHIRが多少短くなる。
  1. 打ち消しあう演算の削除
  2.    *&v    -->  v
        -(-v)  -->  v、 他
    
  3. 特定の定数に対する演算
  4.    v +  0  -->  v		  v -  0  -->  v
       v *  0  -->  0		  v *  1  -->  v, 他
    
  5. 条件式の効率化
  6.     !(a<b)  -->  a>=b
       定数A 比較演算子 定数B  -->  true または false, 他
       e1 && e2  でe1がtrue  -->  e1の副作用,e2
       r = (a=1)>0 ? 1 : 0;  -->  r = (a=1) , 1;   他
    
  7. 無駄な文の削除
  8.    到達不能の式文/return/goto  -->  削除
       ジャンプ距離が0のgoto       -->  削除
       参照されないラベル          -->  削除
       連続するラベル              -->  ラベルの統合
       空のブロック                -->  削除
       式文                    -->  副作用だけ残して他の部分を削除
    
  9. 条件式が定数(trueまたはfalse)の場合のif文の展開
  10.    if(true) THEN部; else ELSE部; --> { THEN部; goto LABEL_END; ELSE部; LABEL_END:; }, 他
    
  11. 条件式が定数(trueまたはfalse)の場合のループ文の展開
  12.    while(false) BODY部;
    	--> { goto LABEL_BREAK; BODY部; LABEL_BREAK:; }
       for(INIT部;false;STEP部) BODY部;
    	--> { INIT部; goto LABEL_BREAK; BODY部; STEP部; LABEL_BREAK:; }
       do BODY部; while(false);             --> BODY部;
       他
    
詳しくは、COINSのソース・アーカイブのdoc-en/CfrontOpt.txtを参照されたい。

5.1.2. Fortranフロントエンド

5.1.2.1. Fortran言語仕様
言語仕様はFortran 77にしたがっている。Fortran 77の規格文書としては以下のものが あるが、内容的にはすべて同じである。

ただし、以下の制限がある。

以下のものはFortran 77の規格の仕様には入っていないが、ベンチマークプログラム などでもよく使われているので、サポートしている。

5.1.2.2. Fortranフロントエンドの使い方
Fortranフロントエンドは次の形のコマンドによって呼び出すことが出来る。
   java coins.driver.F77Driver オプション指定  ソースファイル名
「オプション指定」については 2.2. コンパイラ・ドライバの使い方 を参照されたい。

「ソースファイル名」は".f"で終わるものでなければならない。ソースファイル名は "foo.f bar.f ..."のようにいくつか並べても良い。

なお、

   -coins:printhir
というオプションを指定すると、FortranプログラムをHIRに変換した後で、HIRの木と シンボルテーブルを出力する。

これは、coins.driver.F77Driverの中に、次のような記述があるからである。 このようにして、任意のオプションを追加することが出来る。

   if (io.getCompileSpecification().getCoinsOptions().isSet("printhir")) {
      hirRoot.programRoot.print(0);
      io.printOut.print("¥n");
      symRoot.symTable.printSymTableAllDetail(symRoot.symTableRoot);
      symRoot.symTableConst.printSymTableDetail();
      io.printOut.print("¥n");
    }
必要なソフトウェア
Cで必要なソフトウェアはFortranでも必要である。

その他に、実行時ライブラリとして"libf2c"が必要である。このライブラリは http://www.netlib.org/f2c/libf2c.zip をダウンロードして、その中にあるREADMEにしたがってインストールすれば良い。

UNIX系のOSの場合、解凍したlibf2cのディレクトリで

% cp makefile.u Makefile
% make
を実行して得られる"libf2c.a"を適当なところにおいて、その置き場所を Fortran Driverに認識させれば良い。そのためには
libf2cLocation	  /directory/path/where/libf2c.a/exists
のように、"libf2c.a"の置き場所を指定する行を含んだファイルを"settings"という名前で ライブラリ・ディレクトリに置けば良い。

ライブラリ・ディレクトリは、特に指定しない場合は、

~/coins/
となっているので、そこに"settings"ファイルを置けば良い。

なお、cygwinの場合は、上記の手続きに少し修正が必要である。まず、上記のMakefileの中にある"a.out" を"a.exe"に変更する必要がある(2ヶ所)。また、cygwinでは、上記のライブラリ・ディレクトリを認識せず、 現在作業中のディレクトリを探すようであるので、"settings"ファイルは作業中のディレクトリに置いておく必要がある。

5.1.2.3. Fortranフロントエンドの構成
coins.driver.F77Driverはcoins.driver.Driverのサブクラスであり、 フロントエンド呼び出しのメソッドをオーバライドしているだけである。 したがって、coins.driver.Driverのほとんどの機能はそのまま使うことが出来る。

Fortran言語には、ENTRY文、assigned GOTO文など、最近の言語にはない ものとしてHIRには用意されてない機能がいくつかある。それらについては プログラム変換をしている。おおまかには、それと等値な働きをするCプログラムを 考えて、それのHIRに相当するものに変換している。

HIRへの変換過程は次のようになっている。

  1. FortranプログラムをFortran用中間表現Firに変換
  2. FirをHIRに変換

これらのモジュールはcoins.ffrontパッケージにある。そのディレクトリ内にある

によって字句解析と構文解析が行われる。

詳しくは Fortran特有の機能に対する考慮Fortranコンパイラの設計、を参照されたい。

5.1.3. Javaフロントエンド

Javaのフロントエンドは以下の方針で開発しているが、デバッグ中であるので、リリース版にはまだ入っていない。

Javaではプログラムがソースプログラムとしてではなく、クラスファイルとして提供されることが多い。Javaソースプログラムを入力とする言語処理系を作ったとしても、クラスファイルを入力とするものも必要となる。そこで、COINSではJava言語を入力とするのではなく、それから作られたクラスファイルを入力としてHIRを生成する。JavaプログラムはHIRとLIRを経て機械語に変換されるが、それを実行する時には通常のJava仮想機械が持つ機能も必要になる。それらの機能を少ない人数で短期間に作ることは困難なので、gnu gcjの実行時ライブラリを利用することにし、インタフェースをそれにあわせた。

 Javaの実現にあたっては、オブジェクトの生成と例外処理が大きい課題となる。オブジェクトのデータ構造はgcjにあわせる。例外処理の方法としては、表引き法、2返戻値法などがあるが。gcjは表引き法を採用している。これをHIRで表現するには、HIRに例外処理の機構を組み込む必要があり、それはHIRだけでなく、バックエンドなど、COINSのほぼ全体に対する改造が必要となる。そこで、Javaの例外処理の実現にあたっては、2返戻値法を使うことにして、メソッド呼び出し時にgcjの表引き法が必要とする情報を付加するつなぎの処理を挿入することにした。

5.2. 新しいフロントエンドの作り方

COINSで新しいフロントエンドを作った例としては、C0コンパイラ、PL0コンパイラ、Simpleコンパイラ、 Fortranコンパイラなどがある。
最初のC0コンパイラについては、情報処理学会誌のVol.47のNo.4とNo.5に連載された 「21世紀のコンパイラ道しるべ ・・COINSをベースにして」に説明がある。 後ろの3つのコンパイラについては、それらの説明が下記のページにあるので、 それを参照されたい。 http://www.coins-project.org/advanceduse/compilerDevelop.html

5.2.1. JavaCC(LLパーサ生成系)を使った例

C0コンパイラのフロントエンドのJavaCCによる記述は http://www.coins-project.org/IPSJ-mitisirube/ のc0frontを参照されたい。

PL0コンパイラのフロントエンドのJavaCCによる記述は http://www.coins-project.org/advanceduse/ll/coinsCompilerPL0.html を参照されたい。

5.2.2. LRパーサ生成系を使った例

C0コンパイラのフロントエンドのnotavaccによる記述は http://www.coins-project.org/IPSJ-mitisirube/ のc0front2を参照されたい。

Simpleコンパイラのフロントエンドのjayによる記述は http://www.coins-project.org/advanceduse/simple/coinsCompiler.html を参照されたい。