view 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 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.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