diff boost-spirit/Compiler-boost-spirit/EUC/compiler.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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost-spirit/Compiler-boost-spirit/EUC/compiler.cpp	Mon May 09 03:11:59 2011 +0900
@@ -0,0 +1,413 @@
+#include "stdafx.h"
+#include <iostream>
+#include <iomanip>
+#include <memory>
+#include "compiler.h"
+#include "parser.h"
+
+// コンストラクタ
+
+compiler::compiler()
+	: break_index(-1), error_count(0)
+{
+}
+
+// デストラクタ
+
+compiler::~compiler()
+{
+}
+
+// コンパイル
+
+bool compiler::compile(const std::string &file, vm::data &data)
+{
+	// システムコールの設定
+	add_function(vm::SYS_PRINT, TYPE_VOID, "print", "s");
+	add_function(vm::SYS_TOSTR, TYPE_STRING, "str", "i");
+
+	// グローバル変数用、変数テーブルをセット
+	variables.push_back(CValueTable());
+	variables[0].set_global();
+
+	// 先頭はHALT命令にしておく
+	OpHalt();
+
+	bool result = script_parser(file, this);	// 構文解析
+
+	if (!result)
+		return false;							// パーサーエラー
+
+	int code_size = LabelSetting();				// ラベルにアドレスを設定
+	CraeteData(data, code_size);				// バイナリ生成
+	return error_count == 0;
+}
+
+// エラーメッセージを出力
+
+void compiler::error(const std::string& m)
+{
+	std::cerr << m << std::endl;
+	error_count++;
+}
+
+// 内部関数の定義
+
+bool compiler::add_function(int index, int type, const char *name, const char *args)
+{
+	CFunctionTag func(type);
+	if (!func.SetArgs(args))		// 引数を設定
+		return false;
+
+	func.SetDeclaration();			// 宣言済み
+	func.SetSystem();				// Systemフラグセット
+	func.SetIndex(index);			// システムコール番号を設定
+	if (functions.add(name, func) == 0) {
+		return false;
+	}
+	return true;
+}
+
+// 外部変数の定義
+
+struct define_value {
+	compiler *comp_;
+	int type_;
+	define_value(compiler *comp, int type): comp_(comp), type_(type)
+	{
+	}
+
+	void operator()(cnode_t node) const
+	{
+		comp_->AddValue(type_, node->string(), node->left());
+	}
+} ;
+
+void compiler::DefineValue(int type, const std::vector<cnode_t> &node)
+{
+	std::for_each(node.begin(), node.end(), define_value(this, type));
+}
+
+// 関数宣言
+
+void compiler::DefineFunction(int type, const std::string &name, const std::vector<int> &args)
+{
+	const CFunctionTag *tag = functions.find(name);
+	if (tag) {			// 既に宣言済み
+		if (!tag->ChkArgList(args)) {
+			error("関数 " + name + " に異なる型の引数が指定されています");
+			return;
+		}
+	}
+	else {
+		CFunctionTag func(type);
+		func.SetArgs(args);				// 引数を設定
+		func.SetDeclaration();			// 宣言済み
+		func.SetIndex(MakeLabel());		// ラベル登録
+		if (functions.add(name, func) == 0) {
+			error("内部エラー:関数テーブルに登録できません");
+		}
+	}
+}
+
+// 関数定義
+//
+//	関数が呼ばれた時点のスタック
+//
+//	+--------------+
+//	|     arg2     | -5
+//	+--------------+
+//	|     arg1     | -4
+//	+--------------+
+//	|  arg count   | -3
+//	+--------------+
+//	| base_pointer | -2
+//	+--------------+
+//	| return addr  | -1
+//	+--------------+
+//
+//	したがって、引数の開始アドレスは-4となり、デクリメントしていく。
+
+// 引数の変数名を登録
+struct add_value {
+	compiler *comp_;
+	CValueTable &values_;
+	mutable int addr_;
+	add_value(compiler *comp, CValueTable &values): comp_(comp), values_(values), addr_(-4)
+	{
+	}
+
+	void operator()(const cargdef &arg) const
+	{
+		if (!values_.add_arg(arg.type(), arg.name(), addr_)) {
+			comp_->error("引数 " + arg.name() + " は既に登録されています。");
+		}
+		addr_--;
+	}
+} ;
+
+void compiler::AddFunction(int type, const std::string &name, const std::vector<cargdef> &args, cblock_t block)
+{
+	CFunctionTag *tag = functions.find(name);
+	if (tag) {
+		if (tag->IsDefinition()) {
+			error("関数 " + name + " は既に定義されています");
+			return;
+		}
+		if (tag->IsDeclaration() && !tag->ChkArgList(args)) {
+			error("関数 " + name + " に異なる型の引数が指定されています");
+			return;
+		}
+		tag->SetDefinition();	// 定義済みに設定
+	}
+	else {
+		CFunctionTag func(type);
+		func.SetArgs(args);				// 引数を設定
+		func.SetDefinition();			// 定義済み
+		func.SetIndex(MakeLabel());		// ラベル登録
+		tag = functions.add(name, func);
+		if (tag == 0)
+			error("内部エラー:関数テーブルに登録できません");
+	}
+
+	current_function_name = name;		// 処理中の関数名を登録しておく
+	current_function_type = type;		// 処理中の関数型を登録しておく
+										// 関数内関数(入れ子構造)は無いので、
+										// グローバル変数1つでよい
+
+	// 関数のエントリーポイントにラベルを置く
+
+	SetLabel(tag->GetIndex());
+
+	BlockIn();		// 変数スタックを増やす
+
+	// 引数リストを登録
+	std::for_each(args.rbegin(), args.rend(), add_value(this, variables.back()));
+
+	// 文があれば、文を登録
+	if (block) {
+		block->analyze(this);
+	}
+
+	const CVMCode &code = statement.back();
+	if (type == TYPE_VOID) {			// 戻り値無し
+		if (code.op_ != VM_RETURN)		// returnが無いならば
+			OpReturn();					// returnを追加
+	}
+	else {
+		if (code.op_ != VM_RETURNV) {	// returnが無いならば
+			error("関数 " + name + " の最後にreturn文が有りません。");
+		}
+	}
+
+	BlockOut();		// 変数スタックを減らす
+
+	current_function_name.clear();		// 処理中の関数名を消去
+}
+
+// 変数の登録
+
+void compiler::AddValue(int type, const std::string &name, cnode_t node)
+{
+	int size = 1;
+	if (node) {
+		if (node->op() != OP_NUMBER) {
+			error("配列のサイズは定数で指定してください。");
+		}
+		else if (node->number() <= 0) {
+			error("配列のサイズは1以上の定数が必要です。");
+		}
+		size = node->number();
+	}
+
+	CValueTable &values = variables.back();
+	if (!values.add(type, name, size)) {
+		error("変数 " + name + " は既に登録されています。");
+	}
+}
+
+// ラベル生成
+
+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));
+}
+
+// 文字列定数をpush
+
+void compiler::PushString(const std::string &str)
+{
+	PushString((int)text_table.size());
+	text_table.insert(text_table.end(), str.begin(), str.end());
+	text_table.push_back('\0');
+}
+
+// break文に対応したJmpコマンド生成
+
+bool compiler::JmpBreakLabel()
+{
+	if (break_index < 0)
+		return false;
+	OpJmp(break_index);
+	return true;
+}
+
+// ブロック内では、新しい変数セットに変数を登録する
+
+void compiler::BlockIn()
+{
+	int start_addr = 0;					// 変数アドレスの開始位置
+	if (variables.size() > 1) {			// ブロックの入れ子は、開始アドレスを続きからにする。
+		start_addr = variables.back().size();
+	}
+	variables.push_back(CValueTable(start_addr));
+}
+
+// ブロックの終了で、変数スコープが消える(変数セットを削除する)
+
+void compiler::BlockOut()
+{
+	variables.pop_back();
+}
+
+// ローカル変数用にスタックを確保
+
+void compiler::AllocStack()
+{
+	OpAllocStack(variables.back().size());
+}
+
+// ラベル解決
+//
+// 1.アドレスを生成する
+// 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する
+// 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする
+
+// アドレス計算
+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:
+		  case VM_TEST:
+		  case VM_CALL:
+			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)
+{
+	const CFunctionTag *tag = GetFunctionTag("main");	// 開始位置
+	if (tag == 0) {
+		error("関数 \"main\" が見つかりません。");
+		return false;
+	}
+
+	data.command_ = new unsigned char[code_size];
+	data.text_buffer_ = new char[text_table.size()];
+	data.command_size_ = code_size;
+	data.text_size_ = (int)text_table.size();
+	data.value_size_ = (int)variables[0].size();
+	data.entry_point_ = labels[tag->index_].pos_;
+
+	if (data.text_size_ != 0)
+		memcpy(data.text_buffer_, &text_table[0], data.text_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;
+	size_t vsize = variables.size();
+	std::cout << "value stack = " << vsize << std::endl;
+	for (size_t i=0; i<vsize; i++) {
+		variables[i].dump();
+	}
+	std::cout << "---code---" << std::endl;
+
+	static const char *op_name[] = {
+#define	VM_NAMETABLE
+#include "vm_code.h"
+#undef	VM_NAMETABLE
+		"LABEL",
+	} ;
+
+	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_;
+		}
+	}
+}
+#endif