【原创】【自制编程语言】3.加减乘除运算
如果是从中间来的,建议先从第一篇看起:https://www.cnblogs.com/jisuanjizhishizatan/p/16241991.html
第3天:加减乘除运算
今天我们来继续完善我们的加减乘除的指令。上一次我们支持了mov指令,这次我们来继续写add,sub,mul,div等指令。说是新编写指令,其实只需要改一句话即可。
void add(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){
q=new int;*q=getNum(s2);
}
*p+=*q;//只有这里不同
}
发现了吗?对于add,sub,mul,div等指令,只需要改这里的赋值运算“=”为加减乘除的运算“+=”,“-=”一类的即可。
为了节约篇幅,其他的函数在篇末再和总共的代码一起给出,这样就非常简单了。
好了,接下来我们来编写另外两个指令inc和dec。
inc eax
这样的语句,在C++中等价于:
eax++;
也就是说,inc就是+1的指令,dec就是-1的指令。
对于+1和-1的指令,我们也只需要调用add和sub即可,编写难度也是几乎没有。
else if(s=="inc"){
Word s1;
s1=getword();
add(s1,"1");
}
else if(s=="dec"){
Word s1;
s1=getword();
sub(s1,"1");
}
这一段直接写在main函数中的总循环for(;;)中,也是很好写的。
由于前面的内容很水,接下来我们再写一个简单的功能:使用逗号分隔。
add eax,ebx ;正宗的汇编
add eax ebx ;我们的简易语言
看见了正宗汇编和我们自制的简易语言的区别了没有?也就是说,我们使用逗号来分隔而非空格。这样一来,最早的fscanf读入是按照空格分隔的,因此我们需要进行后期处理。我们定义一个函数getcomma(s,s1,s2),用于把s用逗号分割为s1和s2两个字符串,由于s1和s2在参数中,要想传递必须通过指针。
对于逗号分隔字符串的写法,很多库函数都可以满足我们的需求,这里我使用的是sscanf,看个人习惯,例如strtok等也是可以的。
void getcomma(Word s,Word *s1,Word *s2){//两个操作数,取出逗号
char t1[100],t2[100];
sscanf(s.c_str(),"%[^,],%s",t1,t2);
//printf("[debug]%s %s\n\n",t1,t2);
*s1=t1;*s2=t2;
}
格式串"%[^,],%s"
表示使用逗号来分隔两个字符串。由于传递的参数是string类型(我这里是使用typedef别名定义为Word),因此需要额外使用一次临时变量(sscanf只能传递char*)
这样在main函数中,我们只需要通过getcomma就可以获取两个字符串了。
else if(s=="mov"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
mov(s1,s2);
}
完整代码如下,今天的内容似乎没什么技术含量,我们下期再见。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
using namespace std;
typedef string Word;
int eax,ebx,ecx,edx,esi,edi;
int *ebp,*esp;
Word *eip;
Word wd[32768+10];
Word getword(){
return *(eip++);
}
int *getRegister(Word s){//给定一个寄存器字符串,获取它的地址(地址是因为方便赋值)
if(s=="eax")return &eax;
else if(s=="ebx")return &ebx;
else if(s=="ecx")return &ecx;
else if(s=="edx")return &edx;
else if(s=="esi")return &esi;
else if(s=="edi")return &edi;
else if(s=="ebp")return (int*)&ebp;
else if(s=="esp")return (int*)&esp;//它们都是指针类型,要强制转换一下
else return NULL;
}
int getNum(Word s){//给定一个数字串,获取它的数字形态
int res;
sscanf(s.c_str(),"%d",&res);
return res;
}
void error(){
printf("Error in program: EIP %d\n",eip);
exit(1);
}
void mov(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){//不是寄存器,就看做数字处理
q=new int;*q=getNum(s2);
}
*p=*q;//完成赋值!
}
void debug(){
printf("eax..%d ebx..%d ecx..%d edx..%d\n",eax,ebx,ecx,edx);
printf("esi..%d edi..%d ebp..%d esp..%d\n",esi,edi,ebp,esp);
printf("eip..%p\n",eip);
}
void add(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){
q=new int;*q=getNum(s2);
}
*p+=*q;//只有这里不同
}
void sub(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){
q=new int;*q=getNum(s2);
}
*p-=*q;//只有这里不同
}
void mul(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){
q=new int;*q=getNum(s2);
}
*p*=*q;//只有这里不同
}
void div(Word s1,Word s2){
int *p=getRegister(s1);
if(p==NULL)error();
int *q=getRegister(s2);
if(q==NULL){
q=new int;*q=getNum(s2);
}
*p/=*q;//只有这里不同
}
void getcomma(Word s,Word *s1,Word *s2){//两个操作数,取出逗号
char t1[100],t2[100];
sscanf(s.c_str(),"%[^,],%s",t1,t2);
//printf("[debug]%s %s\n\n",t1,t2);
*s1=t1;*s2=t2;
}
int main(int argc,char** argv){
if(argc!=2){
printf("The syntax of the command is incorrect.\n");
exit(1);
}
FILE *fp=fopen(argv[1],"r");
eip=wd;
for(;;){
char s[100];
int i=fscanf(fp,"%s",s);
if(i==EOF)break;
*eip=s;++eip;//*eip就是读取的指令单词 ,存储在wd数组中
}
eip=wd;
for(;;){
Word s=getword();
if(s=="end"){
exit(0);
}
else if(s=="mov"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
mov(s1,s2);
}
else if(s=="debug"){
debug();
}
else if(s=="add"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
add(s1,s2);
}
else if(s=="sub"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
sub(s1,s2);
}
else if(s=="mul"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
mul(s1,s2);
}
else if(s=="div"){
Word t,s1,s2;
t=getword();getcomma(t,&s1,&s2);
div(s1,s2);
}
else if(s=="inc"){
Word s1;
s1=getword();
add(s1,"1");
}
else if(s=="dec"){
Word s1;
s1=getword();
sub(s1,"1");
}
else{
error();
}
}
return 0;
}