?? interpreter.java
字號:
package compiler.pl0;
/**
* 類P-Code指令類型
*/
enum Fct {
LIT, OPR, LOD, STO, CAL, INT, JMP, JPC, LDA, STA //后兩個是數組操作
}
/**
* 這個類對應C語言版本中的 fct 枚舉類型和 instruction 結構,代表虛擬機指令
*/
class Instruction {
/**
* 虛擬機代碼指令
*/
public Fct f;
/**
* 引用層與聲明層的層次差
*/
public int l;
/**
* 指令參數
*/
public int a;
}
/**
* 類P-Code代碼解釋器(含代碼生成函數),這個類包含了C語言版中兩個重要的全局變量 cx 和 code
*/
public class Interpreter {
// 解釋執行時使用的棧大小
final int stacksize = 500;
/**
* 虛擬機代碼指針,取值范圍[0, cxmax-1]
*/
public int cx = 0;
/**
* 存放虛擬機代碼的數組
*/
public Instruction[] code = new Instruction[PL0.cxmax];
/**
* 生成虛擬機代碼
* @param x instruction.f
* @param y instruction.l
* @param z instruction.a
*/
public void gen(Fct x, int y, int z) {
if (cx >= PL0.cxmax) {
throw new Error("Program too long");
}
code[cx] = new Instruction();
code[cx].f = x;
code[cx].l = y;
code[cx].a = z;
cx++;
}
/**
* 輸出目標代碼清單
* @param start 開始輸出的位置
*/
public void listcode(int start) {
if (PL0.listswitch) {
for (int i = start; i < cx; i++) {
String msg = i + " " + code[i].f + " " + code[i].l +
" " + code[i].a;
System.out.println(msg);
PL0.fa.println(msg);
}
}
}
/**
* 解釋程序
*/
public void interpret() {
int p, b, t; // 指令指針,指令基址,棧頂指針
Instruction i; // 存放當前指令
int[] s = new int[stacksize]; // 棧
System.out.println("start pl0");
t = b = p = 0;
s[0] = s[1] = s[2] = 0;
do {
i = code[p]; // 讀當前指令
p++;
switch (i.f) {
case LIT: // 將a的值取到棧頂
s[t] = i.a;
t++;
break;
case OPR: // 數學、邏輯運算
switch (i.a) {
case 0:
t = b;
p = s[t + 2];
b = s[t + 1];
break;
case 1:
s[t - 1] = -s[t - 1];
break;
case 2:
t--;
s[t - 1] = s[t - 1] + s[t];
break;
case 3:
t--;
s[t - 1] = s[t - 1] - s[t];
break;
case 4:
t--;
s[t - 1] = s[t - 1] * s[t];
break;
case 5:
t--;
s[t - 1] = s[t - 1] / s[t];
break;
case 6:
s[t - 1] = s[t - 1] % 2;
break;
case 8:
t--;
s[t - 1] = (s[t - 1] == s[t] ? 1 : 0);
break;
case 9:
t--;
s[t - 1] = (s[t - 1] != s[t] ? 1 : 0);
break;
case 10:
t--;
s[t - 1] = (s[t - 1] < s[t] ? 1 : 0);
break;
case 11:
t--;
s[t - 1] = (s[t - 1] >= s[t] ? 1 : 0);
break;
case 12:
t--;
s[t - 1] = (s[t - 1] > s[t] ? 1 : 0);
break;
case 13:
t--;
s[t - 1] = (s[t - 1] <= s[t] ? 1 : 0);
break;
case 14:
System.out.print(s[t - 1]);
PL0.fa2.print(s[t - 1]);
t--;
break;
case 15:
System.out.println();
PL0.fa2.println();
break;
case 16:
System.out.print("?");
PL0.fa2.print("?");
s[t] = 0;
try {
s[t] = Integer.parseInt(PL0.
stdin.readLine());
}
catch (Exception e) {}
PL0.fa2.println(s[t]);
t++;
break;
}
break;
case LOD: // 取相對當前過程的數據基地址為a的內存的值到棧頂
s[t] = s[base(i.l, s, b) + i.a];
t++;
break;
case LDA:
int temp = base(i.l, s, b) + i.a + s[t - 1];
s[t - 1] = s[base(i.l, s, b) + i.a + s[t - 1]]; //不用t++了
break;
case STO: // 棧頂的值存到相對當前過程的數據基地址為a的內存
t--;
s[base(i.l, s, b) + i.a] = s[t];
break;
case STA:
t--;
s[base(i.l, s, b) + i.a + s[t - 1]] = s[t];
t--;
break;
case CAL: // 調用子過程
s[t] = base(i.l, s, b); // 將靜態作用域基地址入棧
s[t + 1] = b; // 將動態作用域基地址入棧
s[t + 2] = p; // 將當前指令指針入棧
b = t; // 改變基地址指針值為新過程的基地址
p = i.a; // 跳轉
break;
case INT: // 分配內存
t += i.a;
break;
case JMP: // 直接跳轉
p = i.a;
break;
case JPC: // 條件跳轉(當棧頂為0的時候跳轉)
t--;
if (s[t] == 0) {
p = i.a;
}
break;
}
}
while (p != 0);
}
/**
* 通過給定的層次差來獲得該層的堆棧幀基地址
* @param l 目標層次與當前層次的層次差
* @param s 運行棧
* @param b 當前層堆棧幀基地址
* @return 目標層次的堆棧幀基地址
*/
private int base(int l, int[] s, int b) {
int b1 = b;
while (l > 0) {
b1 = s[b1];
l--;
}
return b1;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -