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