view WindowsOnly/WinScript2/node.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 <functional>
#include <iostream>
#include <iomanip>
#include "node.h"
#include "compiler.h"
#include "script-parser.hh"

// ノード生成
//	ただし、定数同士の計算は、leftノードに結果を代入し、それを返す

CNode *CNode::MakeNode(compiler &c, const yy::location& l, int op, CNode *left, CNode *right)
{
	if (right == 0) {
		switch (op) {
		  case OP_NEG:
			if (left->op_ == OP_CONST) {				// 定数演算を計算する
				left->value_ = -left->value_;
				return left;
			}
			break;
		}
		return new CNode(l, op, left);
	}

	// 定数演算を計算する
	if (left->op_ == OP_CONST && right->op_ == OP_CONST) {
		switch (op) {
		  case OP_LOGAND:
			left->value_ = (left->value_ && right->value_)? 1: 0;
			break;

		  case OP_LOGOR:
			left->value_ = (left->value_ || right->value_)? 1: 0;
			break;

		  case OP_EQ:
			left->value_ = (left->value_ == right->value_)? 1: 0;
			break;

		  case OP_NE:
			left->value_ = (left->value_ != right->value_)? 1: 0;
			break;

		  case OP_GT:
			left->value_ = (left->value_ > right->value_)? 1: 0;
			break;

		  case OP_GE:
			left->value_ = (left->value_ >= right->value_)? 1: 0;
			break;

		  case OP_LT:
			left->value_ = (left->value_ < right->value_)? 1: 0;
			break;

		  case OP_LE:
			left->value_ = (left->value_ <= right->value_)? 1: 0;
			break;

		  case OP_AND:
			left->value_ &= right->value_;
			break;

		  case OP_OR:
			left->value_ |= right->value_;
			break;

		  case OP_LSHIFT:
			left->value_ <<= right->value_;
			break;

		  case OP_RSHIFT:
			left->value_ >>= right->value_;
			break;

		  case OP_MINUS:
			left->value_ -= right->value_;
			break;

		  case OP_PLUS:
			left->value_ += right->value_;
			break;

		  case OP_TIMES:
			left->value_ *= right->value_;
			break;

		  case OP_DIVIDE:
			if (right->value_ == 0) {
				c.error(l, "定数計算を0で除算しました。");
			}
			else {
				left->value_ /= right->value_;
			}
			break;

		  case OP_MOD:
			if (right->value_ == 0) {
				c.error(l, "定数計算を0で除算しました。");
			}
			else {
				left->value_ %= right->value_;
			}
			break;

		  default:
			return new CNode(l, op, left, right);
		}
		delete right;
		return left;
	}

	// 文字列同士の定数計算
	if (left->op_ == OP_STRING && right->op_ == OP_STRING) {
		if (op == OP_PLUS) {
			*left->string_ += *right->string_;
			delete right;
			return left;
		}

		int value = 0;
		switch (op) {
		  case OP_EQ:
			if (*left->string_ == *right->string_)
				value = 1;
			break;

		  case OP_NE:
			if (*left->string_ != *right->string_)
				value = 1;
			break;

		  case OP_GT:
			if (*left->string_ > *right->string_)
				value = 1;
			break;

		  case OP_GE:
			if (*left->string_ >= *right->string_)
				value = 1;
			break;

		  case OP_LT:
			if (*left->string_ < *right->string_)
				value = 1;
			break;

		  case OP_LE:
			if (*left->string_ <= *right->string_)
				value = 1;
			break;

		  default:
			c.error(l, "文字列同士ではできない計算です");
			break;
		}
		delete left;
		delete right;
		return new CNode(l, OP_CONST, value);
	}
	return new CNode(l, op, left, right);
}

