2014-05-09 75 views
0

的字節碼我有一個包含這樣的規則語法:如何產生循環指令

stmt -> ID := expr 
     | print(expr) 
     | if(expr) then (stmt) [ else stmt ]? 
     | while(expr) do stmt 
     | begin stmt [ ; stmt ]* end 

我不知道如何將規則翻譯WHILE字節碼。現在,我寫了這個:

stmt 
    : ID ':''=' expr 
     { 
      if(st.lookupType($ID.text) != $expr.type) { 
       throw new IllegalArgumentException("Type error on variable: " + $ID.text + ".");  
      } 
      int var = st.lookupAddress($ID.text); 
      code.emit(Opcode.ISTORE, var); 
     } 
    | 'print' '(' expr ')' 
     { 
      if($expr.type == Type.INTEGER) { 
       code.emit(Opcode.PRINT); 
      } 
      if($expr.type == Type.BOOLEAN) { 
       code.emit(Opcode.BPRINT);   
      } 
     } 
    | 'if' expr 
     { 
      if($expr.type != Type.BOOLEAN) 
       throw new IllegalArgumentException("Type error in '(expr)': expr is not a boolean."); 
      int ltrue = code.newLabel();  
     } 
     'then' 
     { 
      code.emit(Opcode.LABEL, ltrue); 
     } 
     s1 = stmt ('else' s2 = stmt)? 
    | 'while' expr 
     { 
      if($expr.type != Type.BOOLEAN) 
       throw new IllegalArgumentException("Type error in '(expr)': expr is not a boolean."); 
      //Bytecode generator 
      // CODE... 
     } 
     'do' 
     ( 
      s1 = stmt 
      { 
       int ltrue = code.newLabel();  
      } 
     )*  
    | 'begin' s1 = stmt (';' s2 = stmt)* 'end'  
    ; 

st是一個符號表,也就是包含某個特定變量的類型的表。

在我的語法中只能有兩種類型:INTEGER或BOOLEAN。

方法newLabel()只不過是創建一個新的標籤,如L1,L2,L3等字符串,只需遞增一個計數器即可。

code是CodeGenerator的一個實例,它是一個數據結構(Vector <Instruction>),它存儲在解析程序期間生成的字節碼指令。

Instruction類由兩個字段(opcodeoperand)組成,代表單字節代碼指令。

如何生成循環的字節碼,如WHILE? 由於


修改後的代碼:

'while' 
    { 
     int lloop = code.newLabel(); //label for loop 
     int ldone = code.newLabel(); //laber for done 
     code.emit(Opcode.LABEL, lloop); 
    } 
    expr 
    { 
     if($expr.type != Type.BOOLEAN) 
      throw new IllegalArgumentException("Type error in '(expr)': expr is not a boolean."); 
     code.emit(Opcode.GOTO, ldone); 
    } 
    'do' (stmt)* 
     code.emit(Opcode.GOTO, lloop); 
     code.emit(Opcode.LABEL, ldone); 
    } 
+0

這是一個很模糊的問題,我很害怕。我們甚至不知道你的指令集是什麼樣的,所以我們如何告訴你如何從while循環生成代碼? –

+0

@TheantLRGuy謝謝你的回答,有什麼不清楚的?我可以詳細說明問題。 – user3602008

+0

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html – Holger

回答

0

while循環的最簡單的表達式是:

LOOP: 
     <condition> 
     jmp_if_false DONE; 
     <body> 
     jmp LOOP 
DONE: 

這可能在僞代碼翻譯成:

'while' { 
       Create loop_label 
       Create done_label 
       Emit Label loop_label 
     } 
expr { 
       Emit Jump_If_False to done_label 
     } 
'do' stmt* { 
       Emit Jump to loop_label 
       Emit Label done_label 
     } 

有一個重新進行各種可能的優化,但這至少是一個開始。

+0

非常感謝您的建議,我根據您的模式修改了代碼,但仍然不起作用。你能幫我嗎?修改後的代碼在下一個答案中。謝謝 – user3602008

+0

@ user3602008:我真的無法幫助你,因爲我不知道你的中間語言是什麼樣的。但重要的是你需要*有條件*跳轉到done_label。無條件的跳躍將會(顯然)跳過while body。 – rici