view Bison-Flex/BasicCompiler-StackBase/UTF8/#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.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;
}

void compiler::MakeGotoLabel(const yy::location& l, std::string *value)
{
  int label = MakeLabel();
  SetLabel(label);
  
  gototable.insert( std::map<std::string, int>::value_type( *value, label) );
}

void compiler::GotoLabel(const yy::location& l, std::string *value)
{
  OpJmp(gototable[*value]);
}


// ’¥é’¥Ù’¥ë’À¸’À®

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));
}

// ’¥é’¥Ù’¥ë’²ò’·è
//
// ’£±’¡¥’¥¢’¥É’¥ì’¥¹’¤ò’À¸’À®’¤¹’¤ë
// ’£²’¡¥’¥À’¥ß’¡¼’¤Î’¥é’¥Ù’¥ë’¥³’¥Þ’¥ó’¥É’¤¬’Í­’¤Ã’¤¿’¥¢’¥É’¥ì’¥¹’¤ò’¡¢’¥é’¥Ù’¥ë’¥Æ’¡¼’¥Ö’¥ë’¤Ë’ÅÐ’Ï¿’¤¹’¤ë
// ’£³’¡¥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