diff Bison-Flex/Compiler-StackBase/EUC/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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Bison-Flex/Compiler-StackBase/EUC/node.cpp	Mon May 09 03:11:59 2011 +0900
@@ -0,0 +1,861 @@
+//
+// ノード
+//
+//		(c)2008 Chihiro.SAKAMOTO HyperWorks
+//
+#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();
+}