4
|
1 //
|
5
|
2 // 仮想CPU
|
4
|
3 //
|
|
4 // (c)2008 Chihiro.SAKAMOTO HyperWorks
|
|
5 //
|
|
6 #ifndef __VM_H__
|
|
7 #define __VM_H__
|
|
8
|
|
9 #include <vector>
|
|
10 #include "vm_value.h"
|
|
11
|
|
12 #ifdef _MSC_VER
|
|
13 //
|
5
|
14 // VS2008では、セキュアライブラリ関数(*_s)を使うよう警告が出ます。
|
|
15 // ここでは、一般化(gcc等の対応)のため、旧ライブラリを使用しているので、
|
|
16 // 警告を抑止しています。
|
4
|
17 //
|
|
18 #pragma warning(disable: 4996)
|
|
19 #endif
|
|
20
|
|
21 #define VM_ENUMDEF
|
|
22 enum {
|
|
23 #include "vm_code.h"
|
|
24 VM_MAXCOMMAND,
|
|
25 } ;
|
|
26 #undef VM_ENUMDEF
|
|
27
|
|
28 namespace vm {
|
|
29
|
|
30 enum {
|
|
31 SYS_PRINT,
|
|
32 SYS_TOSTR,
|
|
33 } ;
|
|
34
|
|
35 class data {
|
|
36 public:
|
|
37 data(): command_(0), text_buffer_(0)
|
|
38 {
|
|
39 }
|
|
40 ~data()
|
|
41 {
|
|
42 delete[] command_;
|
|
43 delete[] text_buffer_;
|
|
44 }
|
|
45
|
|
46 public:
|
5
|
47 unsigned char *command_; // コマンドテーブル
|
|
48 char *text_buffer_; // テキストデータ
|
|
49 int command_size_; // コマンドサイズ
|
|
50 int text_size_; // テキストサイズ
|
|
51 int value_size_; // グローバル変数サイズ
|
|
52 int entry_point_; // 開始位置
|
4
|
53 } ;
|
|
54
|
|
55
|
5
|
56 // 0除算例外
|
4
|
57 class devide_by_zero: public std::exception {
|
|
58 public:
|
|
59 const char *what() const throw()
|
|
60 {
|
|
61 return "devide by zero";
|
|
62 }
|
|
63 } ;
|
|
64
|
5
|
65 // 仮想マシン
|
4
|
66 class vcpu {
|
|
67 public:
|
5
|
68 const static int STACK_SIZE = 1000; // スタックサイズ
|
|
69 const static int global_flag = 0x4000000; // 外部変数フラグ
|
4
|
70 const static int global_mask = 0x3ffffff;
|
|
71
|
|
72 public:
|
|
73 vcpu(data &mem)
|
|
74 : data_(mem)
|
|
75 {
|
|
76 }
|
|
77 ~vcpu()
|
|
78 {
|
|
79 }
|
|
80
|
|
81 int run();
|
|
82
|
|
83 private:
|
5
|
84 // 定数Push
|
4
|
85 void PushConst(int val)
|
|
86 {
|
|
87 push(val);
|
|
88 }
|
|
89
|
5
|
90 // 文字定数Push
|
4
|
91 void PushString(int val)
|
|
92 {
|
|
93 push(std::string(text_buffer_ + val));
|
|
94 }
|
|
95
|
5
|
96 // 変数Push
|
4
|
97 void PushValue(int val)
|
|
98 {
|
|
99 push(global_value[val]);
|
|
100 }
|
|
101
|
5
|
102 // ローカル変数Push
|
4
|
103 void PushLocal(int val)
|
|
104 {
|
|
105 push(stack[val + stack_base]);
|
|
106 }
|
|
107
|
5
|
108 // 配列からPush
|
4
|
109 void PushArray(int val)
|
|
110 {
|
|
111 int index = top().i_; pop();
|
|
112 push(global_value[val + index]);
|
|
113 }
|
|
114
|
5
|
115 // ローカルの配列からPush
|
4
|
116 void PushLocalArray(int val)
|
|
117 {
|
|
118 int index = top().i_; pop();
|
|
119 push(stack[val + stack_base + index]);
|
|
120 }
|
|
121
|
5
|
122 // ローカル変数(参照)Push
|
4
|
123 void PushLocalRef(int val)
|
|
124 {
|
|
125 int addr = stack[val + stack_base].i_;
|
|
126 push(ref_to_value(addr));
|
|
127 }
|
|
128
|
5
|
129 // ローカルの配列(参照)からPush
|
4
|
130 void PushLocalArrayRef(int val)
|
|
131 {
|
|
132 int addr = stack[val + stack_base].i_;
|
|
133 int index = top().i_; pop();
|
|
134 push(ref_to_value(addr + index));
|
|
135 }
|
|
136
|
5
|
137 // アドレスをPush
|
4
|
138 void PushAddr(int val)
|
|
139 {
|
|
140 if ((val & global_flag) == 0) // local
|
|
141 val += + stack_base;
|
|
142 push(val);
|
|
143 }
|
|
144
|
5
|
145 // 配列のアドレスをPush
|
4
|
146 void PushArrayAddr(int val)
|
|
147 {
|
|
148 if ((val & global_flag) == 0) // local
|
|
149 val += + stack_base;
|
|
150 int index = top().i_; pop();
|
|
151 push(val + index);
|
|
152 }
|
|
153
|
5
|
154 // 変数にPop
|
4
|
155 void PopValue(int val)
|
|
156 {
|
|
157 global_value[val] = top(); pop();
|
|
158 }
|
|
159
|
5
|
160 // ローカル変数にPop
|
4
|
161 void PopLocal(int val)
|
|
162 {
|
|
163 stack[val + stack_base] = top(); pop();
|
|
164 }
|
|
165
|
5
|
166 // 配列変数にPop
|
4
|
167 void PopArray(int val)
|
|
168 {
|
|
169 int index = top().i_; pop();
|
|
170 global_value[val + index] = top(); pop();
|
|
171 }
|
|
172
|
5
|
173 // ローカルの配列変数にPop
|
4
|
174 void PopLocalArray(int val)
|
|
175 {
|
|
176 int index = top().i_; pop();
|
|
177 stack[val + stack_base + index] = top(); pop();
|
|
178 }
|
|
179
|
5
|
180 // ローカル変数(参照)にPop
|
4
|
181 void PopLocalRef(int val)
|
|
182 {
|
|
183 int addr = stack[val + stack_base].i_;
|
|
184 set_ref(addr, top()); pop();
|
|
185 }
|
|
186
|
5
|
187 // ローカルの配列変数(参照)にPop
|
4
|
188 void PopLocalArrayRef(int val)
|
|
189 {
|
|
190 int addr = stack[val + stack_base].i_;
|
|
191 int index = top().i_; pop();
|
|
192 set_ref(addr + index, top()); pop();
|
|
193 }
|
|
194
|
5
|
195 // ローカル変数を確保
|
4
|
196 void OpAllocStack(int val)
|
|
197 {
|
|
198 stack.resize(stack_base + val);
|
|
199 }
|
|
200
|
5
|
201 // 空Pop(スタックトップを捨てる)
|
4
|
202 void OpPop()
|
|
203 {
|
|
204 pop();
|
|
205 }
|
|
206
|
5
|
207 // 単項マイナス
|
4
|
208 void OpNeg()
|
|
209 {
|
|
210 top().i_ = -top().i_;
|
|
211 }
|
|
212
|
|
213 // ==
|
|
214 void OpEq()
|
|
215 {
|
|
216 int rhs = top().i_; pop();
|
|
217 int lhs = top().i_; pop();
|
|
218 push(lhs == rhs);
|
|
219 }
|
|
220
|
|
221 // !=
|
|
222 void OpNe()
|
|
223 {
|
|
224 int rhs = top().i_; pop();
|
|
225 int lhs = top().i_; pop();
|
|
226 push(lhs != rhs);
|
|
227 }
|
|
228
|
|
229 // >
|
|
230 void OpGt()
|
|
231 {
|
|
232 int rhs = top().i_; pop();
|
|
233 int lhs = top().i_; pop();
|
|
234 push(lhs > rhs);
|
|
235 }
|
|
236
|
|
237 // >=
|
|
238 void OpGe()
|
|
239 {
|
|
240 int rhs = top().i_; pop();
|
|
241 int lhs = top().i_; pop();
|
|
242 push(lhs >= rhs);
|
|
243 }
|
|
244
|
|
245 // <
|
|
246 void OpLt()
|
|
247 {
|
|
248 int rhs = top().i_; pop();
|
|
249 int lhs = top().i_; pop();
|
|
250 push(lhs < rhs);
|
|
251 }
|
|
252
|
|
253 // <=
|
|
254 void OpLe()
|
|
255 {
|
|
256 int rhs = top().i_; pop();
|
|
257 int lhs = top().i_; pop();
|
|
258 push(lhs <= rhs);
|
|
259 }
|
|
260
|
|
261 // &&
|
|
262 void OpLogAnd()
|
|
263 {
|
|
264 int rhs = top().i_; pop();
|
|
265 int lhs = top().i_; pop();
|
|
266 push(lhs && rhs);
|
|
267 }
|
|
268
|
|
269 // ||
|
|
270 void OpLogOr()
|
|
271 {
|
|
272 int rhs = top().i_; pop();
|
|
273 int lhs = top().i_; pop();
|
|
274 push(lhs || rhs);
|
|
275 }
|
|
276
|
|
277 // &
|
|
278 void OpAnd()
|
|
279 {
|
|
280 int rhs = top().i_; pop();
|
|
281 int lhs = top().i_; pop();
|
|
282 push(lhs & rhs);
|
|
283 }
|
|
284
|
|
285 // |
|
|
286 void OpOr()
|
|
287 {
|
|
288 int rhs = top().i_; pop();
|
|
289 int lhs = top().i_; pop();
|
|
290 push(lhs | rhs);
|
|
291 }
|
|
292
|
|
293 // <<
|
|
294 void OpLeftShift()
|
|
295 {
|
|
296 int rhs = top().i_; pop();
|
|
297 int lhs = top().i_; pop();
|
|
298 push(lhs << rhs);
|
|
299 }
|
|
300
|
|
301 // >>
|
|
302 void OpRightShift()
|
|
303 {
|
|
304 int rhs = top().i_; pop();
|
|
305 int lhs = top().i_; pop();
|
|
306 push(lhs >> rhs);
|
|
307 }
|
|
308
|
|
309 // +
|
|
310 void OpAdd()
|
|
311 {
|
|
312 int rhs = top().i_; pop();
|
|
313 int lhs = top().i_; pop();
|
|
314 push(lhs + rhs);
|
|
315 }
|
|
316
|
|
317 // -
|
|
318 void OpSub()
|
|
319 {
|
|
320 int rhs = top().i_; pop();
|
|
321 int lhs = top().i_; pop();
|
|
322 push(lhs - rhs);
|
|
323 }
|
|
324
|
|
325 // *
|
|
326 void OpMul()
|
|
327 {
|
|
328 int rhs = top().i_; pop();
|
|
329 int lhs = top().i_; pop();
|
|
330 push(lhs * rhs);
|
|
331 }
|
|
332
|
|
333 // /
|
|
334 void OpDiv()
|
|
335 {
|
|
336 int rhs = top().i_; pop();
|
|
337 if (rhs == 0)
|
|
338 throw devide_by_zero();
|
|
339 int lhs = top().i_; pop();
|
|
340 push(lhs / rhs);
|
|
341 }
|
|
342
|
|
343 // %
|
|
344 void OpMod()
|
|
345 {
|
|
346 int rhs = top().i_; pop();
|
|
347 if (rhs == 0)
|
|
348 throw devide_by_zero();
|
|
349 int lhs = top().i_; pop();
|
|
350 push(lhs % rhs);
|
|
351 }
|
|
352
|
5
|
353 // 文字列の==
|
4
|
354 void OpStrEq()
|
|
355 {
|
|
356 const std::string &rhs = text(top()); pop();
|
|
357 const std::string &lhs = text(top()); pop();
|
|
358
|
|
359 push(lhs == rhs);
|
|
360 }
|
|
361
|
5
|
362 // 文字列の!=
|
4
|
363 void OpStrNe()
|
|
364 {
|
|
365 const std::string &rhs = text(top()); pop();
|
|
366 const std::string &lhs = text(top()); pop();
|
|
367
|
|
368 push(lhs != rhs);
|
|
369 }
|
|
370
|
5
|
371 // 文字列の>
|
4
|
372 void OpStrGt()
|
|
373 {
|
|
374 const std::string &rhs = text(top()); pop();
|
|
375 const std::string &lhs = text(top()); pop();
|
|
376
|
|
377 push(lhs > rhs);
|
|
378 }
|
|
379
|
5
|
380 // 文字列の>=
|
4
|
381 void OpStrGe()
|
|
382 {
|
|
383 const std::string &rhs = text(top()); pop();
|
|
384 const std::string &lhs = text(top()); pop();
|
|
385
|
|
386 push(lhs >= rhs);
|
|
387 }
|
|
388
|
5
|
389 // 文字列の<
|
4
|
390 void OpStrLt()
|
|
391 {
|
|
392 const std::string &rhs = text(top()); pop();
|
|
393 const std::string &lhs = text(top()); pop();
|
|
394
|
|
395 push(lhs < rhs);
|
|
396 }
|
|
397
|
5
|
398 // 文字列の<=
|
4
|
399 void OpStrLe()
|
|
400 {
|
|
401 const std::string &rhs = text(top()); pop();
|
|
402 const std::string &lhs = text(top()); pop();
|
|
403
|
|
404 push(lhs <= rhs);
|
|
405 }
|
|
406
|
5
|
407 // 文字列の+
|
4
|
408 void OpStrAdd()
|
|
409 {
|
|
410 const std::string &rhs = text(top()); pop();
|
|
411 const std::string &lhs = text(top()); pop();
|
|
412
|
|
413 push(lhs + rhs);
|
|
414 }
|
|
415
|
5
|
416 // 無条件ジャンプ
|
4
|
417 void OpJmp(int val)
|
|
418 {
|
|
419 jmp(val);
|
|
420 }
|
|
421
|
5
|
422 // 真の時ジャンプ
|
4
|
423 void OpJmpC(int val)
|
|
424 {
|
|
425 int cond = top().i_; pop();
|
|
426 if (cond)
|
|
427 jmp(val);
|
|
428 }
|
|
429
|
5
|
430 // 偽の時ジャンプ
|
4
|
431 void OpJmpNC(int val)
|
|
432 {
|
|
433 int cond = top().i_; pop();
|
|
434 if (!cond)
|
|
435 jmp(val);
|
|
436 }
|
|
437
|
5
|
438 // switch文用特殊判定
|
4
|
439 void OpTest(int val)
|
|
440 {
|
|
441 int value = top().i_; pop();
|
|
442 if (value == top().i_) {
|
|
443 pop();
|
|
444 jmp(val);
|
|
445 }
|
|
446 }
|
|
447
|
5
|
448 // 関数コール
|
4
|
449 void OpCall(int val)
|
|
450 {
|
|
451 push(stack_base);
|
5
|
452 push(addr()); // リターンアドレスをPush
|
|
453 stack_base = stack.size(); // スタックベース更新
|
4
|
454 jmp(val);
|
|
455 }
|
|
456
|
5
|
457 // 引数なしリターン
|
4
|
458 void OpReturn()
|
|
459 {
|
5
|
460 stack.resize(stack_base); // ローカル変数排除
|
4
|
461 int addr = top().i_; pop();
|
|
462 stack_base = top().i_; pop();
|
|
463 int arg_count = top().i_; pop();
|
|
464 stack.pop(arg_count);
|
|
465 jmp(addr);
|
|
466 }
|
|
467
|
5
|
468 // 引数付きリターン
|
4
|
469 void OpReturnV()
|
|
470 {
|
|
471 vm::value result = top(); pop();
|
5
|
472 stack.resize(stack_base); // ローカル変数排除
|
4
|
473 int addr = top().i_; pop();
|
|
474 stack_base = top().i_; pop();
|
|
475 int arg_count = top().i_; pop();
|
|
476 stack.pop(arg_count);
|
|
477 push(result);
|
|
478 jmp(addr);
|
|
479 }
|
|
480
|
5
|
481 // 仮想CPUプログラム停止
|
4
|
482 void OpHalt()
|
|
483 {
|
|
484 }
|
|
485
|
5
|
486 // システムコール(組み込み関数)
|
4
|
487 void OpSysCall(int val)
|
|
488 {
|
|
489 pop(); // arg_count
|
|
490 switch (val) {
|
|
491 case SYS_PRINT:
|
|
492 sys_print();
|
|
493 break;
|
|
494
|
|
495 case SYS_TOSTR:
|
|
496 sys_tostr();
|
|
497 break;
|
|
498 }
|
|
499 }
|
|
500
|
5
|
501 // システムコール(print)
|
4
|
502 void sys_print()
|
|
503 {
|
|
504 std::cout << text(top());
|
|
505 pop();
|
|
506 }
|
|
507
|
5
|
508 // システムコール(数値を文字列に変換)
|
4
|
509 void sys_tostr()
|
|
510 {
|
|
511 int v = top().i_; pop();
|
|
512 char str[16];
|
|
513 sprintf(str, "%d", v);
|
5
|
514 push(std::string(str)); // 戻り値はスタックに入れる
|
4
|
515 }
|
|
516
|
|
517 private:
|
|
518 int value() { int v = *(int *)command_ptr_; command_ptr_ += 4; return v; }
|
|
519 int addr() const { return (int)(command_ptr_ - command_); }
|
|
520 void jmp(int addr) { command_ptr_ = command_ + addr; }
|
|
521 void push(int v) { stack.push(vm::value(v)); }
|
|
522 void push(const std::string &v) { stack.push(vm::value(v)); }
|
|
523 void push(const vm::value &v) { stack.push(v); }
|
|
524 void pop() { stack.pop(); }
|
|
525 const vm::value &top() const { return stack.top(); }
|
|
526 vm::value &top() { return stack.top(); }
|
|
527 std::string text(const vm::value &v) { return v.s_->str_; }
|
|
528 const vm::value &ref_to_value(int addr) const
|
|
529 {
|
|
530 if (addr & global_flag)
|
|
531 return global_value[addr & global_mask];
|
|
532 return stack[addr];
|
|
533 }
|
|
534 void set_ref(int addr, const vm::value &v)
|
|
535 {
|
|
536 if (addr & global_flag)
|
|
537 global_value[addr & global_mask] = v;
|
|
538 else
|
|
539 stack[addr] = v;
|
|
540 }
|
|
541
|
|
542 private:
|
|
543 data &data_;
|
|
544 unsigned char *command_;
|
|
545 unsigned char *command_ptr_;
|
|
546 int command_size_;
|
|
547 char *text_buffer_;
|
|
548 int text_size_;
|
|
549
|
|
550 vm::stack<vm::value, STACK_SIZE> stack;
|
|
551 std::vector<vm::value> global_value;
|
|
552 int stack_base;
|
|
553 } ;
|
|
554
|
|
555 }
|
|
556
|
|
557 #endif
|