Mercurial > hg > Members > nobuyasu > myCompiler
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bison-Flex/BasicCompiler-MemoryBase/compiler.cpp Tue May 17 08:00:38 2011 +0900 @@ -0,0 +1,507 @@ +#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