Mercurial > hg > Members > nobuyasu > SampleSource
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), ¶m)); + 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(); +}