日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于堆栈的虚拟机实现

發布時間:2025/6/15 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于堆栈的虚拟机实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面我們對一基于堆棧虛擬機進行了源碼剖析《基于棧的虛擬機源碼剖析》。之前我們也實現了一個簡單的基于堆棧的虛擬機《實現一個堆棧虛擬機》。在《實現一個堆棧虛擬機》中,我們將虛擬機定義為一個VirtualBox類,VirtualBox類中有成員變量:堆棧、指令內存、數據內存,另外還有成員函數:讀取指令、執行指令。《基于棧的虛擬機源碼剖析》中,是C語言實現的,沒有設計成類的形式,但依然有堆棧、指令、數據、讀取指令、執行指令等模塊。

???????? 這里,我們再次實現一個基于堆棧的虛擬機。先給出實現代碼,然后再對代碼進行解釋。

// 基于堆棧的虛擬機實現 #include <iostream> #include <string> #include <vector> #include <stack> using namespace std;// 虛擬機的二進制指令集 enum Command {HALT, IN, OUT, ADD, SUB, MUL, DIV,INMEMORY, /* 存放內存 */OUTMEMORY, /* 讀取內存 */DUP,LD, ST, LDC, JLT, JLE, JGT, JGE, JEQ, JNE, JMP,INVALID };// 指令結構體 struct Instruction {Command com; // 指令碼int opd; // 操作數 };// 堆棧 stack<int> stk;// 指令內存 vector<Instruction> insMemory;// 數據內存 vector<int> datMemory(101);// 狀態碼 enum StateCode {scHALT, scOK,errDIVBYZERO, errDATMEMORY, errINSMEMORY,errSTACKOVERFLOW, errSTACKEMPTY, errPOP,errUNKNOWNOP };// 輸出錯誤信息 void Error(const string& err) {cerr << err << endl; }// 根據指令碼返回指令碼需要的操作數個數 int GetOperandCount(Command com) {int ret = 0;switch (com){case INMEMORY:case OUTMEMORY:case LDC:case JLT:case JLE:case JGT:case JGE:case JEQ:case JNE:case JMP:ret = 1;break;default:ret = 0;break;}return ret; }// 讀取指令 // 從字符串中讀取指令碼和操作數 // 這里讀取的是文本,而非二進制 // 所以指令碼占2位,操作數占4位 void ReadInstruction(const string& strCodes) {int idx = 0;Instruction ins;Command com;int opd;while (idx < strCodes.size()){string strCod = strCodes.substr(idx, 2);idx += 2;cout << strCod;com = static_cast<Command>(atoi(strCod.c_str())); // 字符轉換為指令碼,不檢測com是否合法int cnt = GetOperandCount(com);if (cnt > 0){string strOpd = strCodes.substr(idx, 4);idx += 4;opd = atoi(strOpd.c_str());cout << '\t' << strOpd;}else{opd = 0;}cout << endl;ins.com = com;ins.opd = opd;insMemory.push_back(ins);} }// 執行指令 void ExecuteInstructions() {for (auto idx = 0; idx < insMemory.size() && insMemory[idx].com != HALT; /*++idx*/){bool idxChg = false;int idxJump = 0;switch (insMemory[idx].com){case HALT: // 終止break;case IN: // 輸入 {int tmp;cout << "輸入:" << endl;cin >> tmp;stk.push(tmp);}break;case OUT: // 輸出 {int tmp = stk.top();stk.pop();cout << tmp << endl;}break;case ADD: // 加法 {int a = stk.top();stk.pop();int b = stk.top();stk.pop();int c = b + a;stk.push(c);}break;case SUB: // 減法 {int a = stk.top();stk.pop();int b = stk.top();stk.pop();int c = b - a;stk.push(c);}break;case MUL: // 乘法 {int a = stk.top();stk.pop();int b = stk.top();stk.pop();int c = b * a;stk.push(c);}break;case DIV: // 除法 {int a = stk.top();stk.pop();int b = stk.top();stk.pop();if (a == 0){Error("除數為0");// 忽略 }else{int c = b / a;stk.push(c);}}break;case INMEMORY:{int addr = insMemory[idx].opd;if (addr < 0 || addr >= datMemory.size()){Error("數據地址錯誤");// 忽略處理 }else{datMemory[addr] = stk.top();stk.pop();}}break;case OUTMEMORY:{int addr = insMemory[idx].opd;if (addr < 0 || addr >= datMemory.size()){Error("數據地址錯誤");// 忽略處理 }else{stk.push(datMemory[addr]);}}break;case DUP: // 將棧頂元素的值重復壓棧 {stk.push(stk.top());}break;case LD: // 彈出棧頂元素值,以值為地址,將該地址上的值壓棧 {int addr = stk.top();stk.pop();if (addr < 0 || addr >= datMemory.size()){Error("地址錯誤");// 忽略錯誤 }else{stk.push(datMemory[addr]);}}break;case ST: // 彈出值,再彈出地址,將值賦予該地址 {int val = stk.top();stk.pop();int addr = stk.top();stk.pop();if (addr < 0 || addr >= datMemory.size()){Error("地址錯誤");// 忽略錯誤 }else{datMemory[addr] = val;}}break;case LDC: // 該指令有參數,將該參數壓入棧中 {stk.push(insMemory[idx].opd);}break;case JLT: // 該指令有參數,如果從棧中彈出的值小于0,則指令指針寄存器跳轉到操作數 {int tmp = stk.top();stk.pop();if (tmp < 0){idxChg = true;idxJump = insMemory[idx].opd;}}break;case JLE: // <= {int tmp = stk.top();stk.pop();if (tmp <= 0){idxChg = true;idxJump = insMemory[idx].opd;}}break;case JGT: // > {int tmp = stk.top();stk.pop();if (tmp > 0){idxChg = true;idxJump = insMemory[idx].opd;}}break;case JGE: // >= {int tmp = stk.top();stk.pop();if (tmp >= 0){idxChg = true;idxJump = insMemory[idx].opd;}break;}case JEQ: // == {int tmp = stk.top();stk.pop();if (tmp == 0){idxChg = true;idxJump = insMemory[idx].opd;}}break;case JNE: // != {int tmp = stk.top();stk.pop();if (tmp != 0){idxChg = true;idxJump = insMemory[idx].opd;}}break;case JMP: // 無條件 {idxChg = true;idxJump = insMemory[idx].opd;}break;default:{Error("未知指令碼");}break;}if (idxChg){idx = idxJump;}else{++idx;}} }// 復位虛擬機 void Reset() {insMemory.clear();datMemory.clear();datMemory.resize(101);while (!stk.empty()){stk.pop();} }int main() {// 測試虛擬機// 測試:// 輸入兩個數,并將其比較,將較大者輸出//00 01 #輸入第一個數 IN//01 01 #輸入第二個數 IN//02 07 0001 #將數2存入到內存1中 INMEMORY//03 07 0000 #將數1存入到內存0中 INMEMORY//04 08 0000 #重新將內存0數入棧 OUTMEMORY//05 08 0001 #重新將內存1數入棧 OUTMEMORY//06 04 #將數1減去數2,數1和數2都彈棧,并將結果入棧 SUB//07 15 0011 #檢測棧頂元素是否大于0,如果大于0進行跳轉 JGT//08 08 0001 #如果不大于0,則將內存1輸出,首先還是將內存1數入棧 OUTMEMORY//09 02 #將數1輸出 OUT//10 19 0013 #無條件跳轉到終止 JMP//11 08 0000 #如果大于0,則將內存0輸出,首先還是將內存0數入棧 OUTMEMORY//12 02 #將數0輸出 OUT//13 00 #終止 HALT// 輸入指令為:// 010107000107000008000008000104150011080001021900130800000200while (true){string strCodes;cin >> strCodes;ReadInstruction(strCodes);ExecuteInstructions();Reset();}return 0; }

