view Bison-Flex/BasicCompiler-StackBase/EUC/vm.cpp @ 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
//
#include <exception>
#include "vm.h"

namespace vm {

	// 0除算例外
	class devide_by_zero: public std::exception {
	  public:
		const char *what() const throw()
		{
			return "devide by zero";
		}
	} ;

	void (vcpu::*vcpu::cmd_[])() = {
		#define	VM_EXECTABLE
		#include "vm_code.h"
		#undef	VM_EXECTABLE
	} ;

	// 実行
	int vcpu::run()
	{
		command_ = data_.command_;						// プログラム格納位置
		command_size_ = data_.command_size_;			// プログラムの大きさ

		global_value.resize(data_.value_size_);			// 外部変数テーブル確保
		command_ptr_ = command_;						// プログラムカウンター初期化

		active = true;									// Haltしていない

		try {
			while (active) {							// Haltするまでループ
				int op = *command_ptr_++;
				(this->*cmd_[op])();
			}
		}
		catch (const std::exception &e) {
			std::cerr << "例外発生(" << e.what() << ")" << std::endl;
			return -1;
		}
		return 0;
	}

	// 定数Push
	void vcpu::PushConst()
	{
		push(value());
	}

	// 変数Push
	void vcpu::PushValue()
	{
		push(global_value[value()]);
	}

	// 変数にPop
	void vcpu::PopValue()
	{
		global_value[value()] = top(); pop();
	}

	// 空Pop(スタックトップを捨てる)
	void vcpu::OpPop()
	{
		pop();
	}

	// 単項マイナス
	void vcpu::OpNeg()
	{
		top() = -top();
	}

	// ==
	void vcpu::OpEq()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs == rhs);
	}

	// !=
	void vcpu::OpNe()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs != rhs);
	}

	// >
	void vcpu::OpGt()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs > rhs);
	}

	// >=
	void vcpu::OpGe()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs >= rhs);
	}

	// <
	void vcpu::OpLt()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs < rhs);
	}

	// <=
	void vcpu::OpLe()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs <= rhs);
	}

	// +
	void vcpu::OpAdd()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs + rhs);
	}

	// -
	void vcpu::OpSub()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs - rhs);
	}

	// *
	void vcpu::OpMul()
	{
		int rhs = top(); pop();
		int lhs = top(); pop();
		push(lhs * rhs);
	}

	// /
	void vcpu::OpDiv()
	{
		int rhs = top(); pop();
		if (rhs == 0)
			throw devide_by_zero();
		int lhs = top(); pop();
		push(lhs / rhs);
	}

	// %
	void vcpu::OpMod()
	{
		int rhs = top(); pop();
		if (rhs == 0)
			throw devide_by_zero();
		int lhs = top(); pop();
		push(lhs % rhs);
	}

	// 無条件ジャンプ
	void vcpu::OpJmp()
	{
		jmp(value());
	}

	// 真の時ジャンプ
	void vcpu::OpJmpC()
	{
		int addr = value();
		int cond = top(); pop();
		if (cond)
			jmp(addr);
	}

	// 偽の時ジャンプ
	void vcpu::OpJmpNC()
	{
		int addr = value();
		int cond = top(); pop();
		if (!cond)
			jmp(addr);
	}

	// 仮想CPUプログラム停止
	void vcpu::OpHalt()
	{
		active = false;
	}

	void vcpu::OpRand()
	{
		int range = top(); pop();
		int value = (range <= 0)? 0: (rand() % range);
		push(value);
	}

	void vcpu::OpPrint()
	{
		int count = value();
		while (count--) {
			std::cout << top();
			pop();
			if (count)
				std::cout << ", ";
		}
		std::cout << std::endl;
	}
}