diff Bison-Flex/BasicCompiler-MemoryBase/compiler.cpp @ 4:805d39d28230

add Compiler-stackbase
author nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
date Tue, 17 May 2011 08:00:38 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Bison-Flex/BasicCompiler-MemoryBase/compiler.cpp	Tue May 17 08:00:38 2011 +0900
@@ -0,0 +1,507 @@
+#include <iostream>
+#include <iomanip>
+#include "script-parser.hh"
+#include "compiler.h"
+
+#ifdef  _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+// コンストラクタ
+
+compiler::compiler()
+	: error_count(0)
+{
+}
+
+// デストラクタ
+
+compiler::~compiler()
+{
+}
+
+// コンパイル
+
+bool compiler::compile(const std::string &f, vm::data &data)
+{
+	// システムコールの設定
+
+	file = f;
+	scan_begin();								// スキャナー初期化
+	yy::script_parser parser(*this);			// パーサー構築
+	int result = parser.parse();				// 構文解析
+	scan_end();									// スキャナー終了
+
+	if (result != 0)
+		return false;							// パーサーエラー
+
+	// ステートスタックが空ではないならば、if, for, whileが
+	// 閉じていない
+	while (!state_stack.empty()) {
+		CState state = state_stack.top();
+		switch (state.state_) {
+		case STATE_IF:
+			error(state.l_, "ifに対応するendifが有りません");
+			break;
+
+		case STATE_FOR:
+			error(state.l_, "forに対応するnextが有りません");
+			delete state.end_;
+			delete state.step_;
+			break;
+
+		case STATE_WHILE:
+			error(state.l_, "whileに対応するwendが有りません");
+			break;
+		}
+		state_stack.pop();
+	}
+
+	// 番兵用HALTコマンドを追加
+	const CVMCode &code = statement.back();
+	if (code.op_ != VM_HALT)					// haltが無いならば
+		OpHalt();								// haltを追加
+
+	int code_size = LabelSetting();				// ラベルにアドレスを設定
+	CraeteData(data, code_size);				// バイナリ生成
+
+	return error_count == 0;
+}
+
+// エラーメッセージを出力
+
+void compiler::error(const yy::location& l, const std::string& m)
+{
+	std::cerr << l << ": " << m << std::endl;
+	error_count++;
+}
+
+// エラーメッセージを出力
+
+void compiler::error(const std::string& m)
+{
+	std::cerr << m << std::endl;
+	error_count++;
+}
+
+// 命令文の登録
+
+// 代入文
+void compiler::AssignStatement(const yy::location& l, CAssign *assign)
+{
+	assign->analyze(this);
+	delete assign;
+}
+
+// if文
+void compiler::IfStatement(const yy::location& l, CNode *expr)
+{
+	int label = MakeLabel();
+	MakeJmpNC(label, CNodeValue::MakeNodeValue(this, expr));
+
+	state_stack.push(CState(l, STATE_IF, label));
+
+	delete expr;
+}
+
+void compiler::ElseStatement(const yy::location& l)
+{
+	if (state_stack.empty() || state_stack.top().state_ != STATE_IF) {
+		error(l, "if文と対応していないelse文が有りました。");
+	}
+	else {
+		CState &state = state_stack.top();
+		int label = MakeLabel();
+		OpJmp(label);
+		SetLabel(state.label1_);	// 偽の時の飛び先をここにする
+		state.label1_ = label;		// endifの飛び先を再設定
+	}
+}
+
+void compiler::EndifStatement(const yy::location& l)
+{
+	if (state_stack.empty() || state_stack.top().state_ != STATE_IF) {
+		error(l, "if文と対応していないendif文が有りました。");
+	}
+	else {
+		CState &state = state_stack.top();
+		SetLabel(state.label1_);	// endifの飛び先をここにする
+		state_stack.pop();			// ステートスタックをpop
+	}
+}
+
+// FOR文
+void compiler::ForStatement(const yy::location& l, CAssign *start, CNode *end, CNode *step)
+{
+	int label = MakeLabel();
+
+	CNodeValue counter = start->analyze(this);
+	SetLabel(label);
+
+	state_stack.push(CState(l, STATE_FOR, label, counter, end, step));
+}
+
+void compiler::NextStatement(const yy::location& l)
+{
+	if (state_stack.empty() || state_stack.top().state_ != STATE_FOR) {
+		error(l, "for文と対応していないnext文が有りました。");
+	}
+	else {
+		CState &state = state_stack.top();
+		int label = MakeLabel();
+		MakeJmpC(label, MakeOp(OP_EQ, -1, state.counter_, CNodeValue::MakeNodeValue(this, state.end_)));
+		{
+			CNodeValue step(CNodeValue::CONST, 1);
+			if (state.step_)
+				step = CNodeValue::MakeNodeValue(this, state.step_);
+			MakeOp(OP_PLUS, state.counter_.value(), state.counter_, step);
+		}
+		OpJmp(state.label1_);
+		SetLabel(label);
+
+		// 後始末
+		delete state.end_;
+		delete state.step_;
+
+		state_stack.pop();
+	}
+}
+
+// while文
+void compiler::WhileStatement(const yy::location& l, CNode *expr)
+{
+	int label1 = MakeLabel();
+	int label2 = MakeLabel();
+
+	SetLabel(label1);
+	MakeJmpNC(label2, CNodeValue::MakeNodeValue(this, expr));
+
+	state_stack.push(CState(l, STATE_WHILE, label1, label2));
+
+	delete expr;
+}
+
+void compiler::WendStatement(const yy::location& l)
+{
+	if (state_stack.empty() || state_stack.top().state_ != STATE_WHILE) {
+		error(l, "while文と対応していないwend文が有りました。");
+	}
+	else {
+		CState &state = state_stack.top();
+		OpJmp(state.label1_);
+		SetLabel(state.label2_);
+		state_stack.pop();
+	}
+}
+
+// end文
+//
+//	>	halt
+//
+void compiler::EndStatement(const yy::location& l)
+{
+	OpHalt();
+}
+
+// print文
+//
+//	print a, b, c
+//
+//	>	push c
+//	>	push b
+//	>	push a
+//	>	print 3
+//
+
+struct print_action {
+	compiler *comp_;
+	print_action(compiler *comp): comp_(comp)
+	{
+	}
+
+	void operator()(CNode *node) const
+	{
+		CNodeValue value = CNodeValue::MakeNodeValue(comp_, node);
+		comp_->MakePush(value);
+	}
+} ;
+
+void compiler::PrintStatement(const yy::location& l, CArgs *args)
+{
+	int arg_count = 0;
+	if (args) {
+		args->for_each_rev(print_action(this));
+		arg_count = args->size();
+	}
+
+	OpPrint(arg_count);
+
+	delete args;
+}
+
+// ラベル生成
+
+int compiler::MakeLabel()
+{
+	int index = (int)labels.size();
+	labels.push_back(CLabel(index));
+	return index;
+}
+
+// ラベルのダミーコマンドをステートメントリストに登録する
+
+void compiler::SetLabel(int label)
+{
+	statement.push_back(CVMCode(VM_MAXCOMMAND, label));
+}
+
+// ラベル解決
+//
+// 1.アドレスを生成する
+// 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する
+// 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする
+
+// note:
+//	GCCでは、関数オブジェクトを関数内に書けないので、ここに記述する。
+//	VC++9.0(VS2008)では関数内に書くことで、スコープを封じ込める事が可能。
+
+// アドレス計算関数オブジェクト
+struct calc_addr {
+	std::vector<CLabel> &labels_;
+	int &pos_;
+	calc_addr(std::vector<CLabel> &labels, int &pos): labels_(labels), pos_(pos)
+	{
+	}
+	void operator()(const CVMCode &code)
+	{
+		if (code.op_ == VM_MAXCOMMAND) {			// ラベルのダミーコマンド
+			labels_[code.arg1_].pos_ = pos_;
+		}
+		else {
+			pos_ += code.size_;
+		}
+	}
+} ;
+
+// ジャンプアドレス設定関数オブジェクト
+struct set_addr {
+	std::vector<CLabel> &labels_;
+	set_addr(std::vector<CLabel> &labels): labels_(labels)
+	{
+	}
+	void operator()(CVMCode &code)
+	{
+		switch (code.op_) {
+		  case VM_JMP:
+		  case VM_JMPC:
+		  case VM_JMPNC:
+			code.arg1_ = labels_[code.arg1_].pos_;
+			break;
+		}
+	}
+} ;
+
+int compiler::LabelSetting()
+{
+	// アドレス計算
+	int pos = 0;
+	std::for_each(statement.begin(), statement.end(), calc_addr(labels, pos));
+
+	// ジャンプアドレス設定
+	std::for_each(statement.begin(), statement.end(), set_addr(labels));
+
+	return pos;
+}
+
+// バイナリデータ生成
+
+// 関数オブジェクト
+struct copy_code {
+	unsigned char *p;
+	copy_code(unsigned char *code): p(code)
+	{
+	}
+	void operator()(const CVMCode &code)
+	{
+		p = code.Get(p);
+	}
+} ;
+
+bool compiler::CraeteData(vm::data &data, int code_size)
+{
+	data.command_ = new unsigned char[code_size];
+	data.command_size_ = code_size;
+	data.value_size_ = (int)variables.size();
+
+	std::for_each(statement.begin(), statement.end(), copy_code(data.command_));
+
+	return true;
+}
+
+// 使用してよい一時変数を返す
+int compiler::AllocTempValue()
+{
+	// テーブルから空きを探してみる
+	size_t size = temp_value.size();
+
+	for (size_t i=0; i<size; i++) {
+		if (temp_value[i].ref_ == 0) {
+			temp_value[i].ref_ = 1;
+			return (int)i;
+		}
+	}
+
+	// 空きがなければ追加
+	char str[24];
+	sprintf(str, "#%d", size);
+	const CValueTag *tag = AddValue(str);
+	temp_value.push_back(CTempValue(1, tag->addr_));
+
+	return (int)size;
+}
+
+// 一時変数使用
+void compiler::UseTempValue(int value)
+{
+	temp_value[value].ref_++;
+}
+
+// 一時変数返却
+void compiler::ReleaseTempValue(int value)
+{
+	temp_value[value].ref_--;
+}
+
+// 単項マイナスの生成
+CNodeValue compiler::MakeNeg(int ret, const CNodeValue &value)
+{
+	CNodeValue v = CNodeValue::MakeTempValue(this, ret);
+
+	if (value.type() == CNodeValue::CONST)
+		OpNegC(v.value(), value.value());
+	else
+		OpNegV(v.value(), value.value());
+
+	return v;
+}
+
+// RAND関数の生成
+CNodeValue compiler::MakeRand(int ret, const CNodeValue &value)
+{
+	CNodeValue v = CNodeValue::MakeTempValue(this, ret);
+
+	if (value.type() == CNodeValue::CONST)
+		OpRandC(v.value(), value.value());
+	else
+		OpRandV(v.value(), value.value());
+
+	return v;
+}
+
+// 代入の生成(定数)
+CNodeValue compiler::MakeMoveC(int ret, int value)
+{
+	CNodeValue v = CNodeValue::MakeTempValue(this, ret);
+
+	OpMovC(v.value(), value);
+
+	return v;
+}
+
+// 代入の生成(変数)
+CNodeValue compiler::MakeMoveV(int ret, const CNodeValue &value)
+{
+	CNodeValue v = CNodeValue::MakeTempValue(this, ret);
+
+	OpMovV(v.value(), value.value());
+
+	return v;
+}
+
+// 二項演算子の生成
+CNodeValue compiler::MakeOp(int op, int ret, const CNodeValue &left, const CNodeValue &right)
+{
+	CNodeValue v = CNodeValue::MakeTempValue(this, ret);
+
+	int code = 0;
+	switch (op) {
+	  case OP_EQ:		code = VM_EQ_CC;	break;
+	  case OP_NE:		code = VM_NE_CC;	break;
+	  case OP_GT:		code = VM_GT_CC;	break;
+	  case OP_GE:		code = VM_GE_CC;	break;
+	  case OP_LT:		code = VM_LT_CC;	break;
+	  case OP_LE:		code = VM_LE_CC;	break;
+	  case OP_MINUS:	code = VM_SUB_CC;	break;
+	  case OP_PLUS:		code = VM_ADD_CC;	break;
+	  case OP_TIMES:	code = VM_MUL_CC;	break;
+	  case OP_DIVIDE:	code = VM_DIV_CC;	break;
+	  case OP_MOD:		code = VM_MOD_CC;	break;
+	}
+
+	if (left.type() != CNodeValue::CONST)
+		code++;
+	if (right.type() != CNodeValue::CONST)
+		code += 2;
+
+	statement.push_back(CVMCode(code, v.value(), left.value(), right.value()));
+	return v;
+}
+
+// 条件ジャンプの生成(真)
+void compiler::MakeJmpC(int label, const CNodeValue &value)
+{
+	OpJmpC(label, value.value());
+}
+
+// 条件ジャンプの生成(偽)
+void compiler::MakeJmpNC(int label, const CNodeValue &value)
+{
+	OpJmpNC(label, value.value());
+}
+
+// pushの生成
+void compiler::MakePush(const CNodeValue &value)
+{
+	if (value.type() == CNodeValue::CONST)
+		PushConst(value.value());
+	else
+		PushValue(value.value());
+}
+
+// デバッグダンプ
+#ifdef	_DEBUG
+void compiler::debug_dump()
+{
+	std::cout << "---variables---" << std::endl;
+	variables.dump();
+
+	static const char *op_name[] = {
+#define	VM_NAMETABLE
+#include "vm_code.h"
+#undef	VM_NAMETABLE
+		"LABEL",
+	} ;
+	std::cout << "---code---" << std::endl;
+
+	int	pos = 0;
+	size_t size = statement.size();
+	for (size_t i=0; i < size; i++) {
+		std::cout << std::setw(6) << pos << ": " << op_name[statement[i].op_];
+		if (statement[i].size_ > 1) {
+			std::cout << ", " << statement[i].arg1_;
+			if (statement[i].size_ > 5) {
+				std::cout << ", " << statement[i].arg2_;
+				if (statement[i].size_ > 9) {
+					std::cout << ", " << statement[i].arg3_;
+				}
+			}
+		}
+		std::cout << std::endl;
+
+		if (statement[i].op_ != VM_MAXCOMMAND) {
+			pos += statement[i].size_;
+		}
+	}
+	std::cout << "---" << std::endl;
+}
+#endif