? ? ? ? ?上面基于堆棧的虛擬機主要包含以下幾部分:

???????? 1.虛擬機的二進制指令集定義

???????? 2.指令結構體定義

???????? 3.堆棧

???????? 4.指令內存

???????? 5.數據內存

???????? 6.狀態碼的定義

???????? 7.錯誤信息的處理

???????? 8.根據指令碼獲取其操作數個數

?????????9.讀取指令,這里我們是從文本中讀取的指令碼和操作數,而不是從二進制數據中讀取。由于指令碼的個數大于9,所以我們的指令碼占2位,另外操作數占據4位,操作數可以是數據內存的地址,也可以是指令內存的地址,或者是具體的數值。

???????? 10.執行指令

???????? 11.復位

???????? 12.測試指令:

???????? 這里我們的測試樣例是:輸入兩個數,將其比較輸出其中較大的哪個數,指令如下:

00 01 #輸入第一個數 IN 01 01 #輸入第二個數 IN 02 07 0001 #將數2存入到內存1中 INMEMORY 03 07 0000 #將數1存入到內存0中 INMEMORY 04 08 0000 #重新將內存0數入棧 OUTMEMORY 05 08 0001 #重新將內存1數入棧 OUTMEMORY 06 04 #將數1減去數2,數1和數2都彈棧,并將結果入棧 SUB 07 15 0011 #檢測棧頂元素是否大于0,如果大于0進行跳轉 JGT 08 08 0001 #如果不大于0,則將內存1輸出,首先還是將內存1數入棧 OUTMEMORY 09 02 #將數1輸出 OUT 10 19 0013 #無條件跳轉到終止 JMP 11 08 0000 #如果大于0,則將內存0輸出,首先還是將內存0數入棧 OUTMEMORY 12 02 #將數0輸出 OUT 13 00 #終止 HALT輸入指令為: 010107000107000008000008000104150011080001021900130800000200

