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