まず最初に、「オブジェクト レイアウト」、つまり実行時にオブジェクトがメモリ (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
ご覧のとおり、それほど難しくはありませんが、やるべきことがいくつかあります。これが役立つことを願っています。