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