1

私はコンパイラの設計に関連するプロジェクトに取り組んでいます。Java ベースの言語用に 3 つの住所コードを生成する必要があり、これはオブジェクトとスコープの使用を意味します。次の例の TAC を生成するのを手伝っていただけないでしょうか (またはチュートリアルを参照してください)。

class A {
    int x;
    String y;

    public A(int x, String y) {
       this.x = x;
       this.y = y;
    }
}

import A;

class B {
    int f;
    A foo;

    public B() {
       this.foo = null;
       this.f = -1;
    }

    public boolean createFoo() {
       this.foo = new A(0, "TAC Example");
       return true;
    } 

    public static void main() {
       B bar = new B();
       A baz = new A(666, "TAC generation");
       bar.createFoo();
       bar.foo.y = "Hello World";
       if(bar.foo.x == 666)
           return;
       bar.foo.x = baz.x;           
    }        
}
4

1 に答える 1

5

まず最初に、「オブジェクト レイアウト」、つまり実行時にオブジェクトがメモリ (RAM) 内でどのように見えるかを認識する必要があります。これには標準はありませんが、ほとんどのコンパイラは同様の方法でオブジェクトを作成します。実行は x86 (32 ビット) マシンで行われると仮定するため、ポインタは 4B または 32 ビットであり、64 ビット (x64) マシンではポインタは 8B です。したがって、オブジェクト「A」は次のようになります。「A」オブジェクトの最初の 4 バイトは、仮想ポインタ テーブルへのポインタになります。次の 4Bytes またはオフセット 4 ~ 8 には、「int x」が格納されます。オフセット 8 から 12 には、「文字列 y」へのポインタが格納されます。クラス A の仮想ポインター テーブルを空にするか、A オブジェクトのオフセット 0 のポインターを NULL にすることができます (コンパイラによって異なります)。クラス「B」についても状況は似ています。オフセット 0 は VPT (仮想ポインター テーブル) のアドレスを格納し、オフセット 4 は "

_B.createFoo:
    BeginFunc 12    // stack frame size = 3 registers * sizeof( each_register )
    _t0 = 8         // size of A object
    PushParam _t0   // this is the memory ammount that we are asking
    _t1 = LCall _Alloc  // allocate memory
    PopParams 4     //  clear stack
    _t2 = A
    *(_t1) = _t2    // load VPT
    *(_t1 + 4) = 0  // initialize _A.x
    *(_t1 + 8) = "TAC Example"  // initialize _A.foo
    *(this + 8) = _t1
    Return 1
    EndFunc

それでは、main を実装しましょう。

_B.main:
    BeginFunc 68    // 15 * 4 + 2 * 4 
    _t0 = 8         // size of B object
    PushParam _t0   // memory amount that we need
    _t1 = LCall _Alloc  // allocate memory
    PopParams 4     //  clear stack
    _t2 = B
    *(_t1) = _t2    // load VPT
    *(_t1 + 4) = 0  // initialize _B.foo
    *(_t1 + 8) = -1 // initialize _B.f
    bar = _t1
    _t3 = 8         // size of A object
    PushParam _t3   // this is the memory ammount that we are asking
    _t4 = LCall _Alloc  // allocate memory
    PopParams 4     //  clear stack
    _t5 = A
    *(_t4) = _t5    // load VPT
    *(_t4 + 4) = 666    // initialize _A.x
    *(_t4 + 8) = "TAC generation"   // initialize _A.foo
    baz = _t4
    _t6 = *(bar)    // address of _B.VPT
    _t7 = *(_t6)    // address of _B.createFoo
    PushParam bar   // this for createFoo
    ACall _t7       // call _B.createFoo
    PopParams 4     // clear stack
    _t8 = *(bar + 8)    // get _B.foo
    _t9 = *(_t8 + 8)    // get _B.foo.y
    *(_t9) = "Hello world"  // set _B.foo.y value
    _t10 = *(bar + 8)   // get _B.foo
    _t11 = *(_t10 + 4)  // get _B.foo.x
    _t12 = _t11 == 666  // test _B.foo.x equal to 666
    IfZ _t12 GoTo _L0   // if not equal continue to _L0
    Return
    _L0:
    _t13 = *(bar + 8)   // get _B.foo
    _t14 = _t13 + 4     // get address of _B.foo.x
    _t15 = *(baz + 4)   // get _A.x
    *(_t14) = _t15      // set _B.foo.x
    EndFunc

ご覧のとおり、それほど難しくはありませんが、やるべきことがいくつかあります。これが役立つことを願っています。

于 2013-06-25T03:21:11.930 に答える