小計算器/譯原理學習日記簡單指令型計算器(2)虛擬機的實現
/* 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): */
- 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:
- /
- define check_underflow(n) \
if(opSp <= n - 1) { \
fprintf(stderr, "Operate stack underflow!\n"); \
exit(0); \
}
其中,check_overflow()用於檢查運算棧是否上溢出,用於所有入棧操作之前;check_underflow()用於檢查運算棧是否下溢出,用於所有出棧操作之前。由於所有的指令最多只會將一個運算元壓入堆疊,check_overflow()巨集是沒有參數的,只要檢查運算棧中是否有一個空位即可;但是,有的指令需要彈出一個運算元,有的需要兩個,所以我為check_underflow()宏添加了一個參數,用來表示需要的檢查的最小空間。下面的示意圖顯示了堆疊的結構和堆疊指標在不同情況下的位置,可以幫助你理解如果獲取棧頂運算元(後面會遇到)以及上、下溢出檢查的依據。