// ノードのpush処理
int CNode::push(compiler *c) const
{
	switch (op_) {
	  case OP_NEG:
		if (left_->push(c) == TYPE_STRING)
			c->error(l_, "文字列には許されない計算です。");
		c->OpNeg();
		return TYPE_INTEGER;

	  case OP_CONST:
		c->PushConst(value_);
		return TYPE_INTEGER;

	  case OP_STRING:
		c->PushString(*string_);
		return TYPE_STRING;
	}

	int left_type = left_->push(c);
	int right_type = right_->push(c);

	if (left_type != right_type)
		c->error(l_, "文字列と整数間で計算できません。");

	// 整数計算ノードの処理
	if (left_type == TYPE_INTEGER) {
		switch (op_) {
		  case OP_LOGAND:
			c->OpLogAnd();
			break;

		  case OP_LOGOR:
			c->OpLogOr();
			break;

		  case OP_EQ:
			c->OpEq();
			break;

		  case OP_NE:
			c->OpNe();
			break;

		  case OP_GT:
			c->OpGt();
			break;

		  case OP_GE:
			c->OpGe();
			break;

		  case OP_LT:
			c->OpLt();
			break;

		  case OP_LE:
			c->OpLe();
			break;

		  case OP_AND:
			c->OpAnd();
			break;

		  case OP_OR:
			c->OpOr();
			break;

		  case OP_LSHIFT:
			c->OpLeftShift();
			break;

		  case OP_RSHIFT:
			c->OpRightShift();
			break;

		  case OP_MINUS:
			c->OpSub();
			break;

		  case OP_PLUS:
			c->OpAdd();
			break;

		  case OP_TIMES:
			c->OpMul();
			break;

		  case OP_DIVIDE:
			c->OpDiv();
			break;

		  case OP_MOD:
			c->OpMod();
			break;

		  default:
			c->error(l_, "内部エラー:処理できない計算ノードがありました。");
			break;
		}
		return TYPE_INTEGER;
	}

	// 文字列計算ノードの処理
	switch (op_) {
	  case OP_EQ:
		c->OpStrEq();
		return TYPE_INTEGER;

	  case OP_NE:
		c->OpStrNe();
		return TYPE_INTEGER;

	  case OP_GT:
		c->OpStrGt();
		return TYPE_INTEGER;

	  case OP_GE:
		c->OpStrGe();
		return TYPE_INTEGER;

	  case OP_LT:
		c->OpStrLt();
		return TYPE_INTEGER;

	  case OP_LE:
		c->OpStrLe();
		return TYPE_INTEGER;

	  case OP_PLUS:
		c->OpStrAdd();
		break;

	  default:
		c->error(l_, "文字列では計算できない式です。");
		break;
	}
	return TYPE_STRING;
}

// ノードのpop
// 計算ノードはpopできない

int CNode::pop(compiler *c) const
{
	c->error(l_, "内部エラー:計算ノードをpopしています。");
	return TYPE_INTEGER;
}

// 変数ノードのpush
int CValueNode::push(compiler *c) const
{
	if (op_ != OP_VALUE) {
		c->error(l_, "内部エラー:変数ノードに変数以外が登録されています。");
	}
	else {
		const CValueTag *tag = c->GetValueTag(*string_);
		if (tag == 0) {
			c->error(l_, "変数 " + *string_ + " は定義されていません。");
		}
		else {
			// 参照型変数は、引数にしか存在しない
			if (tag->type_ >= TYPE_INTEGER_REF) {
				if (left_) {		// 配列
					left_->push(c);
					c->PushLocalArrayRef(tag->addr_);
				}
				else {
					c->PushLocalRef(tag->addr_);
				}
				return tag->type_ - TYPE_INTEGER_REF;
			}
			if (tag->global_) {		// 外部変数
				if (left_) {		// 配列
					left_->push(c);
					c->PushArray(tag->addr_);
				}
				else {
					c->PushValue(tag->addr_);
				}
			}
			else {					// ローカル変数
				if (left_) {		// 配列
					left_->push(c);
					c->PushLocalArray(tag->addr_);
				}
				else {
					c->PushLocal(tag->addr_);
				}
			}
			return tag->type_;
		}
	}
	return TYPE_INTEGER;
}

