2014-05-09 39 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