4
|
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
|