Mercurial > hg > Members > nobuyasu > SampleSource
diff WindowsOnly/WinScript2/vm.h @ 0:db40c85cad7a default tip
upload sample source
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 May 2011 03:11:59 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WindowsOnly/WinScript2/vm.h Mon May 09 03:11:59 2011 +0900 @@ -0,0 +1,658 @@ +#ifndef __VM_H__ +#define __VM_H__ + +#include <vector> +#include "vm_value.h" + +#ifdef _MSC_VER +// +// VS2008では、セキュアライブラリ関数(*_s)を使うよう警告が出ます。 +// ここでは、一般化(gcc等の対応)のため、旧ライブラリを使用しているので、 +// 警告を抑止しています。 +// +#pragma warning(disable: 4996) +#endif + +#define VM_ENUMDEF +enum { +#include "vm_code.h" + VM_MAXCOMMAND, +} ; +#undef VM_ENUMDEF + +int VmMessageBox(const char *title, const char *message); +void VmMoveTo(int dc, int x, int y); +void VmLineTo(int dc, int x, int y); +void VmSetColor(int dc, int r, int g, int b); +int VmGetDC(); +void VmReleaseDC(int hdc); + +namespace vm { + + enum { + SYS_TOSTR, + SYS_MESSAGE_BOX, + SYS_MOVE_TO, + SYS_LINE_TO, + SYS_SET_COLOR, + SYS_GET_DC, + SYS_RELEASE_DC, + } ; + + class data { + public: + enum { + ON_CREATE, // WM_CREATE + ON_DESTROY, // WM_DESTROY + ON_PAINT, // WM_PAINT + ON_LBUTTONDOWN, // WM_LBUTTONDOWN + ON_LBUTTONUP, // WM_LBUTTONUP + ON_MOUSEMOVE, // WM_MOUSEMOVE + MAX_ENTRY_POINT // エントリーポイントの数 + } ; + + public: + data(): command_(0), text_buffer_(0) + { + } + ~data() + { + delete[] command_; + delete[] text_buffer_; + } + + public: + unsigned char *command_; // コマンドテーブル + char *text_buffer_; // テキストデータ + int command_size_; // コマンドサイズ + int text_size_; // テキストサイズ + int value_size_; // グローバル変数サイズ + int entry_point_[MAX_ENTRY_POINT]; // 開始位置 + } ; + + + // 0除算例外 + class devide_by_zero: public std::exception { + public: + const char *what() const throw() + { + return "devide by zero"; + } + } ; + + // 仮想マシン + class vcpu { + public: + const static int STACK_SIZE = 1000; + const static int global_flag = 0x4000000; + const static int global_mask = 0x3ffffff; + + public: + vcpu() + { + } + ~vcpu() + { + } + +// int run(); + int call(data &program, int entry) + { + return internal_call(program, entry, 0, 0); + } + + int call(data &program, int entry, int arg1) + { + int arg[] = { arg1 }; + return internal_call(program, entry, arg, 1); + } + + int call(data &program, int entry, int arg1, int arg2) + { + int arg[] = { arg1, arg2 }; + return internal_call(program, entry, arg, 2); + } + + int call(data &program, int entry, int arg1, int arg2, int arg3) + { + int arg[] = { arg1, arg2, arg3 }; + return internal_call(program, entry, arg, 3); + } + + private: + int internal_call(data &program, int entry, int *arg, int narg); + + private: + // 定数Push + void PushConst(int val) + { + push(val); + } + + // 文字定数Push + void PushString(int val) + { + push(std::string(text_buffer_ + val)); + } + + // 変数Push + void PushValue(int val) + { + push(global_value[val]); + } + + // ローカル変数Push + void PushLocal(int val) + { + push(stack[val + stack_base]); + } + + // 配列からPush + void PushArray(int val) + { + int index = top().i_; pop(); + push(global_value[val + index]); + } + + // ローカルの配列からPush + void PushLocalArray(int val) + { + int index = top().i_; pop(); + push(stack[val + stack_base + index]); + } + + // ローカル変数(参照)Push + void PushLocalRef(int val) + { + int addr = stack[val + stack_base].i_; + push(ref_to_value(addr)); + } + + // ローカルの配列(参照)からPush + void PushLocalArrayRef(int val) + { + int addr = stack[val + stack_base].i_; + int index = top().i_; pop(); + push(ref_to_value(addr + index)); + } + + // アドレスをPush + void PushAddr(int val) + { + if ((val & global_flag) == 0) // local + val += + stack_base; + push(val); + } + + // 配列のアドレスをPush + void PushArrayAddr(int val) + { + if ((val & global_flag) == 0) // local + val += + stack_base; + int index = top().i_; pop(); + push(val + index); + } + + // 変数にPop + void PopValue(int val) + { + global_value[val] = top(); pop(); + } + + // ローカル変数にPop + void PopLocal(int val) + { + stack[val + stack_base] = top(); pop(); + } + + // 配列変数にPop + void PopArray(int val) + { + int index = top().i_; pop(); + global_value[val + index] = top(); pop(); + } + + // ローカルの配列変数にPop + void PopLocalArray(int val) + { + int index = top().i_; pop(); + stack[val + stack_base + index] = top(); pop(); + } + + // ローカル変数(参照)にPop + void PopLocalRef(int val) + { + int addr = stack[val + stack_base].i_; + set_ref(addr, top()); pop(); + } + + // ローカルの配列変数(参照)にPop + void PopLocalArrayRef(int val) + { + int addr = stack[val + stack_base].i_; + int index = top().i_; pop(); + set_ref(addr + index, top()); pop(); + } + + // ローカル変数を確保 + void OpAllocStack(int val) + { + stack.resize(stack_base + val); + } + + // 空Pop(スタックトップを捨てる) + void OpPop() + { + pop(); + } + + // 単項マイナス + void OpNeg() + { + top().i_ = -top().i_; + } + + // == + void OpEq() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs == rhs); + } + + // != + void OpNe() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs != rhs); + } + + // > + void OpGt() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs > rhs); + } + + // >= + void OpGe() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs >= rhs); + } + + // < + void OpLt() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs < rhs); + } + + // <= + void OpLe() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs <= rhs); + } + + // && + void OpLogAnd() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs && rhs); + } + + // || + void OpLogOr() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs || rhs); + } + + // & + void OpAnd() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs & rhs); + } + + // | + void OpOr() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs | rhs); + } + + // << + void OpLeftShift() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs << rhs); + } + + // >> + void OpRightShift() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs >> rhs); + } + + // + + void OpAdd() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs + rhs); + } + + // - + void OpSub() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs - rhs); + } + + // * + void OpMul() + { + int rhs = top().i_; pop(); + int lhs = top().i_; pop(); + push(lhs * rhs); + } + + // / + void OpDiv() + { + int rhs = top().i_; pop(); + if (rhs == 0) + throw devide_by_zero(); + int lhs = top().i_; pop(); + push(lhs / rhs); + } + + // % + void OpMod() + { + int rhs = top().i_; pop(); + if (rhs == 0) + throw devide_by_zero(); + int lhs = top().i_; pop(); + push(lhs % rhs); + } + + // 文字列の== + void OpStrEq() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs == rhs); + } + + // 文字列の!= + void OpStrNe() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs != rhs); + } + + // 文字列の> + void OpStrGt() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs > rhs); + } + + // 文字列の>= + void OpStrGe() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs >= rhs); + } + + // 文字列の< + void OpStrLt() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs < rhs); + } + + // 文字列の<= + void OpStrLe() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs <= rhs); + } + + // 文字列の+ + void OpStrAdd() + { + const std::string &rhs = text(top()); pop(); + const std::string &lhs = text(top()); pop(); + + push(lhs + rhs); + } + + // 無条件ジャンプ + void OpJmp(int val) + { + jmp(val); + } + + // 真の時ジャンプ + void OpJmpC(int val) + { + int cond = top().i_; pop(); + if (cond) + jmp(val); + } + + // 偽の時ジャンプ + void OpJmpNC(int val) + { + int cond = top().i_; pop(); + if (!cond) + jmp(val); + } + + // switch文用特殊判定 + void OpTest(int val) + { + int value = top().i_; pop(); + if (value == top().i_) { + pop(); + jmp(val); + } + } + + // 関数コール + void OpCall(int val) + { + push(stack_base); + push(addr()); // リターンアドレスをPush + stack_base = stack.size(); // スタックベース更新 + jmp(val); + } + + // 引数なしリターン + void OpReturn() + { + stack.resize(stack_base); // ローカル変数排除 + int addr = top().i_; pop(); + stack_base = top().i_; pop(); + int arg_count = top().i_; pop(); + stack.pop(arg_count); + jmp(addr); + } + + // 引数付きリターン + void OpReturnV() + { + vm::value result = top(); pop(); + stack.resize(stack_base); // ローカル変数排除 + int addr = top().i_; pop(); + stack_base = top().i_; pop(); + int arg_count = top().i_; pop(); + stack.pop(arg_count); + push(result); + jmp(addr); + } + + // 仮想CPUプログラム停止 + void OpHalt() + { + } + + // システムコール(組み込み関数) + void OpSysCall(int val) + { + pop(); // arg_count + switch (val) { + case SYS_TOSTR: + sys_tostr(); + break; + case SYS_MESSAGE_BOX: + sys_message_box(); + break; + case SYS_MOVE_TO: + sys_move_to(); + break; + case SYS_LINE_TO: + sys_line_to(); + break; + case SYS_SET_COLOR: + sys_set_color(); + break; + case SYS_GET_DC: + sys_get_dc(); + break; + case SYS_RELEASE_DC: + sys_release_dc(); + break; + } + } + + // システムコール(MessageBox) + void sys_message_box() + { + const std::string message = text(top()); pop(); + const std::string title = text(top()); pop(); + + push(VmMessageBox(title.c_str(), message.c_str())); + } + + // システムコール(MoveTo) + void sys_move_to() + { + int y = top().i_; pop(); + int x = top().i_; pop(); + int dc = top().i_; pop(); + + VmMoveTo(dc, x, y); + } + + // システムコール(LineTo) + void sys_line_to() + { + int y = top().i_; pop(); + int x = top().i_; pop(); + int dc = top().i_; pop(); + + VmLineTo(dc, x, y); + } + + // システムコール(SetColor) + void sys_set_color() + { + int b = top().i_; pop(); + int g = top().i_; pop(); + int r = top().i_; pop(); + int dc = top().i_; pop(); + + VmSetColor(dc, r, g, b); + } + + // システムコール(GetDC) + void sys_get_dc() + { + push(VmGetDC()); + } + + // システムコール(ReleaseDC) + void sys_release_dc() + { + int dc = top().i_; pop(); + VmReleaseDC(dc); + } + + // システムコール(数値を文字列に変換) + void sys_tostr() + { + int v = top().i_; pop(); + char str[16]; + sprintf(str, "%d", v); + push(std::string(str)); // 戻り値はスタックに入れる + } + + private: + int value() { int v = *(int *)command_ptr_; command_ptr_ += 4; return v; } + int addr() const { return (int)(command_ptr_ - command_); } + void jmp(int addr) { command_ptr_ = command_ + addr; } + void push(int v) { stack.push(vm::value(v)); } + void push(const std::string &v) { stack.push(vm::value(v)); } + void push(const vm::value &v) { stack.push(v); } + void pop() { stack.pop(); } + const vm::value &top() const { return stack.top(); } + vm::value &top() { return stack.top(); } + std::string text(const vm::value &v) { return v.s_->str_; } + const vm::value &ref_to_value(int addr) const + { + if (addr & global_flag) + return global_value[addr & global_mask]; + return stack[addr]; + } + void set_ref(int addr, const vm::value &v) + { + if (addr & global_flag) + global_value[addr & global_mask] = v; + else + stack[addr] = v; + } + + private: + unsigned char *command_; + unsigned char *command_ptr_; + int command_size_; + char *text_buffer_; + int text_size_; + + vm::stack<vm::value, STACK_SIZE> stack; + std::vector<vm::value> global_value; + int stack_base; + } ; + +} + +#endif