forked from gdut-yy/PL0
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInterpreter.java
More file actions
218 lines (205 loc) · 4.36 KB
/
Copy pathInterpreter.java
File metadata and controls
218 lines (205 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package net.devyy;
/**
* 类P-Code指令类型
*/
enum Fct {
LIT, OPR, LOD, STO, CAL, INT, JMP, JPC
}
/**
* 这个类对应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 STO: // 栈顶的值存到相对当前过程的数据基地址为a的内存
t--;
s[base(i.l, s, b) + i.a] = s[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;
}
}