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