diff Bison-Flex/BasicCompiler-StackBase/compiler.cpp @ 1:a3ea4c73696b

move files
author nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
date Tue, 10 May 2011 06:26:08 +0900
parents Bison-Flex/EUC/compiler.cpp@3f4ade70b4d2
children fbe42292d479
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Bison-Flex/BasicCompiler-StackBase/compiler.cpp	Tue May 10 06:26:08 2011 +0900
@@ -0,0 +1,426 @@
+#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.start_;
+			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文
+//
+//	if expr then
+//		A
+//	endif
+//
+//	>	push expr
+//	>	jmp_nc L1
+//	>		A
+//	>	L1:
+//
+//	if expr then
+//		A
+//	else
+//		B
+//	endif
+//
+//	>	push expr
+//	>	jmp_nc L1
+//	>		A
+//	>	jmp L2
+//	>	L1:
+//	>		B
+//	>	L2:
+//
+void compiler::IfStatement(const yy::location& l, CNode *expr)
+{
+	expr->push(this);
+	int label = MakeLabel();
+	OpJmpNC(label);				// 偽の時の飛び先
+
+	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文
+//
+//	for value=X to Y step Z
+//		A
+//	next
+//
+//	>	push X			: value = X
+//	>	pop value
+//	>	L1:
+//	>		A
+//	>	push value		: if (value == Y) goto L2
+//	>	push Y
+//	>	eq
+//	>	jmp_c L2
+//	>	push value		: value = value + Z
+//	>	push Z
+//	>	add
+//	>	pop value
+//	>	jmp L1
+//	>	L2:
+//
+void compiler::ForStatement(const yy::location& l, CAssign *start, CNode *end, CNode *step)
+{
+	int label = MakeLabel();
+
+	start->analyze(this);
+	SetLabel(label);
+
+	state_stack.push(CState(l, STATE_FOR, label, start, 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();
+
+		// ループ終了のチェック
+		state.start_->push_value(this);
+		state.end_->push(this);
+		OpEq();
+		OpJmpC(label);			// 終了時飛び先
+
+		// カウンター増分
+		state.start_->push_value(this);
+		if (state.step_)
+			state.step_->push(this);
+		else
+			PushConst(1);
+
+		OpAdd();
+		state.start_->pop_value(this);
+
+		// ループ
+		OpJmp(state.label1_);
+
+		// ループ終了
+		SetLabel(label);
+
+		// 後始末
+		delete state.start_;
+		delete state.end_;
+		delete state.step_;
+
+		state_stack.pop();
+	}
+}
+
+// while文
+//
+//	while (expr) A
+//	>	L1:
+//	>	push expr
+//	>	jmp_nc L2
+//	>		A
+//	>		jmp L1
+//	>	L2:
+//
+void compiler::WhileStatement(const yy::location& l, CNode *expr)
+{
+	int label1 = MakeLabel();
+	int label2 = MakeLabel();
+
+	SetLabel(label1);
+	expr->push(this);
+	OpJmpNC(label2);
+
+	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
+//
+void compiler::PrintStatement(const yy::location& l, CArgs *args)
+{
+	int arg_count = 0;
+	if (args) {
+		args->for_each_rev(std::bind2nd(std::mem_fun(&CNode::push), 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;
+}
+
+// デバッグダンプ
+#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_;
+		}
+		std::cout << std::endl;
+
+		if (statement[i].op_ != VM_MAXCOMMAND) {
+			pos += statement[i].size_;
+		}
+	}
+	std::cout << "---" << std::endl;
+}
+#endif