// 変数ノードのpop
int CValueNode::pop(compiler *c) const
{
	if (op_ != OP_VALUE) {
		c->error(l_, "内部エラー:変数ノードに変数以外が登録されています。");
	}
	else {
		const CValueTag *tag = c->GetValueTag(*string_);
		if (tag == 0) {
			c->error(l_, "変数 " + *string_ + " は定義されていません。");
		}
		else {
			// 参照型変数は、引数にしか存在しない
			if (tag->type_ >= TYPE_INTEGER_REF) {
				if (left_) {		// 配列
					left_->push(c);
					c->PopLocalArrayRef(tag->addr_);
				}
				else {
					c->PopLocalRef(tag->addr_);
				}
				return tag->type_ - TYPE_INTEGER_REF;
			}
			if (tag->global_) {		// 外部変数
				if (left_) {		// 配列
					left_->push(c);
					c->PopArray(tag->addr_);
				}
				else {
					c->PopValue(tag->addr_);
				}
			}
			else {					// ローカル変数
				if (left_) {		// 配列
					left_->push(c);
					c->PopLocalArray(tag->addr_);
				}
				else {
					c->PopLocal(tag->addr_);
				}
			}
			return tag->type_;
		}
	}
	return TYPE_INTEGER;
}

// 関数呼び出し

struct set_arg {
	compiler *comp_;
	const CFunctionTag *func_;
	mutable int index_;
	set_arg(compiler *comp, const CFunctionTag *func): comp_(comp), func_(func), index_(0)
	{
	}

	void operator()(CNode *node) const
	{
		int type = func_->GetArg(index_++);
		if (type >= TYPE_INTEGER_REF) {		// 参照
			if (node->op() != OP_VALUE) {
				comp_->error(node->location(), "参照型引数に、変数以外は指定できません。");
			}
			else {
				const CValueTag *tag = comp_->GetValueTag(node->string());
				if (tag == 0) {
					comp_->error(node->location(), "変数 " + node->string() + " は定義されていません。");
				}
				else if (tag->type_ >= TYPE_INTEGER_REF) {		// 参照
					// 参照型変数は、ローカルしかない
					if (node->left()) {
						node->left()->push(comp_);
						comp_->PushLocal(tag->addr_);
						comp_->OpAdd();
					}
					else {
						comp_->PushLocal(tag->addr_);
					}
				}
				else {
					if (TypeToRef(tag->type_) != type) {
						comp_->error(node->location(), "引数の型が合いません。");
					}
					int addr = tag->addr_;
					if (tag->global_)			// 外部変数
						addr |= vm::vcpu::global_flag;
					// アドレスをpush
					if (node->left()) {			// 配列
						if (node->left()->op() == OP_CONST) {
							comp_->PushAddr(addr + node->left()->value());
						}
						else {
							node->left()->push(comp_);
							comp_->PushArrayAddr(addr);
						}
					}
					else {
						comp_->PushAddr(addr);
					}
				}
			}
		}
		else {
			if (node->push(comp_) != type) {
				comp_->error(node->location(), "引数の型が合いません。");
			}
		}
	}
} ;

int CFunctionNode::push(compiler *c) const
{
	const CFunctionTag *tag = c->GetFunctionTag(*string_);
	if (tag == NULL) {
		c->error(l_, "関数 " + *string_ + "は、定義されていません。");
		return TYPE_INTEGER;
	}

	int arg_size = (args_)? args_->size(): 0;
	if (tag->ArgSize() != arg_size) {
		c->error(l_, "引数の数が合いません。");
	}

	// 引数をpush
	if (args_ && tag->ArgSize() == arg_size) {
		args_->for_each(set_arg(c, tag));
	}

	// 引数の数をpush
	c->PushConst(arg_size);

	if (tag->IsSystem()) {
		c->OpSysCall(tag->GetIndex());		// システムコール
	}
	else {
		c->OpCall(tag->GetIndex());			// スクリプト上の関数
	}

	return tag->type_;
}

