> 文章列表 > 代码生成- 栈式计算机

代码生成- 栈式计算机

代码生成- 栈式计算机

栈式计算机Stack的结构

  • 内存,用于存放程序中声明的所有变量。
  • 栈,用于进行运算的空间。
  • 执行引擎,指令的执行。

栈计算机的指令集(ISA)

指令的语法

s ->  push NUM        栈操作

   ->  load x               访存

   ->  store x              访存

   ->  add                   算术运算

   ->  sub                   算术运算

   -> times                 算术运算

   ->  div                    算术运算

注:我们可以看到这样的7条指令分成了四类, 上述的指令其实就是Java字节码的一个子集,Java字节码是用一个字节来表示字节码中的操作符,所以一个字节的话,Java字节码的指令原则上有256条,但是现在还没完全用完。

指令的语义:push

把整形常量压到栈顶上,栈的规模增加1 

push NUM:top ++;stack[top] = NUM;

指令的语义:load  x

把x从内存读到栈顶上 

load x:top ++;stack[top] = x;

指令的语义:store  x

把栈顶元素弹出去,并且赋值给内存中的x这个变量

store x:x = stack[top];top --;

指令的语义:add

add:temp = stack[top - 1] + stack[top];top -= 2;push temp;

 指令的语义:sub

add:temp = stack[top - 1] - stack[top];top -= 2;push temp;

 指令的语义:times

add:temp = stack[top - 1] * stack[top];top -= 2;push temp;

 指令的语义:div

add:temp = stack[top - 1] / stack[top];top -= 2;push temp;

变量的内存分配伪指令

Stack机器只支持一种数据类型int,并且给变量分配内存的伪指令是:

.int x

伪指令并不会真正的被ALU那样的执行单元来执行,而是Stack机器在装载一个程序时,就会读取伪指令,并且给相关变量分配内存空间

递归下降代码生成算法

从C--到Stack

表达式的代码生成

不变式:表达式的值总在栈顶(注:不变式是在所有可能的情况中都会成立的一个状况)

Gen_E(E e)
{switch (e){case n:emit("push n");break;case id:emit("load id");break;case true:emit("push 1");break;case false:emit("push 0");break;case e1 + e2:Gen_E(e1);Gen_E(e2);emit("add");break;case e1 && e2:Gen_E(e1);Gen_E(e2);emit("times");break;default:break;}
}

语句的代码生成

不变式:栈的规模不变

Gen_S(S s)
{switch (s){case id = e:Gen_E(e);emit("store id");break;case printi(e):Gen_E(e);emit("printi");  // 从栈上拿一个元素弹出来,然后打印到屏幕上break;case printb(e):Gen_E(e);emit("printb");break;default:break;}
}

类型的代码生成

不变式:只生成.int 类型

Gen_T(T t)
{switch (t){case int:emit(".int");break;// 目标机器上只支持整形数,所以我们把布尔类型也翻译成整形case bool:emit(".int");break;default:break;}
}

变量声明的代码生成

不变式:只生成.int 类型

Gen_D(T id; D)Gen_T(T);emit(" id");Gen_D(D);

程序的代码生成

不变式:只生成.int 类型

Gen_P(D S)Gen_D(D);Gen_S(S);

如何运行生成的代码?

1、找一台真实的物理机

2、写一个虚拟机(解释器),类似于JVM,虚拟机可以根据自己定义的Stack指令集做一个定制,并不拘泥于真实的物理机上有没有这条指令,只要虚拟机里支持,那么Stack就可以设置这样一条指令进去。

3、在非栈式计算机上进行模拟,例如,可以在X86上模拟栈式计算机的行为,用X86的调用栈模拟栈,通过操作ebp、esp显式地操作这个栈,所以我们可以把它当做Stack机器上的一个栈,然后用push、pop等操作来模拟执行Stack机器上的指令。注:JVM中的JIT(即时编译)就是采用此种方式,JVM在执行Java字节码的时候,把它动态的翻译成一个底层机器上的代码,比如,底层机器为X86,JIT就会把Java字节码动态的翻译成X86代码,然后用X86代码来模拟字节码指令的行为。