1

我正在研究一個與編譯器設計相關的項目。我需要爲基於Java的語言生成三個地址代碼,這意味着使用對象和範圍。我想如果你能幫助我產生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;   
    }   
} 

回答

2

首先你需要知道的「對象佈局」或換句話說,運行時對象在內存(RAM)中的外觀如何。對此沒有標準,但大多數編譯器以類似的方式創建對象。我們將假設執行將發生在x86(32位)機器上,所以指針是4B或32位,而對於64位(x64)機器,指針是8B。所以對象「A」看起來像這樣:「A」對象的第一個4Bytes將是指向虛擬指針表的指針。接下來的4Bytes或偏移量4到8將存儲「int x」。偏移8至12將存儲指向「字符串y」的指針。類A的虛擬指針表可以是空的或者對象中的偏移量0上的指針可以是NULL - 這取決於編譯器。至於班級「B」的情況是相似的。偏移0將存儲VPT(虛擬指針表)的地址,偏移4「int f」和偏移8指針指向「A foo」。在B的VPT中,「createFoo」地址將被存儲在偏移0處,因爲它只是B類中的方法。現在,讓我們做的實現:

_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 

現在讓我們來實現主:

_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 

正如你可以看到它是不是太硬,但有一些工作要做。希望這有助於。

+0

我能完成我的項目。不管怎麼說,還是要謝謝你。只是一個評論......類似於「TAC生成」的字符串我在堆內存中逐字節地分配字節。 – 2013-06-25 17:18:31

+0

幹得好。我很高興我的幫助。問候。 – 2013-06-25 18:39:42

+0

僅供參考,StackOverflow禮儀可以「接受」您的問題的最佳答案,以便答案的作者爲他的努力獲得信譽積分。 – 2013-10-11 16:39:28