Mercurial > hg > Members > nobuyasu > SampleSource
view Bison-Flex/BasicCompiler-StackBase/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.start_; 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文 // // if expr then // A // endif // // > push expr // > jmp_nc L1 // > A // > L1: // // if expr then // A // else // B // endif // // > push expr // > jmp_nc L1 // > A // > jmp L2 // > L1: // > B // > L2: // void compiler::IfStatement(const yy::location& l, CNode *expr) { expr->push(this); int label = MakeLabel(); OpJmpNC(label); // 偽の時の飛び先 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文 // // for value=X to Y step Z // A // next // // > push X : value = X // > pop value // > L1: // > A // > push value : if (value == Y) goto L2 // > push Y // > eq // > jmp_c L2 // > push value : value = value + Z // > push Z // > add // > pop value // > jmp L1 // > L2: // void compiler::ForStatement(const yy::location& l, CAssign *start, CNode *end, CNode *step) { int label = MakeLabel(); start->analyze(this); SetLabel(label); state_stack.push(CState(l, STATE_FOR, label, start, 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(); // ループ終了のチェック state.start_->push_value(this); state.end_->push(this); OpEq(); OpJmpC(label); // 終了時飛び先 // カウンター増分 state.start_->push_value(this); if (state.step_) state.step_->push(this); else PushConst(1); OpAdd(); state.start_->pop_value(this); // ループ OpJmp(state.label1_); // ループ終了 SetLabel(label); // 後始末 delete state.start_; delete state.end_; delete state.step_; state_stack.pop(); } } // while文 // // while (expr) A // > L1: // > push expr // > jmp_nc L2 // > A // > jmp L1 // > L2: // void compiler::WhileStatement(const yy::location& l, CNode *expr) { int label1 = MakeLabel(); int label2 = MakeLabel(); SetLabel(label1); expr->push(this); OpJmpNC(label2); 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 // void compiler::PrintStatement(const yy::location& l, CArgs *args) { int arg_count = 0; if (args) { args->for_each_rev(std::bind2nd(std::mem_fun(&CNode::push), 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; } // デバッグダンプ #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_; } std::cout << std::endl; if (statement[i].op_ != VM_MAXCOMMAND) { pos += statement[i].size_; } } std::cout << "---" << std::endl; } #endif