新Emoji工具: 复制✂粘贴表情📝词典

小计算器/译原理学习日记简单指令型计算器(2)虚拟机的实现

小计算器相关知识 - 译原理学习日记简单指令型计算器(2)虚拟机的实现


  首先,我对指令系统进行了完善,主要是添加了很多三角函数指令,尤其是双曲函数。还有,我修改了操作数和指令的数据类型,通过使用typedef语句,我将操作数类型声明为double、将指令类型声明为unsigned char。这主要体现在inst.h的改动中,我在其中添加了如下声明:


/* type of instructions: */

typedef unsigned char inst_t;


/* type of operands: */

typedef double operand_t;


  这使得我的程序更具伸缩性。当然,这些改动使得我同时改动了汇编编译器和反汇编编译器。如果大家真的感兴趣,而且需要“新版”的计算器,呵呵,老规矩,给我发邮件,我悄悄地告诉你。


  另外还有一件值得高兴的事我要在这里说,我的大学英语四级(国家)考试居然过了!我还是上上次(非典刚过,9月份那次)考的试,都没指望了,也没查过分,而且上次(大概是1月份的吧)都没报名。前两天居然接到通知,60.5!哈哈哈Tracy


  好了,这也不是什么光彩的事,不过觉得很有意思而已。我这种人四级居然能过,中国的教育……

  现在就说说我这个虚拟的计算器的实现吧。程序方面没什么新鲜的,主要是一些想法和其中的数学原理。

  首先,以前已经说过,这个计算器是基于堆栈的。不过,我没有在其中使用任何显式的堆栈数据结构,也没有特地为此建立函数库。原因很简单——效率。我在程序中声明了一个全局数组opStack,类型为operand_t,作为运算栈;以及一个全局变量opSP,类型为unsigned int,作为堆栈指针。堆栈指针的初值为零(因为使用了无符号整型),这可能与一些用数组实现堆栈的程序不太一样;这样,出栈操作类似于:


operand_t operand = opStack[--opSp];


而入栈操作类似于:


opStack[opSp++] = operand;


  也就是说,我的堆栈指针并未指向栈顶元素,而是指向了栈顶元素上面的位置。不过,我在程序中并没有使用这样的操作,稍后将作说明。


  由于使用了固定大小的运算栈,对堆栈的空满状态的检查就显得尤为重要。因为几乎所有的指令都要涉及到出入栈操作,因此,我为栈状态的检查编写了两个宏:


/* check the stack status(overflow): */

  1. define check_overflow() \

  if(opSp >= MAX_STACK_SIZE - 1) { \

  fprintf(stderr, "Operate stack overflow!\n"); \

  exit(0); \

  }


/* check the stack statuc(underflow)

  • n means how many operands are required:
  • /
  1. define check_underflow(n) \

  if(opSp <= n - 1) { \

  fprintf(stderr, "Operate stack underflow!\n"); \

  exit(0); \

  }

  其中,check_overflow()用于检查运算栈是否上溢出,用于所有入栈操作之前;check_underflow()用于检查运算栈是否下溢出,用于所有出栈操作之前。由于所有的指令最多只会将一个操作数压入堆栈,check_overflow()宏是没有参数的,只要检查运算栈中是否有一个空位即可;但是,有的指令需要弹出一个操作数,有的需要两个,所以我为check_underflow()宏添加了一个参数,用来表示需要的检查的最小空间。下面的示意图显示了堆栈的结构和堆栈指针在不同情况下的位置,可以帮助你理解如果获取栈顶操作数(后面会遇到)以及上、下溢出检查的依据。

关于“小计算器/译原理学习日记简单指令型计算器(2)虚拟机的实现”的留言:

目前暂无留言

新增相关留言