? ? ? ?

? ? ? ? ?另外,對于JLT、JLE、JGT、JGE、JEQ、JNE、JMP這幾個跳轉指令,其操作數是為下一個執行指令的地址,而非當前指令地址的增量。

?

???????? 以上是我們根據《基于棧的虛擬機的實現》,相對于之前的《實現一個堆棧虛擬機》臨摹的另一個版本的堆棧虛擬機。堆棧虛擬機支持更多的指令,比如算術指令、函數操作等有待我們進一步學習。另外,基于寄存器的虛擬機實現原理將在以后的學習中予以介紹。除此之外,還會研讀一些別人的源碼(比如XML解析器的實現),從中學習一些東西。

總結

以上是生活随笔為你收集整理的基于堆栈的虚拟机实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美人妖xxxx | 欧美午夜寂寞影院 | 污污视频免费看 | 国产精品污www在线观看 | 在线免费观看黄色小视频 | 丰满饥渴老女人hd | 免费欧美黄色片 | 久久精品欧美一区二区三区麻豆 | 久久久久久久久久影视 | 致单身男女免费观看完整版 | 伊人久久爱 | 婷婷精品在线 | 久久精品国产亚洲AV成人雅虎 | 久久成人激情 | 精品亚洲永久免费精品 | 一区二区在线播放视频 | 2024av视频| 亚洲欲色| 免费在线h| 日韩免费精品 | 黄色小说网站在线观看 | 欧美三级小说 | 国产精品九色 | 蜜桃在线一区二区 | 人妻视频一区 | 在线观看涩涩 | 米奇狠狠干 | 欧美成人国产精品高潮 | 国产三级观看 | 国产资源精品 | 懂色一区二区二区av免费观看 | 高清视频一区二区三区 | 年下总裁被打光屁股sp | 日韩少妇中文字幕 | 亚洲视频中文字幕 | √天堂资源地址在线官网 | 男女激情实录 | 亚洲天天操 | 欧美激情一二三区 | 精品久久久久久久久久久 | 日韩黄色录像 | 麻豆高清免费国产一区 | 美国色视频 | 解开人妻的裙子猛烈进入 | 99视频在线精品免费观看2 | 精品久久久久久久 | 中文字幕日本人妻久久久免费 | 驯服少爷漫画免费观看下拉式漫画 | 一区二区三区伦理 | 日本欧美韩国国产精品 | 久久一热 | 竹菊影视一区二区三区 | 中文字幕免 | 99热6这里只有精品 三级av在线免费观看 | 国产精品99久久久久久宅男 | 综合久久久 | 精品少妇一区二区三区 | 亚洲黄色大片 | 91精品在线播放 | 亚洲国产一二三区 | 久久久久久久久久久丰满 | 91香蕉视频在线看 | 国产亚洲久一区二区 | 国产三级小视频 | 亚洲专区欧美专区 | 黄色片在线观看免费 | 亚洲成熟丰满熟妇高潮xxxxx | www.夜夜 | 波多野结衣福利 | 一边摸内裤一边吻胸 | 中文字幕一区二区三区四区不卡 | 亚洲另类xxxx | 久久精品高清 | 亚洲视频 中文字幕 | 97国产免费 | 亚洲精品一卡二卡 | 篠田优在线观看 | 久久精品超碰 | 国产成人无码精品久久 | 欧洲美一区二区三区亚洲 | 97色资源 | 日韩av一区二区在线 | 成人福利片 | 亚洲精品在线影院 | 女人扒开腿让男人桶爽 | 国产三区av | 久久噜噜色综合一区二区 | 亚洲欧美国产高清va在线播放 | 精品国产乱码久久久人妻 | 久久99成人 | 亚洲欧洲色图 | 国产三区四区视频 | 加勒比一区在线 | 成人影视在线看 | 性一交一乱一色一视频麻豆 | 青青免费在线视频 | 亚洲自拍偷拍色图 | 丰满人妻一区二区三区精品高清 | 久久久久亚洲精品 |