Mercurial > hg > Members > nobuyasu > myCompiler
comparison Bison-Flex/BasicCompiler-MemoryBase/compiler.cpp @ 4:805d39d28230
add Compiler-stackbase
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 17 May 2011 08:00:38 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:3cea2e8a0e4b | 4:805d39d28230 |
---|---|
1 #include <iostream> | |
2 #include <iomanip> | |
3 #include "script-parser.hh" | |
4 #include "compiler.h" | |
5 | |
6 #ifdef _MSC_VER | |
7 #pragma warning(disable: 4996) | |
8 #endif | |
9 | |
10 // コンストラクタ | |
11 | |
12 compiler::compiler() | |
13 : error_count(0) | |
14 { | |
15 } | |
16 | |
17 // デストラクタ | |
18 | |
19 compiler::~compiler() | |
20 { | |
21 } | |
22 | |
23 // コンパイル | |
24 | |
25 bool compiler::compile(const std::string &f, vm::data &data) | |
26 { | |
27 // システムコールの設定 | |
28 | |
29 file = f; | |
30 scan_begin(); // スキャナー初期化 | |
31 yy::script_parser parser(*this); // パーサー構築 | |
32 int result = parser.parse(); // 構文解析 | |
33 scan_end(); // スキャナー終了 | |
34 | |
35 if (result != 0) | |
36 return false; // パーサーエラー | |
37 | |
38 // ステートスタックが空ではないならば、if, for, whileが | |
39 // 閉じていない | |
40 while (!state_stack.empty()) { | |
41 CState state = state_stack.top(); | |
42 switch (state.state_) { | |
43 case STATE_IF: | |
44 error(state.l_, "ifに対応するendifが有りません"); | |
45 break; | |
46 | |
47 case STATE_FOR: | |
48 error(state.l_, "forに対応するnextが有りません"); | |
49 delete state.end_; | |
50 delete state.step_; | |
51 break; | |
52 | |
53 case STATE_WHILE: | |
54 error(state.l_, "whileに対応するwendが有りません"); | |
55 break; | |
56 } | |
57 state_stack.pop(); | |
58 } | |
59 | |
60 // 番兵用HALTコマンドを追加 | |
61 const CVMCode &code = statement.back(); | |
62 if (code.op_ != VM_HALT) // haltが無いならば | |
63 OpHalt(); // haltを追加 | |
64 | |
65 int code_size = LabelSetting(); // ラベルにアドレスを設定 | |
66 CraeteData(data, code_size); // バイナリ生成 | |
67 | |
68 return error_count == 0; | |
69 } | |
70 | |
71 // エラーメッセージを出力 | |
72 | |
73 void compiler::error(const yy::location& l, const std::string& m) | |
74 { | |
75 std::cerr << l << ": " << m << std::endl; | |
76 error_count++; | |
77 } | |
78 | |
79 // エラーメッセージを出力 | |
80 | |
81 void compiler::error(const std::string& m) | |
82 { | |
83 std::cerr << m << std::endl; | |
84 error_count++; | |
85 } | |
86 | |
87 // 命令文の登録 | |
88 | |
89 // 代入文 | |
90 void compiler::AssignStatement(const yy::location& l, CAssign *assign) | |
91 { | |
92 assign->analyze(this); | |
93 delete assign; | |
94 } | |
95 | |
96 // if文 | |
97 void compiler::IfStatement(const yy::location& l, CNode *expr) | |
98 { | |
99 int label = MakeLabel(); | |
100 MakeJmpNC(label, CNodeValue::MakeNodeValue(this, expr)); | |
101 | |
102 state_stack.push(CState(l, STATE_IF, label)); | |
103 | |
104 delete expr; | |
105 } | |
106 | |
107 void compiler::ElseStatement(const yy::location& l) | |
108 { | |
109 if (state_stack.empty() || state_stack.top().state_ != STATE_IF) { | |
110 error(l, "if文と対応していないelse文が有りました。"); | |
111 } | |
112 else { | |
113 CState &state = state_stack.top(); | |
114 int label = MakeLabel(); | |
115 OpJmp(label); | |
116 SetLabel(state.label1_); // 偽の時の飛び先をここにする | |
117 state.label1_ = label; // endifの飛び先を再設定 | |
118 } | |
119 } | |
120 | |
121 void compiler::EndifStatement(const yy::location& l) | |
122 { | |
123 if (state_stack.empty() || state_stack.top().state_ != STATE_IF) { | |
124 error(l, "if文と対応していないendif文が有りました。"); | |
125 } | |
126 else { | |
127 CState &state = state_stack.top(); | |
128 SetLabel(state.label1_); // endifの飛び先をここにする | |
129 state_stack.pop(); // ステートスタックをpop | |
130 } | |
131 } | |
132 | |
133 // FOR文 | |
134 void compiler::ForStatement(const yy::location& l, CAssign *start, CNode *end, CNode *step) | |
135 { | |
136 int label = MakeLabel(); | |
137 | |
138 CNodeValue counter = start->analyze(this); | |
139 SetLabel(label); | |
140 | |
141 state_stack.push(CState(l, STATE_FOR, label, counter, end, step)); | |
142 } | |
143 | |
144 void compiler::NextStatement(const yy::location& l) | |
145 { | |
146 if (state_stack.empty() || state_stack.top().state_ != STATE_FOR) { | |
147 error(l, "for文と対応していないnext文が有りました。"); | |
148 } | |
149 else { | |
150 CState &state = state_stack.top(); | |
151 int label = MakeLabel(); | |
152 MakeJmpC(label, MakeOp(OP_EQ, -1, state.counter_, CNodeValue::MakeNodeValue(this, state.end_))); | |
153 { | |
154 CNodeValue step(CNodeValue::CONST, 1); | |
155 if (state.step_) | |
156 step = CNodeValue::MakeNodeValue(this, state.step_); | |
157 MakeOp(OP_PLUS, state.counter_.value(), state.counter_, step); | |
158 } | |
159 OpJmp(state.label1_); | |
160 SetLabel(label); | |
161 | |
162 // 後始末 | |
163 delete state.end_; | |
164 delete state.step_; | |
165 | |
166 state_stack.pop(); | |
167 } | |
168 } | |
169 | |
170 // while文 | |
171 void compiler::WhileStatement(const yy::location& l, CNode *expr) | |
172 { | |
173 int label1 = MakeLabel(); | |
174 int label2 = MakeLabel(); | |
175 | |
176 SetLabel(label1); | |
177 MakeJmpNC(label2, CNodeValue::MakeNodeValue(this, expr)); | |
178 | |
179 state_stack.push(CState(l, STATE_WHILE, label1, label2)); | |
180 | |
181 delete expr; | |
182 } | |
183 | |
184 void compiler::WendStatement(const yy::location& l) | |
185 { | |
186 if (state_stack.empty() || state_stack.top().state_ != STATE_WHILE) { | |
187 error(l, "while文と対応していないwend文が有りました。"); | |
188 } | |
189 else { | |
190 CState &state = state_stack.top(); | |
191 OpJmp(state.label1_); | |
192 SetLabel(state.label2_); | |
193 state_stack.pop(); | |
194 } | |
195 } | |
196 | |
197 // end文 | |
198 // | |
199 // > halt | |
200 // | |
201 void compiler::EndStatement(const yy::location& l) | |
202 { | |
203 OpHalt(); | |
204 } | |
205 | |
206 // print文 | |
207 // | |
208 // print a, b, c | |
209 // | |
210 // > push c | |
211 // > push b | |
212 // > push a | |
213 // > print 3 | |
214 // | |
215 | |
216 struct print_action { | |
217 compiler *comp_; | |
218 print_action(compiler *comp): comp_(comp) | |
219 { | |
220 } | |
221 | |
222 void operator()(CNode *node) const | |
223 { | |
224 CNodeValue value = CNodeValue::MakeNodeValue(comp_, node); | |
225 comp_->MakePush(value); | |
226 } | |
227 } ; | |
228 | |
229 void compiler::PrintStatement(const yy::location& l, CArgs *args) | |
230 { | |
231 int arg_count = 0; | |
232 if (args) { | |
233 args->for_each_rev(print_action(this)); | |
234 arg_count = args->size(); | |
235 } | |
236 | |
237 OpPrint(arg_count); | |
238 | |
239 delete args; | |
240 } | |
241 | |
242 // ラベル生成 | |
243 | |
244 int compiler::MakeLabel() | |
245 { | |
246 int index = (int)labels.size(); | |
247 labels.push_back(CLabel(index)); | |
248 return index; | |
249 } | |
250 | |
251 // ラベルのダミーコマンドをステートメントリストに登録する | |
252 | |
253 void compiler::SetLabel(int label) | |
254 { | |
255 statement.push_back(CVMCode(VM_MAXCOMMAND, label)); | |
256 } | |
257 | |
258 // ラベル解決 | |
259 // | |
260 // 1.アドレスを生成する | |
261 // 2.ダミーのラベルコマンドが有ったアドレスを、ラベルテーブルに登録する | |
262 // 3.Jmpコマンドの飛び先をラベルテーブルに登録されたアドレスにする | |
263 | |
264 // note: | |
265 // GCCでは、関数オブジェクトを関数内に書けないので、ここに記述する。 | |
266 // VC++9.0(VS2008)では関数内に書くことで、スコープを封じ込める事が可能。 | |
267 | |
268 // アドレス計算関数オブジェクト | |
269 struct calc_addr { | |
270 std::vector<CLabel> &labels_; | |
271 int &pos_; | |
272 calc_addr(std::vector<CLabel> &labels, int &pos): labels_(labels), pos_(pos) | |
273 { | |
274 } | |
275 void operator()(const CVMCode &code) | |
276 { | |
277 if (code.op_ == VM_MAXCOMMAND) { // ラベルのダミーコマンド | |
278 labels_[code.arg1_].pos_ = pos_; | |
279 } | |
280 else { | |
281 pos_ += code.size_; | |
282 } | |
283 } | |
284 } ; | |
285 | |
286 // ジャンプアドレス設定関数オブジェクト | |
287 struct set_addr { | |
288 std::vector<CLabel> &labels_; | |
289 set_addr(std::vector<CLabel> &labels): labels_(labels) | |
290 { | |
291 } | |
292 void operator()(CVMCode &code) | |
293 { | |
294 switch (code.op_) { | |
295 case VM_JMP: | |
296 case VM_JMPC: | |
297 case VM_JMPNC: | |
298 code.arg1_ = labels_[code.arg1_].pos_; | |
299 break; | |
300 } | |
301 } | |
302 } ; | |
303 | |
304 int compiler::LabelSetting() | |
305 { | |
306 // アドレス計算 | |
307 int pos = 0; | |
308 std::for_each(statement.begin(), statement.end(), calc_addr(labels, pos)); | |
309 | |
310 // ジャンプアドレス設定 | |
311 std::for_each(statement.begin(), statement.end(), set_addr(labels)); | |
312 | |
313 return pos; | |
314 } | |
315 | |
316 // バイナリデータ生成 | |
317 | |
318 // 関数オブジェクト | |
319 struct copy_code { | |
320 unsigned char *p; | |
321 copy_code(unsigned char *code): p(code) | |
322 { | |
323 } | |
324 void operator()(const CVMCode &code) | |
325 { | |
326 p = code.Get(p); | |
327 } | |
328 } ; | |
329 | |
330 bool compiler::CraeteData(vm::data &data, int code_size) | |
331 { | |
332 data.command_ = new unsigned char[code_size]; | |
333 data.command_size_ = code_size; | |
334 data.value_size_ = (int)variables.size(); | |
335 | |
336 std::for_each(statement.begin(), statement.end(), copy_code(data.command_)); | |
337 | |
338 return true; | |
339 } | |
340 | |
341 // 使用してよい一時変数を返す | |
342 int compiler::AllocTempValue() | |
343 { | |
344 // テーブルから空きを探してみる | |
345 size_t size = temp_value.size(); | |
346 | |
347 for (size_t i=0; i<size; i++) { | |
348 if (temp_value[i].ref_ == 0) { | |
349 temp_value[i].ref_ = 1; | |
350 return (int)i; | |
351 } | |
352 } | |
353 | |
354 // 空きがなければ追加 | |
355 char str[24]; | |
356 sprintf(str, "#%d", size); | |
357 const CValueTag *tag = AddValue(str); | |
358 temp_value.push_back(CTempValue(1, tag->addr_)); | |
359 | |
360 return (int)size; | |
361 } | |
362 | |
363 // 一時変数使用 | |
364 void compiler::UseTempValue(int value) | |
365 { | |
366 temp_value[value].ref_++; | |
367 } | |
368 | |
369 // 一時変数返却 | |
370 void compiler::ReleaseTempValue(int value) | |
371 { | |
372 temp_value[value].ref_--; | |
373 } | |
374 | |
375 // 単項マイナスの生成 | |
376 CNodeValue compiler::MakeNeg(int ret, const CNodeValue &value) | |
377 { | |
378 CNodeValue v = CNodeValue::MakeTempValue(this, ret); | |
379 | |
380 if (value.type() == CNodeValue::CONST) | |
381 OpNegC(v.value(), value.value()); | |
382 else | |
383 OpNegV(v.value(), value.value()); | |
384 | |
385 return v; | |
386 } | |
387 | |
388 // RAND関数の生成 | |
389 CNodeValue compiler::MakeRand(int ret, const CNodeValue &value) | |
390 { | |
391 CNodeValue v = CNodeValue::MakeTempValue(this, ret); | |
392 | |
393 if (value.type() == CNodeValue::CONST) | |
394 OpRandC(v.value(), value.value()); | |
395 else | |
396 OpRandV(v.value(), value.value()); | |
397 | |
398 return v; | |
399 } | |
400 | |
401 // 代入の生成(定数) | |
402 CNodeValue compiler::MakeMoveC(int ret, int value) | |
403 { | |
404 CNodeValue v = CNodeValue::MakeTempValue(this, ret); | |
405 | |
406 OpMovC(v.value(), value); | |
407 | |
408 return v; | |
409 } | |
410 | |
411 // 代入の生成(変数) | |
412 CNodeValue compiler::MakeMoveV(int ret, const CNodeValue &value) | |
413 { | |
414 CNodeValue v = CNodeValue::MakeTempValue(this, ret); | |
415 | |
416 OpMovV(v.value(), value.value()); | |
417 | |
418 return v; | |
419 } | |
420 | |
421 // 二項演算子の生成 | |
422 CNodeValue compiler::MakeOp(int op, int ret, const CNodeValue &left, const CNodeValue &right) | |
423 { | |
424 CNodeValue v = CNodeValue::MakeTempValue(this, ret); | |
425 | |
426 int code = 0; | |
427 switch (op) { | |
428 case OP_EQ: code = VM_EQ_CC; break; | |
429 case OP_NE: code = VM_NE_CC; break; | |
430 case OP_GT: code = VM_GT_CC; break; | |
431 case OP_GE: code = VM_GE_CC; break; | |
432 case OP_LT: code = VM_LT_CC; break; | |
433 case OP_LE: code = VM_LE_CC; break; | |
434 case OP_MINUS: code = VM_SUB_CC; break; | |
435 case OP_PLUS: code = VM_ADD_CC; break; | |
436 case OP_TIMES: code = VM_MUL_CC; break; | |
437 case OP_DIVIDE: code = VM_DIV_CC; break; | |
438 case OP_MOD: code = VM_MOD_CC; break; | |
439 } | |
440 | |
441 if (left.type() != CNodeValue::CONST) | |
442 code++; | |
443 if (right.type() != CNodeValue::CONST) | |
444 code += 2; | |
445 | |
446 statement.push_back(CVMCode(code, v.value(), left.value(), right.value())); | |
447 return v; | |
448 } | |
449 | |
450 // 条件ジャンプの生成(真) | |
451 void compiler::MakeJmpC(int label, const CNodeValue &value) | |
452 { | |
453 OpJmpC(label, value.value()); | |
454 } | |
455 | |
456 // 条件ジャンプの生成(偽) | |
457 void compiler::MakeJmpNC(int label, const CNodeValue &value) | |
458 { | |
459 OpJmpNC(label, value.value()); | |
460 } | |
461 | |
462 // pushの生成 | |
463 void compiler::MakePush(const CNodeValue &value) | |
464 { | |
465 if (value.type() == CNodeValue::CONST) | |
466 PushConst(value.value()); | |
467 else | |
468 PushValue(value.value()); | |
469 } | |
470 | |
471 // デバッグダンプ | |
472 #ifdef _DEBUG | |
473 void compiler::debug_dump() | |
474 { | |
475 std::cout << "---variables---" << std::endl; | |
476 variables.dump(); | |
477 | |
478 static const char *op_name[] = { | |
479 #define VM_NAMETABLE | |
480 #include "vm_code.h" | |
481 #undef VM_NAMETABLE | |
482 "LABEL", | |
483 } ; | |
484 std::cout << "---code---" << std::endl; | |
485 | |
486 int pos = 0; | |
487 size_t size = statement.size(); | |
488 for (size_t i=0; i < size; i++) { | |
489 std::cout << std::setw(6) << pos << ": " << op_name[statement[i].op_]; | |
490 if (statement[i].size_ > 1) { | |
491 std::cout << ", " << statement[i].arg1_; | |
492 if (statement[i].size_ > 5) { | |
493 std::cout << ", " << statement[i].arg2_; | |
494 if (statement[i].size_ > 9) { | |
495 std::cout << ", " << statement[i].arg3_; | |
496 } | |
497 } | |
498 } | |
499 std::cout << std::endl; | |
500 | |
501 if (statement[i].op_ != VM_MAXCOMMAND) { | |
502 pos += statement[i].size_; | |
503 } | |
504 } | |
505 std::cout << "---" << std::endl; | |
506 } | |
507 #endif |