[CS@Nets][编译原理]一个栈式计算机的加法语言编译器

本文介绍了如何构建一个从Sum语言到栈计算机Stack的编译器,涉及C语言和数据结构的应用。文章中提供了源代码,包括前端分析输入语言并构建语法树,后端将语法树翻译为push和add指令。重点在于编译器的后端实现,通过递归后序遍历语法树并将结果存储到链表中。最后,通过递归逆序打印链表以完成常量折叠优化的加分题。作者强调了数据结构、算法和交流学习的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:(本题目是一个动手实践类题目,需要具备C语言和数据结构基础。)
在课程中,我们讨论一个小型的从表达式语言Sum到栈计算机Stack的编译器,
在附件中,你能找到对该编译器的一个C语言实现,但这个实现是不完整的,请你 把缺少的代码补充完整(不超过10行代码)。
加分题:实现常量折叠优化。

源代码详见:
http://mooc.study.163.com/learn/USTC-1000002001#/learn/content?type=detail&id=1000140056&cid=1000125134

由题目要求,Sum语言只有两种“符号”,整数+,栈计算机Stack只支持两种指令pushadd,例如3+4+5转换为

push 3
push 4
add
push 5
add

思路分析
编译器分为前端和后端,前端负责将输入语言进行分析,并保存在语法树种;后端将其翻译为指令。

源代码分析与补全
本代码中的前端部分直接以程序的形式给出,

struct Exp_t *exp = Exp_Sum_new (Exp_Sum_new(Exp_Int_new (2), Exp_Int_new (3)), Exp_Int_new (4));
printf ("the expression is:\n");
Exp_print (exp);

Exp_Sum_new()函数即直接构造了一个二叉树,
Exp_print (exp)采用中序遍历将二叉树打印出来,

然后进入compile(exp)函数,这里使用了链表,链表负责顺序存储指令并打印出来,另有一个Stack系列的结构体存放指令。

需要填写的代码有两处
a. 一个是在compile( )中利用递归,后序遍历语法树,并保存到链表中。

void compile(struct Exp_t *exp)
{
  switch (exp->kind){
  ...
  case EXP_SUM:{
    struct Exp_Sum *p = (struct Exp_Sum *)exp;
    if(p->left != NULL) compile(p->left);
    if(p->right != NULL) compile(p->right);
    emit(Stack_Add_new());
    break;
  }
  ...
}

b. 是把链表逆序打印出来;因为这个链表是顶端插入,所以必须逆序打印。本来写了一个数组,先顺序把结果保存到数组中,再把数组输出。后来在讨论区得到了提示,用递归的方法输出。所以,最后递归逆序输出链表的代码如下

void List_reverse_print (struct List_t *list)
{
  if(list->next != NULL)
    List_reverse_print(list->next);
  if(list->instr->kind == STACK_ADD)
      printf("\nADD");
   else
      printf("\nPUSH %d",((struct Stack_Push *)(list->instr))->i);
}

结论
1. 后序遍历4行+倒序输出6行,共10行代码完成了任务;
2. 数据结构很重要;
3. 算法很重要,不仅要知道更要会应用;
4. 要善于搜索和交流;树的递归遍历算法我已经忘了,是百度出来的;单向链表的逆向输出,其实很早就碰到过这个问题,一直使用很笨的方法解决的,没想过用了递归如此简洁明了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值