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