Mercurial > hg > Members > nobuyasu > SampleSource
view boost-spirit/Compiler-boost-spirit/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 "stdafx.h" #include <iostream> #include <iomanip> #include <memory> #include "compiler.h" #include "parser.h" // コンストラクタ compiler::compiler() : break_index(-1), error_count(0) { } // デストラクタ compiler::~compiler() { } // コンパイル bool compiler::compile(const std::string &file, vm::data &data) { // システムコールの設定 add_function(vm::SYS_PRINT, TYPE_VOID, "print", "s"); add_function(vm::SYS_TOSTR, TYPE_STRING, "str", "i"); // グローバル変数用、変数テーブルをセット variables.push_back(CValueTable()); variables[0].set_global(); // 先頭はHALT命令にしておく OpHalt(); bool result = script_parser(file, this); // 構文解析 if (!result) return false; // パーサーエラー int code_size = LabelSetting(); // ラベルにアドレスを設定 CraeteData(data, code_size); // バイナリ生成 return error_count == 0; } // エラーメッセージを出力 void compiler::error(const std::string& m) { std::cerr << m << std::endl; error_count++; } // 内部関数の定義 bool compiler::add_function(int index, int type, const char *name, const char *args) { CFunctionTag func(type); if (!func.SetArgs(args)) // 引数を設定 return false; func.SetDeclaration(); // 宣言済み func.SetSystem(); // Systemフラグセット func.SetIndex(index); // システムコール番号を設定 if (functions.add(name, func) == 0) { return false; } return true; } // 外部変数の定義 struct define_value { compiler *comp_; int type_; define_value(compiler *comp, int type): comp_(comp), type_(type) { } void operator()(cnode_t node) const { comp_->AddValue(type_, node->string(), node->left()); } } ; void compiler::DefineValue(int type, const std::vector<cnode_t> &node) { std::for_each(node.begin(), node.end(), define_value(this, type)); } // 関数宣言 void compiler::DefineFunction(int type, const std::string &name, const std::vector<int> &args) { const CFunctionTag *tag = functions.find(name); if (tag) { // 既に宣言済み if (!tag->ChkArgList(args)) { error("関数 " + name + " に異なる型の引数が指定されています"); return; } } else { CFunctionTag func(type); func.SetArgs(args); // 引数を設定 func.SetDeclaration(); // 宣言済み func.SetIndex(MakeLabel()); // ラベル登録 if (functions.add(name, func) == 0) { error("内部エラー:関数テーブルに登録できません"); } } } // 関数定義 // // 関数が呼ばれた時点のスタック // // +--------------+ // | arg2 | -5 // +--------------+ // | arg1 | -4 // +--------------+ // | arg count | -3 // +--------------+ // | base_pointer | -2 // +--------------+ // | return addr | -1 // +--------------+ // // したがって、引数の開始アドレスは-4となり、デクリメントしていく。 // 引数の変数名を登録 struct add_value { compiler *comp_; CValueTable &values_; mutable int addr_; add_value(compiler *comp, CValueTable &values): comp_(comp), values_(values), addr_(-4) { } void operator()(const cargdef &arg) const { if (!values_.add_arg(arg.type(), arg.name(), addr_)) { comp_->error("引数 " + arg.name() + " は既に登録されています。"); } addr_--; } } ; void compiler::AddFunction(int type, const std::string &name, const std::vector<cargdef> &args, cblock_t block) { CFunctionTag *tag = functions.find(name); if (tag) { if (tag->IsDefinition()) { error("関数 " + name + " は既に定義されています"); return; } if (tag->IsDeclaration() && !tag->ChkArgList(args)) { error("関数 " + name + " に異なる型の引数が指定されています"); return; } tag->SetDefinition(); // 定義済みに設定 } else { CFunctionTag func(type); func.SetArgs(args); // 引数を設定 func.SetDefinition(); // 定義済み func.SetIndex(MakeLabel()); // ラベル登録 tag = functions.add(name, func); if (tag == 0) error("内部エラー:関数テーブルに登録できません"); } current_function_name = name; // 処理中の関数名を登録しておく current_function_type = type; // 処理中の関数型を登録しておく // 関数内関数(入れ子構造)は無いので、 // グローバル変数1つでよい // 関数のエントリーポイントにラベルを置く SetLabel(tag->GetIndex()); BlockIn(); // 変数スタックを増やす // 引数リストを登録 std::for_each(args.rbegin(), args.rend(), add_value(this, variables.back())); // 文があれば、文を登録 if (block) { block->analyze(this); } const CVMCode &code = statement.back(); if (type == TYPE_VOID) { // 戻り値無し if (code.op_ != VM_RETURN) // returnが無いならば OpReturn(); // returnを追加 } else { if (code.op_ != VM_RETURNV) { // returnが無いならば error("関数 " + name + " の最後にreturn文が有りません。"); } } BlockOut(); // 変数スタックを減らす current_function_name.clear(); // 処理中の関数名を消去 } // 変数の登録 void compiler::AddValue(int type, const std::string &name, cnode_t node) { int size = 1; if (node) { if (node->op() != OP_NUMBER) { error("配列のサイズは定数で指定してください。"); } else if (node->number() <= 0) { error("配列のサイズは1以上の定数が必要です。"); } size = node->number(); } CValueTable &values = variables.back(); if (!values.add(type, name, size)) { error("変数 " + name + " は既に登録されています。"); } } // ラベル生成 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)); } // 文字列定数をpush void compiler::PushString(const std::string &str) { PushString((int)text_table.size()); text_table.insert(text_table.end(), str.begin(), str.end()); text_table.push_back('\0'); } // break文に対応したJmpコマンド生成 bool compiler::JmpBreakLabel() { if (break_index < 0) return false; OpJmp(break_index); return true; } // ブロック内では、新しい変数セットに変数を登録する void compiler::BlockIn() { int start_addr = 0; // 変数アドレスの開始位置 if (variables.size() > 1) { // ブロックの入れ子は、開始アドレスを続きからにする。 start_addr = variables.back().size(); } variables.push_back(CValueTable(start_addr)); } // ブロックの終了で、変数スコープが消える(変数セットを削除する) void compiler::BlockOut() { variables.pop_back(); } // ローカル変数用にスタックを確保 void compiler::AllocStack() { OpAllocStack(variables.back().size()); } // ラベル解決 // // 1.アドレスを生成する // 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する // 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする // アドレス計算 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: case VM_TEST: case VM_CALL: 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) { const CFunctionTag *tag = GetFunctionTag("main"); // 開始位置 if (tag == 0) { error("関数 \"main\" が見つかりません。"); return false; } data.command_ = new unsigned char[code_size]; data.text_buffer_ = new char[text_table.size()]; data.command_size_ = code_size; data.text_size_ = (int)text_table.size(); data.value_size_ = (int)variables[0].size(); data.entry_point_ = labels[tag->index_].pos_; if (data.text_size_ != 0) memcpy(data.text_buffer_, &text_table[0], data.text_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; size_t vsize = variables.size(); std::cout << "value stack = " << vsize << std::endl; for (size_t i=0; i<vsize; i++) { variables[i].dump(); } std::cout << "---code---" << std::endl; static const char *op_name[] = { #define VM_NAMETABLE #include "vm_code.h" #undef VM_NAMETABLE "LABEL", } ; 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_; } } } #endif