4
|
1 //
|
5
|
2 // コンパイラドライバ
|
4
|
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
|
5
|
12 // コンストラクタ
|
4
|
13
|
|
14 compiler::compiler()
|
|
15 : break_index(-1), error_count(0)
|
|
16 {
|
|
17 }
|
|
18
|
5
|
19 // デストラクタ
|
4
|
20
|
|
21 compiler::~compiler()
|
|
22 {
|
|
23 }
|
|
24
|
5
|
25 // コンパイル
|
4
|
26
|
|
27 bool compiler::compile(const std::string &f, vm::data &data)
|
|
28 {
|
5
|
29 // システムコールの設定
|
4
|
30 add_function(vm::SYS_PRINT, TYPE_VOID, "print", "s");
|
|
31 add_function(vm::SYS_TOSTR, TYPE_STRING, "str", "i");
|
|
32
|
5
|
33 // グローバル変数用、変数テーブルをセット
|
4
|
34 variables.push_back(CValueTable());
|
|
35 variables[0].set_global();
|
|
36
|
5
|
37 // 先頭はHALT命令にしておく
|
4
|
38 OpHalt();
|
|
39
|
|
40 file = f;
|
5
|
41 scan_begin(); // スキャナー初期化
|
|
42 yy::script_parser parser(*this); // パーサー構築
|
|
43 int result = parser.parse(); // 構文解析
|
|
44 scan_end(); // スキャナー終了
|
4
|
45
|
|
46 if (result != 0)
|
5
|
47 return false; // パーサーエラー
|
4
|
48
|
5
|
49 int code_size = LabelSetting(); // ラベルにアドレスを設定
|
|
50 CraeteData(data, code_size); // バイナリ生成
|
4
|
51 return error_count == 0;
|
|
52 }
|
|
53
|
5
|
54 // エラーメッセージを出力
|
4
|
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
|
5
|
62 // エラーメッセージを出力
|
4
|
63
|
|
64 void compiler::error(const std::string& m)
|
|
65 {
|
|
66 std::cerr << m << std::endl;
|
|
67 error_count++;
|
|
68 }
|
|
69
|
5
|
70 // 内部関数の定義
|
4
|
71
|
|
72 bool compiler::add_function(int index, int type, const char *name, const char *args)
|
|
73 {
|
|
74 CFunctionTag func(type);
|
5
|
75 if (!func.SetArgs(args)) // 引数を設定
|
4
|
76 return false;
|
|
77
|
5
|
78 func.SetDeclaration(); // 宣言済み
|
|
79 func.SetSystem(); // Systemフラグセット
|
|
80 func.SetIndex(index); // システムコール番号を設定
|
4
|
81 if (functions.add(name, func) == 0) {
|
|
82 return false;
|
|
83 }
|
|
84 return true;
|
|
85 }
|
|
86
|
5
|
87 // 外部変数の定義
|
4
|
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
|
5
|
109 // 関数宣言
|
4
|
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);
|
5
|
117 if (tag) { // 既に宣言済み
|
4
|
118 if (!tag->ChkArgList(args)) {
|
5
|
119 error(l, "関数 " + *name + " に異なる型の引数が指定されています");
|
4
|
120 return;
|
|
121 }
|
|
122 }
|
|
123 else {
|
|
124 CFunctionTag func(type);
|
5
|
125 func.SetArgs(args); // 引数を設定
|
|
126 func.SetDeclaration(); // 宣言済み
|
|
127 func.SetIndex(MakeLabel()); // ラベル登録
|
4
|
128 if (functions.add(*name, func) == 0) {
|
5
|
129 error(l, "内部エラー:関数テーブルに登録できません");
|
4
|
130 }
|
|
131 }
|
|
132 }
|
|
133
|
5
|
134 // 関数定義
|
4
|
135 //
|
5
|
136 // 関数が呼ばれた時点のスタック
|
4
|
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 //
|
5
|
150 // したがって、引数の開始アドレスは-4となり、デクリメントしていく。
|
4
|
151
|
5
|
152 // 引数の変数名を登録
|
4
|
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_)) {
|
5
|
165 comp_->error(arg->location(), "引数 " + arg->name() + " は既に登録されています。");
|
4
|
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()) {
|
5
|
180 error(l, "関数 " + *name + " は既に定義されています");
|
4
|
181 return;
|
|
182 }
|
|
183 if (tag->IsDeclaration() && !tag->ChkArgList(args)) {
|
5
|
184 error(l, "関数 " + *name + " に異なる型の引数が指定されています");
|
4
|
185 return;
|
|
186 }
|
5
|
187 tag->SetDefinition(); // 定義済みに設定
|
4
|
188 }
|
|
189 else {
|
|
190 CFunctionTag func(type);
|
5
|
191 func.SetArgs(args); // 引数を設定
|
|
192 func.SetDefinition(); // 定義済み
|
|
193 func.SetIndex(MakeLabel()); // ラベル登録
|
4
|
194 tag = functions.add(*name, func);
|
|
195 if (tag == 0)
|
5
|
196 error(l, "内部エラー:関数テーブルに登録できません");
|
4
|
197 }
|
|
198
|
5
|
199 current_function_name = *name; // 処理中の関数名を登録しておく
|
|
200 current_function_type = type; // 処理中の関数型を登録しておく
|
|
201 // 関数内関数(入れ子構造)は無いので、
|
|
202 // グローバル変数1つでよい
|
4
|
203
|
5
|
204 // 関数のエントリーポイントにラベルを置く
|
4
|
205
|
|
206 SetLabel(tag->GetIndex());
|
|
207
|
5
|
208 BlockIn(); // 変数スタックを増やす
|
4
|
209
|
5
|
210 // 引数があれば、引数リストを登録
|
4
|
211 if (args) {
|
|
212 args->for_each_rev(add_value(this, variables.back()));
|
|
213 }
|
|
214
|
5
|
215 // 文があれば、文を登録
|
4
|
216 if (block) {
|
|
217 block->analyze(this);
|
|
218 }
|
|
219
|
|
220 const CVMCode &code = statement.back();
|
5
|
221 if (type == TYPE_VOID) { // 戻り値無し
|
|
222 if (code.op_ != VM_RETURN) // returnが無いならば
|
|
223 OpReturn(); // returnを追加
|
4
|
224 }
|
|
225 else {
|
5
|
226 if (code.op_ != VM_RETURNV) { // returnが無いならば
|
|
227 error(l, "関数 " + *name + " の最後にreturn文が有りません。");
|
4
|
228 }
|
|
229 }
|
|
230
|
5
|
231 BlockOut(); // 変数スタックを減らす
|
4
|
232
|
5
|
233 current_function_name.clear(); // 処理中の関数名を消去
|
4
|
234 }
|
|
235
|
5
|
236 void compiler::AddGotoFunction(const yy::location& l, int type, const std::string *name, CArgList *args, CStateBlock *block)
|
|
237 {
|
|
238 std::auto_ptr<const std::string> name_(name);
|
|
239 std::auto_ptr<CArgList> args_(args);
|
|
240 std::auto_ptr<CStateBlock> block_(block);
|
|
241
|
|
242 CFunctionTag *tag = functions.find(*name);
|
|
243 if (tag) {
|
|
244 if (tag->IsDefinition()) {
|
|
245 error(l, "関数 " + *name + " は既に定義されています");
|
|
246 return;
|
|
247 }
|
|
248 if (tag->IsDeclaration() && !tag->ChkArgList(args)) {
|
|
249 error(l, "関数 " + *name + " に異なる型の引数が指定されています");
|
|
250 return;
|
|
251 }
|
|
252 tag->SetDefinition(); // 定義済みに設定
|
|
253 }
|
|
254 else {
|
|
255 CFunctionTag func(type);
|
|
256 func.SetArgs(args); // 引数を設定
|
|
257 func.SetDefinition(); // 定義済み
|
|
258 func.SetIndex(MakeLabel()); // ラベル登録
|
|
259 tag = functions.add(*name, func);
|
|
260 if (tag == 0)
|
|
261 error(l, "内部エラー:関数テーブルに登録できません");
|
|
262 }
|
|
263 current_function_name = *name; // 処理中の関数名を登録しておく
|
|
264 current_function_type = type; // 処理中の関数型を登録しておく
|
|
265 // 関数内関数(入れ子構造)は無いので、
|
|
266 // グローバル変数1つでよい
|
|
267
|
|
268 // 関数のエントリーポイントにラベルを置く
|
|
269
|
|
270 SetLabel(tag->GetIndex());
|
|
271
|
|
272 // 引数があれば、引数リストを登録
|
|
273 if (args) {
|
|
274 args->for_each_rev(add_value(this, variables.back()));
|
|
275 }
|
|
276
|
|
277 // 文があれば、文を登録
|
|
278 if (block) {
|
|
279 block->analyze(this);
|
|
280 }
|
|
281
|
|
282 const CVMCode &code = statement.back();
|
|
283
|
6
|
284 current_function_name.clear(); // 処理中の関数名を消去
|
5
|
285
|
6
|
286 OpHalt();
|
|
287
|
5
|
288 }
|
|
289
|
6
|
290 void compiler::AddExit(const yy::location& l, int type)
|
|
291 {
|
|
292 // OpExit();
|
|
293 OpHalt();
|
|
294 }
|
|
295
|
|
296
|
|
297
|
5
|
298 // 変数の登録
|
4
|
299
|
|
300 void compiler::AddValue(const yy::location& l, int type, const std::string &name, const CNode *node)
|
|
301 {
|
|
302 int size = 1;
|
|
303 if (node) {
|
|
304 if (node->op() != OP_CONST) {
|
5
|
305 error(l, "配列のサイズは定数で指定してください。");
|
4
|
306 }
|
|
307 else if (node->value() <= 0) {
|
5
|
308 error(l, "配列のサイズは1以上の定数が必要です。");
|
4
|
309 }
|
|
310 size = node->value();
|
|
311 }
|
|
312
|
|
313 CValueTable &values = variables.back();
|
|
314 if (!values.add(type, name, size)) {
|
5
|
315 error(l, "変数 " + name + " は既に登録されています。");
|
4
|
316 }
|
|
317 }
|
|
318
|
6
|
319
|
|
320
|
|
321
|
5
|
322 // ラベル生成
|
4
|
323
|
|
324 int compiler::MakeLabel()
|
|
325 {
|
|
326 int index = (int)labels.size();
|
|
327 labels.push_back(CLabel(index));
|
|
328 return index;
|
|
329 }
|
|
330
|
5
|
331 // ラベルのダミーコマンドをステートメントリストに登録する
|
4
|
332
|
|
333 void compiler::SetLabel(int label)
|
|
334 {
|
|
335 statement.push_back(CVMCode(VM_MAXCOMMAND, label));
|
|
336 }
|
|
337
|
5
|
338 // 文字列定数をpush
|
4
|
339
|
|
340 void compiler::PushString(const std::string &str)
|
|
341 {
|
|
342 PushString((int)text_table.size());
|
|
343 text_table.insert(text_table.end(), str.begin(), str.end());
|
|
344 text_table.push_back('\0');
|
|
345 }
|
|
346
|
5
|
347 // break文に対応したJmpコマンド生成
|
4
|
348
|
|
349 bool compiler::JmpBreakLabel()
|
|
350 {
|
|
351 if (break_index < 0)
|
|
352 return false;
|
|
353 OpJmp(break_index);
|
|
354 return true;
|
|
355 }
|
|
356
|
5
|
357 // ブロック内では、新しい変数セットに変数を登録する
|
4
|
358
|
|
359 void compiler::BlockIn()
|
|
360 {
|
5
|
361 int start_addr = 0; // 変数アドレスの開始位置
|
|
362 if (variables.size() > 1) { // ブロックの入れ子は、開始アドレスを続きからにする。
|
4
|
363 start_addr = variables.back().size();
|
|
364 }
|
|
365 variables.push_back(CValueTable(start_addr));
|
|
366 }
|
|
367
|
5
|
368 // ブロックの終了で、変数スコープが消える(変数セットを削除する)
|
4
|
369
|
|
370 void compiler::BlockOut()
|
|
371 {
|
|
372 variables.pop_back();
|
|
373 }
|
|
374
|
5
|
375 // ローカル変数用にスタックを確保
|
4
|
376
|
|
377 void compiler::AllocStack()
|
|
378 {
|
|
379 OpAllocStack(variables.back().size());
|
|
380 }
|
|
381
|
5
|
382 // ラベル解決
|
4
|
383 //
|
5
|
384 // 1.アドレスを生成する
|
|
385 // 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する
|
|
386 // 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする
|
4
|
387
|
5
|
388 // アドレス計算
|
4
|
389 struct calc_addr {
|
|
390 std::vector<CLabel> &labels_;
|
|
391 int &pos_;
|
|
392 calc_addr(std::vector<CLabel> &labels, int &pos): labels_(labels), pos_(pos)
|
|
393 {
|
|
394 }
|
|
395 void operator()(const CVMCode &code)
|
|
396 {
|
5
|
397 if (code.op_ == VM_MAXCOMMAND) { // ラベルのダミーコマンド
|
4
|
398 labels_[code.arg1_].pos_ = pos_;
|
|
399 }
|
|
400 else {
|
|
401 pos_ += code.size_;
|
|
402 }
|
|
403 }
|
|
404 } ;
|
|
405
|
5
|
406 // ジャンプアドレス設定
|
4
|
407
|
|
408 struct set_addr {
|
|
409 std::vector<CLabel> &labels_;
|
|
410 set_addr(std::vector<CLabel> &labels): labels_(labels)
|
|
411 {
|
|
412 }
|
|
413 void operator()(CVMCode &code)
|
|
414 {
|
|
415 switch (code.op_) {
|
|
416 case VM_JMP:
|
|
417 case VM_JMPC:
|
|
418 case VM_JMPNC:
|
|
419 case VM_TEST:
|
|
420 case VM_CALL:
|
|
421 code.arg1_ = labels_[code.arg1_].pos_;
|
|
422 break;
|
|
423 }
|
|
424 }
|
|
425 } ;
|
|
426
|
|
427 int compiler::LabelSetting()
|
|
428 {
|
5
|
429 // アドレス計算
|
4
|
430 int pos = 0;
|
|
431 std::for_each(statement.begin(), statement.end(), calc_addr(labels, pos));
|
5
|
432 // ジャンプアドレス設定
|
4
|
433 std::for_each(statement.begin(), statement.end(), set_addr(labels));
|
|
434
|
|
435 return pos;
|
|
436 }
|
|
437
|
5
|
438 // バイナリデータ生成
|
4
|
439
|
|
440 struct copy_code {
|
|
441 unsigned char *p;
|
|
442 copy_code(unsigned char *code): p(code)
|
|
443 {
|
|
444 }
|
|
445 void operator()(const CVMCode &code)
|
|
446 {
|
|
447 p = code.Get(p);
|
|
448 }
|
|
449 } ;
|
|
450
|
|
451 bool compiler::CraeteData(vm::data &data, int code_size)
|
|
452 {
|
5
|
453 const CFunctionTag *tag = GetFunctionTag("main"); // 開始位置
|
4
|
454 if (tag == 0) {
|
5
|
455 error("関数 \"main\" が見つかりません。");
|
4
|
456 return false;
|
|
457 }
|
|
458
|
|
459 data.command_ = new unsigned char[code_size];
|
|
460 data.text_buffer_ = new char[text_table.size()];
|
|
461 data.command_size_ = code_size;
|
|
462 data.text_size_ = (int)text_table.size();
|
|
463 data.value_size_ = (int)variables[0].size();
|
|
464 data.entry_point_ = labels[tag->index_].pos_;
|
|
465
|
|
466 if (data.text_size_ != 0)
|
|
467 memcpy(data.text_buffer_, &text_table[0], data.text_size_);
|
|
468
|
|
469 std::for_each(statement.begin(), statement.end(), copy_code(data.command_));
|
|
470
|
|
471 return true;
|
|
472 }
|
|
473
|
5
|
474 // デバッグダンプ
|
4
|
475 #ifdef _DEBUG
|
|
476 void compiler::debug_dump()
|
|
477 {
|
|
478 std::cout << "---variables---" << std::endl;
|
|
479 size_t vsize = variables.size();
|
|
480 std::cout << "value stack = " << vsize << std::endl;
|
|
481 for (size_t i=0; i<vsize; i++) {
|
|
482 variables[i].dump();
|
|
483 }
|
|
484 std::cout << "---code---" << std::endl;
|
|
485
|
|
486 static const char *op_name[] = {
|
|
487 #define VM_NAMETABLE
|
|
488 #include "vm_code.h"
|
|
489 #undef VM_NAMETABLE
|
|
490 "LABEL",
|
|
491 } ;
|
|
492
|
|
493 int pos = 0;
|
|
494 size_t size = statement.size();
|
|
495 for (size_t i=0; i < size; i++) {
|
|
496 std::cout << std::setw(6) << pos << ": " << op_name[statement[i].op_];
|
|
497 if (statement[i].size_ > 1) {
|
|
498 std::cout << ", " << statement[i].arg1_;
|
|
499 }
|
|
500 std::cout << std::endl;
|
|
501
|
|
502 if (statement[i].op_ != VM_MAXCOMMAND) {
|
|
503 pos += statement[i].size_;
|
|
504 }
|
|
505 }
|
|
506 }
|
|
507 #endif
|