// 関数にpopはできないのでエラーメッセージを出す
int CFunctionNode::pop(compiler *c) const
{
	c->error(l_, "内部エラー:関数ノードをpopした");
	return TYPE_INTEGER;
}

// 変数定義

struct add_value {
	compiler *comp_;
	int type_;
	add_value(compiler *comp, int type): comp_(comp), type_(type)
	{
	}

	void operator()(CValueNode *node)
	{
		comp_->AddValue(node->location(), type_, node->string(), node->left());
	}
} ;

void CDecl::analyze(compiler *c)
{
	list_->for_each(add_value(c, type_));
}

// 代入命令を生成
//
//	a = b
//	>	push b
//	>	pop a
//
//	a += b
//	>	push a
//	>	push b
//	>	add
//	>	pop a
//
void CAssign::analyze(compiler *c)
{
	if (op_ != '=')
		value_->push(c);

	if (expr_->push(c) == TYPE_INTEGER) {
		switch (op_) {
		  case '+':
			c->OpAdd();
			break;

		  case '-':
			c->OpSub();
			break;

		  case '*':
			c->OpMul();
			break;

		  case '/':
			c->OpDiv();
			break;

		  case '%':
			c->OpMod();
			break;
		}
		if (value_->pop(c) != TYPE_INTEGER)
			c->error(l_, "文字列型に整数を代入しています。");
		return;
	}

	switch (op_) {
	  case '+':
		c->OpStrAdd();
		break;

	  case '=':
		break;

	  default:
		c->error(l_, "文字列では許されない計算です。");
		break;
	}
	if (value_->pop(c) != TYPE_STRING)
		c->error(l_, "整数型に文字列を代入しています。");
}

// '{' '}' で囲まれた文の生成

void CStateBlock::analyze(compiler *c)
{
	// ローカル変数の定義
	if (decls_) {
		decls_->for_each(std::bind2nd(std::mem_fun(&CDecl::analyze), c));
		c->AllocStack();
	}

	// 文のコード生成
	if (states_) {
		states_->for_each(std::bind2nd(std::mem_fun(&CStatement::analyze), c));
	}
}

// NOP

void CNopStatement::analyze(compiler *c)
{
	// 何もしない
}

// 代入

void CAssignStatement::analyze(compiler *c)
{
	assign_->analyze(c);
}

// 関数呼び出し

void CFunctionStatement::analyze(compiler *c)
{
	int type = node_.push(c);
	if (type != TYPE_VOID)
		c->OpPop();			// 戻り値を捨てるためのpop
}

// IF文
//
//	if (expr) A
//	>	push expr
//	>	jmp_nc L1
//	>		A
//	>	L1:
//
//	if (expr) A else B
//	>	push expr
//	>	jmp_nc L1
//	>		A
//	>	jmp L2
//	>	L1:
//	>		B
//	>	L2:
//
void CIfStatement::analyze(compiler *c)
{
	expr_->push(c);
	int label1 = c->MakeLabel();
	c->OpJmpNC(label1);
	then_statement_->analyze(c);

	if (else_statement_) {
		int label2 = c->MakeLabel();
		c->OpJmp(label2);
		c->SetLabel(label1);
		else_statement_->analyze(c);
		c->SetLabel(label2);
	}
	else {
		c->SetLabel(label1);
	}
}

// FOR文
//
//	for (init; expr; next) A
//	>	init
//	>	L1:
//	>	push expr
//	>	jmp_nc L2
//	>		A
//	>		next
//	>		jmp L1
//	>	L2:
//
void CForStatement::analyze(compiler *c)
{
	int label1 = c->MakeLabel();
	int label2 = c->MakeLabel();

	int break_label = c->SetBreakLabel(label2);

	init_->analyze(c);
	c->SetLabel(label1);
	expr_->push(c);
	c->OpJmpNC(label2);
	statement_->analyze(c);
	next_->analyze(c);
	c->OpJmp(label1);
	c->SetLabel(label2);

	c->SetBreakLabel(break_label);
}

