Mercurial > hg > Members > nobuyasu > SampleSource
view Bison-Flex/BasicCompiler-MemoryBase/compiler.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 <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