代码生成- 栈式计算机

文章介绍了栈式计算机的结构,包括内存、栈和执行引擎,并详细阐述了其简单的指令集,如push、load、store、算术运算等。此外,还讨论了从C--到栈的递归下降代码生成算法,以及变量声明和语句的代码生成过程。最后提到了在非栈式计算机上模拟栈式计算机行为的方法,如通过虚拟机或X86的调用栈来实现。
摘要由CSDN通过智能技术生成

栈式计算机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代码来模拟字节码指令的行为。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫客36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值