// WHILE文
//
//	while (expr) A
//	>	L1:
//	>	push expr
//	>	jmp_nc L2
//	>		A
//	>		jmp L1
//	>	L2:
//
void CWhileStatement::analyze(compiler *c)
{
	int label1 = c->MakeLabel();
	int label2 = c->MakeLabel();

	int break_label = c->SetBreakLabel(label2);

	c->SetLabel(label1);
	expr_->push(c);
	c->OpJmpNC(label2);
	statement_->analyze(c);
	c->OpJmp(label1);
	c->SetLabel(label2);

	c->SetBreakLabel(break_label);
}

// SWITCH文
//
//	switch (expr) {
//		case A:
//			STATE_A
//			break;
//		case B:
//			STATE_B
//			break;
//		default:
//			STATE_C
//			break;
//	}
//	>	push expr
//	>	push A
//	>	test L1		; stack上の2値を比較し、等しければpopしてJmp
//	>	push B
//	>	test L2
//	>	pop
//	>	jmp L3
//	>	L1:
//	>		STATE_A
//	>	jmp L0		; break
//	>	L2:
//	>		STATE_B
//	>	jmp L0		; break
//	>	L3:
//	>		STATE_C
//	>	jmp L0		; break
//	>	L0:
//
void CSwitchStatement::analyze(compiler *c)
{
	expr_->push(c);

	if (list_) {
		int label = c->MakeLabel();		// L0ラベル作成
		int break_label = c->SetBreakLabel(label);
		int default_label = label;

		case_action_param param(c, default_label);

		list_->for_each(std::bind2nd(std::mem_fun(&CStatement::case_analyze), &param));
		c->OpPop();
		c->OpJmp(default_label);

		list_->for_each(std::bind2nd(std::mem_fun(&CStatement::analyze), c));
		c->SetLabel(label);

		c->SetBreakLabel(break_label);
	}
}

// CASE文
//
//	switch文の特殊処理
//
void CCaseStatement::analyze(compiler *c)
{
	c->SetLabel(label_);
}

void CCaseStatement::case_analyze(case_action_param *param)
{
	compiler *c = param->comp_;

	label_ = c->MakeLabel();
	if (expr_->op() != OP_CONST)
		c->error(l_, "case 文には定数のみ指定できます。");
	expr_->push(c);
	c->OpTest(label_);
}

// DEFAULT文
//
//	switch文の特殊処理
//
void CDefaultStatement::analyze(compiler *c)
{
	c->SetLabel(label_);
}

void CDefaultStatement::case_analyze(case_action_param *param)
{
	label_ = param->comp_->MakeLabel();
	param->default_label = label_;
}

// BREAK文
//
//	登録されているJump先へのJmp命令を生成
//
void CBreakStatement::analyze(compiler *c)
{
	if (!c->JmpBreakLabel()) {
		c->error(l_, "breakがswitch/for/while外に有ります");
	}
}

// RETURN文
//
//	RETURNコマンドを生成
//
void CReturnStatement::analyze(compiler *c)
{
	if (c->GetFunctionType() == TYPE_VOID) {	// 戻り値無し
		if (expr_ != 0) {
			c->error(l_, "void関数に戻り値が設定されています");
		}
		c->OpReturn();
	}
	else {
		if (expr_ == 0) {
			c->error(l_, "関数の戻り値がありません");
		}
		else {
			int expr_type = expr_->push(c);		// 戻り値をpush
			if (expr_type != c->GetFunctionType()) {
				c->error(l_, "戻り値の型が合いません");
			}
		}
		c->OpReturnV();
	}
}

// 文ブロック
//
//	再帰的にすべての文を解析
//
void CBlockStatement::analyze(compiler *c)
{
	c->BlockIn();
	block_->analyze(c);
	c->BlockOut();
}