【原創】【自制程式語言】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;
}