Mercurial > hg > Members > nobuyasu > SampleSource
diff Bison-Flex/BasicCompiler-StackBase/EUC/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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bison-Flex/BasicCompiler-StackBase/EUC/compiler.cpp Mon May 09 03:11:59 2011 +0900 @@ -0,0 +1,426 @@ +#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