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

#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