JavaCCとJJTreeを使ってjavaコードをC++へ変換 その1

これはjavaのコードをC++のコードへ変換するために必要な項目をまとめたメモです。(随時修正してます。)
社内用のトランスレータなのでいろんな制限があります。

  • javaのクラスライブラリは使えない。
  • コードはC++にそのまま持っていけそうな書き方しかできない。for-each文とか書けないということ。
  • ガベージコレクタは搭載しない。

プログラムの書き方にも制限があります。
javaで書かれた携帯アプリをBREW用のC++コードに変換するのが前提ですが、それぞれのSDKを使ったコードまで変換するのは大変なので、あらかじめ自前のライブラリでラップしておく必要があります。
javaのクラスライブラリを用いる場合も同様にラップしたクラスを用意します。

例としてApplicationクラスを用意し画面サイズを取得する関数getWidth()を定義します。JavaのソースにApplication.getWidth()が書いてあってもBREW用のC++ソースではApplication::getWidth()と翻訳すれば済みます。


javaBREWで同じ機能が同じ名前のクラスから提供されるのであればかまいません。
BREWの場合stringクラスくらいはないと困るので用意します。


javaソースはコンパイルが通るものに限定。

変換方法

パッケージ宣言、インポート宣言

パッケージ宣言などはnamespaceでくくるのが良いかも。
今回翻訳しようとしてるソースはパッケージ宣言がなかったので特に対応しない。

クラス宣言

extendsとimplementsをpublicに置き換え,で結合

インスタンス変数

プリミティブ型はそのまま。
クラス型変数はポインタ型にする。
プリミティブ型の配列はポインタ型
クラス型の配列は**型にする。(クラス型のポインタのポインタ型)

多次元配列は次元数に応じた数の初期化コードを生成する。
以下のようなフィールドは

class Foo{
  private int[][] a = new int{{1, 2},{3, 4}};
}

このように展開する

class Foo{
private:
  int **a;
public:
  Foo(){
    a=static_cast<int**>(System::new_array(2, 2, sizeof(int*)));
    a[0]=static_cast<int*>(
        System::new_array(1, 2, sizeof(int)));
    a[1]=static_cast<int*>(
        System::new_array(1, 2, sizeof(int)));
    a[0][0] = 1;
    a[0][1] = 2;
    a[1][0] = 3;
    a[1][1] = 4;
  }
  ~Foo(){
    System::delete_array<int*>(a);
  }
};

ここでSystem::new_arrayは内部でメモリの確保を行うが、その時ポインタの次元数、サイズ、要素数を記録する。
System::delete_arrayは書き込まれている次元数を元にネストをたどって全てdeleteする。
ジャグ配列であっても対応は可能。
メソッド中のnewも全てSystem::new_arrayに置き換えることでほとんどのケースに対応できると思われる。

定数 finalで宣言された変数

定数はstatic constとする。インスタンス変数もstatic constにする。
(配列で宣言されたインスタンス変数を扱えないので、定数のインスタンス変数をstaic constつまりクラス変数に変換する)
C++では1次元目の添字しか省略できないため、まずは配列の定数は1次元のみを対象とする。

クラス変数

検討中
 BREWではARMコンパイラとelf2modでstatic変数が使えるはずですが未検証に付き検討中です。
 それとstatic変数はコンストラクタが呼ばれないらしいので注意が必要です。
(参照 2009-04-24 - melpon日記 - HaskellもC++もまともに扱えないへたれのページ)
現状シングルトンパターンで実装し直してなるべくstatic変数を使わないようにしています。シングルトンパターンを実装したクラスのインスタンスを保持するクラス変数はApplicationクラスに実装し、Applicationのインスタンスアプレット構造体に保持しいつでもアクセスできるようにしています。

メソッド

ポインタ型へのアクセスを->に変更したり、クラスの定数へのアクセスを.から::へ変えるといった対応を行う。

アクセス修飾子はpublic: private: protected:と変換する。

基底クラスのメソッドをvirtualにしたり、abstructクラス、abstructメソッドの変換は行いません。現状変換対象のコードに継承関係のあるコードがないので。

可変引数は対応しない。


方針は以上のような感じです。
いくつかはJavaCCとJJTreeによる構文解析で済みますが、ポインタ変数のアクセスをアロー演算子に置き換える処理やその他のコードの追加は意味解析まで行わなければならないので少々厄介です。

続きは次回。
第2回目