view Bison-Flex/Compiler-StackBase/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 source

//
// 仮想CPU
//
//		(c)2008 Chihiro.SAKAMOTO HyperWorks
//
#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

namespace vm {

	enum {
		SYS_PRINT,
		SYS_TOSTR,
	} ;

	class data {
	  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_;			// 開始位置
	} ;


	// 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(data &mem)
			: data_(mem)
		{
		}
		~vcpu()
		{
		}

		int run();

	  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_PRINT:
				sys_print();
				break;

			  case SYS_TOSTR:
				sys_tostr();
				break;
			}
		}

		// システムコール(print)
		void sys_print()
		{
			std::cout << text(top());
			pop();
		}

		// システムコール(数値を文字列に変換)
		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:
		data &data_;
		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