comparison Bison-Flex/Compiler-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
comparison
equal deleted inserted replaced
-1:000000000000 0:db40c85cad7a
1 //
2 // コンパイラドライバ
3 //
4 // (c)2008 Chihiro.SAKAMOTO HyperWorks
5 //
6 #include <iostream>
7 #include <iomanip>
8 #include <memory>
9 #include "compiler.h"
10 #include "script-parser.hh"
11
12 // コンストラクタ
13
14 compiler::compiler()
15 : break_index(-1), error_count(0)
16 {
17 }
18
19 // デストラクタ
20
21 compiler::~compiler()
22 {
23 }
24
25 // コンパイル
26
27 bool compiler::compile(const std::string &f, vm::data &data)
28 {
29 // システムコールの設定
30 add_function(vm::SYS_PRINT, TYPE_VOID, "print", "s");
31 add_function(vm::SYS_TOSTR, TYPE_STRING, "str", "i");
32
33 // グローバル変数用、変数テーブルをセット
34 variables.push_back(CValueTable());
35 variables[0].set_global();
36
37 // 先頭はHALT命令にしておく
38 OpHalt();
39
40 file = f;
41 scan_begin(); // スキャナー初期化
42 yy::script_parser parser(*this); // パーサー構築
43 int result = parser.parse(); // 構文解析
44 scan_end(); // スキャナー終了
45
46 if (result != 0)
47 return false; // パーサーエラー
48
49 int code_size = LabelSetting(); // ラベルにアドレスを設定
50 CraeteData(data, code_size); // バイナリ生成
51 return error_count == 0;
52 }
53
54 // エラーメッセージを出力
55
56 void compiler::error(const yy::location& l, const std::string& m)
57 {
58 std::cerr << l << ": " << m << std::endl;
59 error_count++;
60 }
61
62 // エラーメッセージを出力
63
64 void compiler::error(const std::string& m)
65 {
66 std::cerr << m << std::endl;
67 error_count++;
68 }
69
70 // 内部関数の定義
71
72 bool compiler::add_function(int index, int type, const char *name, const char *args)
73 {
74 CFunctionTag func(type);
75 if (!func.SetArgs(args)) // 引数を設定
76 return false;
77
78 func.SetDeclaration(); // 宣言済み
79 func.SetSystem(); // Systemフラグセット
80 func.SetIndex(index); // システムコール番号を設定
81 if (functions.add(name, func) == 0) {
82 return false;
83 }
84 return true;
85 }
86
87 // 外部変数の定義
88
89 struct define_value {
90 compiler *comp_;
91 int type_;
92 define_value(compiler *comp, int type): comp_(comp), type_(type)
93 {
94 }
95
96 void operator()(CValueNode *node) const
97 {
98 comp_->AddValue(node->location(), type_, node->string(), node->left());
99 }
100 } ;
101
102 void compiler::DefineValue(const yy::location& l, int type, CValueList *value_list)
103 {
104 std::auto_ptr<CValueList> value_list_(value_list);
105
106 value_list->for_each(define_value(this, type));
107 }
108
109 // 関数宣言
110
111 void compiler::DefineFunction(const yy::location& l, int type, const std::string *name, CArgList *args)
112 {
113 std::auto_ptr<const std::string> name_(name);
114 std::auto_ptr<CArgList> args_(args);
115
116 const CFunctionTag *tag = functions.find(*name);
117 if (tag) { // 既に宣言済み
118 if (!tag->ChkArgList(args)) {
119 error(l, "関数 " + *name + " に異なる型の引数が指定されています");
120 return;
121 }
122 }
123 else {
124 CFunctionTag func(type);
125 func.SetArgs(args); // 引数を設定
126 func.SetDeclaration(); // 宣言済み
127 func.SetIndex(MakeLabel()); // ラベル登録
128 if (functions.add(*name, func) == 0) {
129 error(l, "内部エラー:関数テーブルに登録できません");
130 }
131 }
132 }
133
134 // 関数定義
135 //
136 // 関数が呼ばれた時点のスタック
137 //
138 // +--------------+
139 // | arg2 | -5
140 // +--------------+
141 // | arg1 | -4
142 // +--------------+
143 // | arg count | -3
144 // +--------------+
145 // | base_pointer | -2
146 // +--------------+
147 // | return addr | -1
148 // +--------------+
149 //
150 // したがって、引数の開始アドレスは-4となり、デクリメントしていく。
151
152 // 引数の変数名を登録
153
154 struct add_value {
155 compiler *comp_;
156 CValueTable &values_;
157 mutable int addr_;
158 add_value(compiler *comp, CValueTable &values): comp_(comp), values_(values), addr_(-4)
159 {
160 }
161
162 void operator()(CArgDef *arg) const
163 {
164 if (!values_.add_arg(arg->type(), arg->name(), addr_)) {
165 comp_->error(arg->location(), "引数 " + arg->name() + " は既に登録されています。");
166 }
167 addr_--;
168 }
169 } ;
170
171 void compiler::AddFunction(const yy::location& l, int type, const std::string *name, CArgList *args, CStateBlock *block)
172 {
173 std::auto_ptr<const std::string> name_(name);
174 std::auto_ptr<CArgList> args_(args);
175 std::auto_ptr<CStateBlock> block_(block);
176
177 CFunctionTag *tag = functions.find(*name);
178 if (tag) {
179 if (tag->IsDefinition()) {
180 error(l, "関数 " + *name + " は既に定義されています");
181 return;
182 }
183 if (tag->IsDeclaration() && !tag->ChkArgList(args)) {
184 error(l, "関数 " + *name + " に異なる型の引数が指定されています");
185 return;
186 }
187 tag->SetDefinition(); // 定義済みに設定
188 }
189 else {
190 CFunctionTag func(type);
191 func.SetArgs(args); // 引数を設定
192 func.SetDefinition(); // 定義済み
193 func.SetIndex(MakeLabel()); // ラベル登録
194 tag = functions.add(*name, func);
195 if (tag == 0)
196 error(l, "内部エラー:関数テーブルに登録できません");
197 }
198
199 current_function_name = *name; // 処理中の関数名を登録しておく
200 current_function_type = type; // 処理中の関数型を登録しておく
201 // 関数内関数(入れ子構造)は無いので、
202 // グローバル変数1つでよい
203
204 // 関数のエントリーポイントにラベルを置く
205
206 SetLabel(tag->GetIndex());
207
208 BlockIn(); // 変数スタックを増やす
209
210 // 引数があれば、引数リストを登録
211 if (args) {
212 args->for_each_rev(add_value(this, variables.back()));
213 }
214
215 // 文があれば、文を登録
216 if (block) {
217 block->analyze(this);
218 }
219
220 const CVMCode &code = statement.back();
221 if (type == TYPE_VOID) { // 戻り値無し
222 if (code.op_ != VM_RETURN) // returnが無いならば
223 OpReturn(); // returnを追加
224 }
225 else {
226 if (code.op_ != VM_RETURNV) { // returnが無いならば
227 error(l, "関数 " + *name + " の最後にreturn文が有りません。");
228 }
229 }
230
231 BlockOut(); // 変数スタックを減らす
232
233 current_function_name.clear(); // 処理中の関数名を消去
234 }
235
236 // 変数の登録
237
238 void compiler::AddValue(const yy::location& l, int type, const std::string &name, const CNode *node)
239 {
240 int size = 1;
241 if (node) {
242 if (node->op() != OP_CONST) {
243 error(l, "配列のサイズは定数で指定してください。");
244 }
245 else if (node->value() <= 0) {
246 error(l, "配列のサイズは1以上の定数が必要です。");
247 }
248 size = node->value();
249 }
250
251 CValueTable &values = variables.back();
252 if (!values.add(type, name, size)) {
253 error(l, "変数 " + name + " は既に登録されています。");
254 }
255 }
256
257 // ラベル生成
258
259 int compiler::MakeLabel()
260 {
261 int index = (int)labels.size();
262 labels.push_back(CLabel(index));
263 return index;
264 }
265
266 // ラベルのダミーコマンドをステートメントリストに登録する
267
268 void compiler::SetLabel(int label)
269 {
270 statement.push_back(CVMCode(VM_MAXCOMMAND, label));
271 }
272
273 // 文字列定数をpush
274
275 void compiler::PushString(const std::string &str)
276 {
277 PushString((int)text_table.size());
278 text_table.insert(text_table.end(), str.begin(), str.end());
279 text_table.push_back('\0');
280 }
281
282 // break文に対応したJmpコマンド生成
283
284 bool compiler::JmpBreakLabel()
285 {
286 if (break_index < 0)
287 return false;
288 OpJmp(break_index);
289 return true;
290 }
291
292 // ブロック内では、新しい変数セットに変数を登録する
293
294 void compiler::BlockIn()
295 {
296 int start_addr = 0; // 変数アドレスの開始位置
297 if (variables.size() > 1) { // ブロックの入れ子は、開始アドレスを続きからにする。
298 start_addr = variables.back().size();
299 }
300 variables.push_back(CValueTable(start_addr));
301 }
302
303 // ブロックの終了で、変数スコープが消える(変数セットを削除する)
304
305 void compiler::BlockOut()
306 {
307 variables.pop_back();
308 }
309
310 // ローカル変数用にスタックを確保
311
312 void compiler::AllocStack()
313 {
314 OpAllocStack(variables.back().size());
315 }
316
317 // ラベル解決
318 //
319 // 1.アドレスを生成する
320 // 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する
321 // 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする
322
323 // アドレス計算
324 struct calc_addr {
325 std::vector<CLabel> &labels_;
326 int &pos_;
327 calc_addr(std::vector<CLabel> &labels, int &pos): labels_(labels), pos_(pos)
328 {
329 }
330 void operator()(const CVMCode &code)
331 {
332 if (code.op_ == VM_MAXCOMMAND) { // ラベルのダミーコマンド
333 labels_[code.arg1_].pos_ = pos_;
334 }
335 else {
336 pos_ += code.size_;
337 }
338 }
339 } ;
340
341 // ジャンプアドレス設定
342
343 struct set_addr {
344 std::vector<CLabel> &labels_;
345 set_addr(std::vector<CLabel> &labels): labels_(labels)
346 {
347 }
348 void operator()(CVMCode &code)
349 {
350 switch (code.op_) {
351 case VM_JMP:
352 case VM_JMPC:
353 case VM_JMPNC:
354 case VM_TEST:
355 case VM_CALL:
356 code.arg1_ = labels_[code.arg1_].pos_;
357 break;
358 }
359 }
360 } ;
361
362 int compiler::LabelSetting()
363 {
364 // アドレス計算
365 int pos = 0;
366 std::for_each(statement.begin(), statement.end(), calc_addr(labels, pos));
367 // ジャンプアドレス設定
368 std::for_each(statement.begin(), statement.end(), set_addr(labels));
369
370 return pos;
371 }
372
373 // バイナリデータ生成
374
375 struct copy_code {
376 unsigned char *p;
377 copy_code(unsigned char *code): p(code)
378 {
379 }
380 void operator()(const CVMCode &code)
381 {
382 p = code.Get(p);
383 }
384 } ;
385
386 bool compiler::CraeteData(vm::data &data, int code_size)
387 {
388 const CFunctionTag *tag = GetFunctionTag("main"); // 開始位置
389 if (tag == 0) {
390 error("関数 \"main\" が見つかりません。");
391 return false;
392 }
393
394 data.command_ = new unsigned char[code_size];
395 data.text_buffer_ = new char[text_table.size()];
396 data.command_size_ = code_size;
397 data.text_size_ = (int)text_table.size();
398 data.value_size_ = (int)variables[0].size();
399 data.entry_point_ = labels[tag->index_].pos_;
400
401 if (data.text_size_ != 0)
402 memcpy(data.text_buffer_, &text_table[0], data.text_size_);
403
404 std::for_each(statement.begin(), statement.end(), copy_code(data.command_));
405
406 return true;
407 }
408
409 // デバッグダンプ
410 #ifdef _DEBUG
411 void compiler::debug_dump()
412 {
413 std::cout << "---variables---" << std::endl;
414 size_t vsize = variables.size();
415 std::cout << "value stack = " << vsize << std::endl;
416 for (size_t i=0; i<vsize; i++) {
417 variables[i].dump();
418 }
419 std::cout << "---code---" << std::endl;
420
421 static const char *op_name[] = {
422 #define VM_NAMETABLE
423 #include "vm_code.h"
424 #undef VM_NAMETABLE
425 "LABEL",
426 } ;
427
428 int pos = 0;
429 size_t size = statement.size();
430 for (size_t i=0; i < size; i++) {
431 std::cout << std::setw(6) << pos << ": " << op_name[statement[i].op_];
432 if (statement[i].size_ > 1) {
433 std::cout << ", " << statement[i].arg1_;
434 }
435 std::cout << std::endl;
436
437 if (statement[i].op_ != VM_MAXCOMMAND) {
438 pos += statement[i].size_;
439 }
440 }
441 }
442 #endif