N88BASICが簡単に動くインタープリタを目指します。
@@ -0,0 +1,687 @@ | ||
1 | +// | |
2 | +// compile.cpp | |
3 | +// | |
4 | +#include <vector> | |
5 | +#include "trifle.h" | |
6 | + | |
7 | +using namespace std; | |
8 | + | |
9 | +#define FirstAddr 2 // 各ブロックの最初の変数のアドレス | |
10 | + | |
11 | +Token NextToken; // 次のトークン | |
12 | +int CurNameIndex = 0; // 名前表の現在のインデックス | |
13 | +int CurFuncIndex; // 名前表の現在の関数のインデックス | |
14 | +int Level = -1; // 現在のブロックレベル | |
15 | +int LastIndex[MAX_LEVEL]; // LastIndex[i]はブロックレベルiの最後のインデックス | |
16 | +int LastVarAddr[MAX_LEVEL]; // LastVarAddr[i]はブロックレベルiの最後の変数のアドレス | |
17 | +int LasrVarAddr; // 現在のブロックの最後の変数のアドレス | |
18 | + | |
19 | +vector <NameItem> NameTable(MAX_TABLE_ENTRY); // 名前表 | |
20 | + | |
21 | +// プロトタイプ宣言 | |
22 | +void compileBlock(int indx); | |
23 | +void expression(); | |
24 | + | |
25 | +/* | |
26 | + * 新しいブロックの初期化 | |
27 | + * firstAddr:最初の変数のアドレス | |
28 | + */ | |
29 | +void initBlock(int firstAddr) | |
30 | +{ | |
31 | + if (Level == -1) // 主ブロックの場合 | |
32 | + { | |
33 | + LasrVarAddr = firstAddr; // 初期設定を行う | |
34 | + CurNameIndex = 0; | |
35 | + Level += 1; // レベルをインクリメントする | |
36 | + return; | |
37 | + } | |
38 | + if (Level == MAX_LEVEL-1) | |
39 | + errorMsgExit("ブロックのネストが深すぎます。"); | |
40 | + LastIndex[Level] = CurNameIndex; // これまでのブロックの情報を保存する | |
41 | + LastVarAddr[Level] = LasrVarAddr; | |
42 | + LasrVarAddr = firstAddr; // このブロックの最初の変数のアドレス | |
43 | + Level +=1 ; // レベルをインクリメントする | |
44 | + return; | |
45 | +} | |
46 | + | |
47 | +/* | |
48 | + * ブロックの終り | |
49 | + */ | |
50 | +void finBlock() | |
51 | +{ | |
52 | + Level--; // ブロックのレベルをデクリメントする | |
53 | + CurNameIndex = LastIndex[Level]; // 外側のブロックの情報を復帰する | |
54 | + LasrVarAddr = LastVarAddr[Level]; | |
55 | +} | |
56 | + | |
57 | +/* | |
58 | + * 現在のブロックのレベルを返す | |
59 | + */ | |
60 | +int getCurLevel() | |
61 | +{ | |
62 | + return Level; | |
63 | +} | |
64 | + | |
65 | +/* | |
66 | + * 現在のブロックの関数の仮引数数を返す | |
67 | + */ | |
68 | +int getFuncParams() | |
69 | +{ | |
70 | + if (Level<1) | |
71 | + return 0; | |
72 | + return NameTable[ LastIndex[Level-1] ].val.params; | |
73 | +} | |
74 | + | |
75 | +/* | |
76 | + * 名前表にプログラム名と先頭アドレスを登録する | |
77 | + */ | |
78 | +int regProgName(string id, int v) | |
79 | +{ | |
80 | + if (CurNameIndex++ < MAX_TABLE_ENTRY){ | |
81 | + NameTable[CurNameIndex].name = id; | |
82 | + } else { | |
83 | + errorMsgExit("名前が多すぎます。"); | |
84 | + } | |
85 | + NameTable[CurNameIndex].val.type = progId; | |
86 | + NameTable[CurNameIndex].val.param1 = Level; | |
87 | + NameTable[CurNameIndex].val.param2 = v; // 先頭アドレス | |
88 | + return CurNameIndex; | |
89 | +} | |
90 | + | |
91 | +/* | |
92 | + * 名前表に関数名と先頭アドレスを登録する | |
93 | + */ | |
94 | +int regFuncName(string id, int v) | |
95 | +{ | |
96 | + if (CurNameIndex++ < MAX_TABLE_ENTRY){ | |
97 | + NameTable[CurNameIndex].name = id; | |
98 | + } else { | |
99 | + errorMsgExit("名前が多すぎます。"); | |
100 | + } | |
101 | + NameTable[CurNameIndex].val.type = funcId; | |
102 | + NameTable[CurNameIndex].val.param1 = Level; | |
103 | + NameTable[CurNameIndex].val.param2 = v; // 関数の先頭アドレス | |
104 | + NameTable[CurNameIndex].val.params = 0; // 仮引数数 | |
105 | + CurFuncIndex = CurNameIndex; | |
106 | + return CurNameIndex; | |
107 | +} | |
108 | + | |
109 | +/* | |
110 | + * 名前表に仮引数名を登録する | |
111 | + */ | |
112 | +int regFuncParam(string id) | |
113 | +{ | |
114 | + if (CurNameIndex++ < MAX_TABLE_ENTRY){ | |
115 | + NameTable[CurNameIndex].name = id; | |
116 | + } else { | |
117 | + errorMsgExit("名前が多すぎます。"); | |
118 | + } | |
119 | + NameTable[CurNameIndex].val.type = parId; | |
120 | + NameTable[CurNameIndex].val.param1 = Level; | |
121 | + NameTable[CurFuncIndex].val.params++; // 引数の数をインクリメント | |
122 | + return CurNameIndex; | |
123 | +} | |
124 | + | |
125 | +/* | |
126 | + * 名前表に変数名を登録する | |
127 | + * アドレスは自動的に決まる | |
128 | + */ | |
129 | +int regVarName(string id) | |
130 | +{ | |
131 | + if (CurNameIndex++ < MAX_TABLE_ENTRY){ | |
132 | + NameTable[CurNameIndex].name = id; | |
133 | + } else { | |
134 | + errorMsgExit("名前が多すぎます。"); | |
135 | + } | |
136 | + NameTable[CurNameIndex].val.type = varId; | |
137 | + NameTable[CurNameIndex].val.param1 = Level; | |
138 | + NameTable[CurNameIndex].val.param2 = LasrVarAddr++; | |
139 | + return CurNameIndex; | |
140 | +} | |
141 | + | |
142 | +/* | |
143 | + * 名前表に定数名とその値を登録する | |
144 | + */ | |
145 | +int regConst(string id, int v) | |
146 | +{ | |
147 | + if (CurNameIndex++ < MAX_TABLE_ENTRY){ | |
148 | + NameTable[CurNameIndex].name = id; | |
149 | + } else { | |
150 | + errorMsgExit("名前が多すぎます。"); | |
151 | + } | |
152 | + NameTable[CurNameIndex].val.type = constId; | |
153 | + NameTable[CurNameIndex].val.param1 = v; | |
154 | + return CurNameIndex; | |
155 | +} | |
156 | + | |
157 | +/* | |
158 | + * 仮引数の宣言部の最後を処理する | |
159 | + */ | |
160 | +void finParamDecl() | |
161 | +{ | |
162 | + int prs = NameTable[CurFuncIndex].val.params; | |
163 | + if (prs == 0) return; | |
164 | + for (int i=1; i<=prs; i++) // 各仮引数のアドレス | |
165 | + NameTable[CurFuncIndex+i].val.param2 = i-1-prs; | |
166 | +} | |
167 | + | |
168 | +/* | |
169 | + * 名前表のインデックスがindxの関数のアドレスを変更する | |
170 | + */ | |
171 | +void changeV(int indx, int newVal) | |
172 | +{ | |
173 | + NameTable[indx].val.param2 = newVal; | |
174 | +} | |
175 | + | |
176 | +/* | |
177 | + * 指定した名前の位置を名前表から探す | |
178 | + */ | |
179 | +int searchId(string id, TypeOfID k) | |
180 | +{ | |
181 | + int i = CurNameIndex; | |
182 | + NameTable[0].name = id; | |
183 | + while( id.compare(string( NameTable[i].name)) ) | |
184 | + i--; | |
185 | + if ( i ) // 名前を検出 | |
186 | + return i; | |
187 | + else { // 名前がなかった->エラー | |
188 | + string msg = "名前" + id + "が未定義です。"; | |
189 | + compileError(msg); | |
190 | + if (k == varId) | |
191 | + return regVarName(id); // 名前が変数なら登録して続行を試みる | |
192 | + return 0; | |
193 | + } | |
194 | +} | |
195 | + | |
196 | +/* | |
197 | + * 名前表のインデックスがindxの種類を返す | |
198 | + */ | |
199 | +TypeOfID getIDType(int indx) | |
200 | +{ | |
201 | + return NameTable[indx].val.type; | |
202 | +} | |
203 | + | |
204 | +/* | |
205 | + * 名前表のインデックスがindxのアドレスを返す | |
206 | + */ | |
207 | +int getAddress(int indx) | |
208 | +{ | |
209 | + return NameTable[indx].val.param2; | |
210 | +} | |
211 | + | |
212 | +/* | |
213 | + * 名前表のインデックスがindxのレベルを返す | |
214 | + */ | |
215 | +int getLevel(int indx) | |
216 | +{ | |
217 | + return NameTable[indx].val.param1; | |
218 | +} | |
219 | + | |
220 | +/* | |
221 | + * 名前表のインデックスがindxの値を返す | |
222 | + */ | |
223 | +int getVal(int indx) | |
224 | +{ | |
225 | + return NameTable[indx].val.param1; | |
226 | +} | |
227 | + | |
228 | +/* | |
229 | + * 名前表のインデックスがindxの関数の仮引数の数を返す | |
230 | + */ | |
231 | +int getNumOfParams(int indx) | |
232 | +{ | |
233 | + return NameTable[indx].val.params; | |
234 | +} | |
235 | + | |
236 | +/* | |
237 | + * ブロックの変数の最大アドレスを返す | |
238 | + */ | |
239 | +int getLastVarAddr() | |
240 | +{ | |
241 | + return LasrVarAddr; | |
242 | +} | |
243 | + | |
244 | +/* | |
245 | + * プログラムをコンパイルする | |
246 | + */ | |
247 | +bool compile() | |
248 | +{ | |
249 | + cout << "コンパイル中..." << endl; | |
250 | + init(); // 初期化 | |
251 | + NextToken = nextToken(); // 最初のトークンを返す | |
252 | + initBlock(FirstAddr); // 最初のブロック | |
253 | + compileBlock(0); // 主ブロック | |
254 | + | |
255 | + if (fGenerateList) | |
256 | + listCode(); // 生成されたコードのリストをコンソールに出力する | |
257 | + outputObjectCode(); // 生成されたコードをファイルに出力する | |
258 | + | |
259 | + if (getNumberOfErrors() != 0){ | |
260 | + cout << "コンパイルエラー:" << getNumberOfErrors() << endl; | |
261 | + return false; | |
262 | + } | |
263 | + return true; | |
264 | +} | |
265 | + | |
266 | +/* | |
267 | + * 定数宣言をコンパイルする | |
268 | + */ | |
269 | +void compileConstDecl() | |
270 | +{ | |
271 | + Token temp; | |
272 | + while(1){ | |
273 | + if (NextToken.type == Id){ // トークンはIDのはず | |
274 | + temp = NextToken; | |
275 | + NextToken = checkAndgetToken(nextToken(), Equal); // 名前の次は「=」のはず | |
276 | + if (NextToken.type == Num) | |
277 | + regConst(temp.name, NextToken.value); | |
278 | + else | |
279 | + compileError("数値でなければなりません。"); | |
280 | + NextToken = nextToken(); | |
281 | + }else | |
282 | + compileError("名前がありません。"); | |
283 | + if (NextToken.type != Comma){ | |
284 | + if (NextToken.type == Id){ | |
285 | + // 次が名前ならコンマを忘れた可能性がある | |
286 | + compileError(",がありません。"); | |
287 | + continue; | |
288 | + }else | |
289 | + break; | |
290 | + } | |
291 | + NextToken = nextToken(); | |
292 | + } | |
293 | + NextToken = checkAndgetToken(NextToken, Semicolon); // 最後は「;」のはず | |
294 | +} | |
295 | + | |
296 | +/* | |
297 | + * 変数宣言をコンパイルする | |
298 | + */ | |
299 | +void compileVarDecl() | |
300 | +{ | |
301 | + int count = 0; | |
302 | + while(1){ | |
303 | + if (++count > MAX_LOOP){ | |
304 | + errorMessage(CurLineNo, "シンタックスエラー"); | |
305 | + return; | |
306 | + } | |
307 | + if (NextToken.type == Id){ | |
308 | + regVarName(NextToken.name); | |
309 | + NextToken = nextToken(); | |
310 | + }else | |
311 | + compileError("名前がありません。"); | |
312 | + if (NextToken.type != Comma){ | |
313 | + if (NextToken.type == Id){ | |
314 | + compileError( ",がありません。"); | |
315 | + continue; | |
316 | + }else | |
317 | + break; | |
318 | + } | |
319 | + NextToken = nextToken(); | |
320 | + } | |
321 | + NextToken = checkAndgetToken(NextToken, Semicolon); // 最後は「;」のはず | |
322 | +} | |
323 | + | |
324 | +/* | |
325 | + * 関数宣言をコンパイルする | |
326 | + */ | |
327 | +void compileFuncDecl() | |
328 | +{ | |
329 | + int fIndex; | |
330 | + if (NextToken.type == Id){ | |
331 | + fIndex = regFuncName(NextToken.name, getNextCodeAddrs()); | |
332 | + NextToken = checkAndgetToken(nextToken(), Lparen); | |
333 | + initBlock(FirstAddr); | |
334 | + while(1){ | |
335 | + if (NextToken.type == Id){ // 仮引数 | |
336 | + regFuncParam(NextToken.name); | |
337 | + NextToken = nextToken(); | |
338 | + }else | |
339 | + break; | |
340 | + if (NextToken.type != Comma){ | |
341 | + if (NextToken.type == Id){ | |
342 | + compileError(",がありません。"); | |
343 | + continue; | |
344 | + }else | |
345 | + break; | |
346 | + } | |
347 | + NextToken = nextToken(); | |
348 | + } | |
349 | + NextToken = checkAndgetToken(NextToken, Rparen); // 最後は「)」のはず | |
350 | + finParamDecl(); // 仮引数部が終わった | |
351 | + if (NextToken.type == Semicolon){ | |
352 | + compileError("シンタックスエラーです。トークンを削除します。"); | |
353 | + NextToken = nextToken(); | |
354 | + } | |
355 | + compileBlock(fIndex); // ブロックのコンパイル | |
356 | + NextToken = checkAndgetToken(NextToken, Semicolon); // 最後は「;」のはず | |
357 | + } else | |
358 | + compileError("名前がありません。"); // おそらく関数名がないというエラー | |
359 | +} | |
360 | + | |
361 | +/* | |
362 | + * プログラム文をコンパイルする | |
363 | + */ | |
364 | +void compileProgDecl() | |
365 | +{ | |
366 | + int fIndex; | |
367 | + if (NextToken.type == Id){ | |
368 | + fIndex = regProgName(NextToken.name, getNextCodeAddrs()); | |
369 | + NextToken = nextToken(); | |
370 | + compileBlock(0); // programブロックのコンパイル | |
371 | + } else | |
372 | + compileError("名前がありません。"); // おそらくprogram名がないというエラー | |
373 | +} | |
374 | + | |
375 | +/* | |
376 | + * トークンtが文の先頭のキーであればtrueを返す | |
377 | + */ | |
378 | +static bool isStBeginKey(Token t) | |
379 | +{ | |
380 | + switch (t.type){ | |
381 | + case If: | |
382 | + case LBrace: | |
383 | + case Call: | |
384 | + case Ret: | |
385 | + case While: | |
386 | + case Write: | |
387 | + case WriteLn: | |
388 | + case WriteSp: | |
389 | + return true; | |
390 | + default: | |
391 | + return false; | |
392 | + } | |
393 | +} | |
394 | + | |
395 | +/* | |
396 | + * 式の因子をコンパイルする | |
397 | + */ | |
398 | +void factor() | |
399 | +{ | |
400 | + int indx, i; | |
401 | + TypeOfID kk; | |
402 | + if (NextToken.type == Id){ | |
403 | + indx = searchId(NextToken.name, varId); | |
404 | + kk = getIDType(indx); | |
405 | + switch (kk) { | |
406 | + case varId: | |
407 | + case parId: | |
408 | + genObjCode(load, indx); | |
409 | + NextToken = nextToken(); | |
410 | + break; | |
411 | + case constId: | |
412 | + genObjCode(literl, getVal(indx)); | |
413 | + NextToken = nextToken(); | |
414 | + break; | |
415 | + case funcId: // 関数呼び出し | |
416 | + NextToken = nextToken(); | |
417 | + if (NextToken.type == Lparen){ | |
418 | + i=0; // 実引数の個数 | |
419 | + NextToken = nextToken(); | |
420 | + if (NextToken.type != Rparen) { | |
421 | + while ( true ) { // 実引数のコンパイル | |
422 | + expression(); | |
423 | + i++; | |
424 | + if (NextToken.type == Comma){ // 次がコンマなら実引数が続く | |
425 | + NextToken = nextToken(); | |
426 | + continue; | |
427 | + } | |
428 | + NextToken = checkAndgetToken(NextToken, Rparen); | |
429 | + break; | |
430 | + } | |
431 | + } else | |
432 | + NextToken = nextToken(); | |
433 | + if (getNumOfParams(indx) != i) | |
434 | + errorMessage("仮引数と実引数の数が異なります。"); | |
435 | + }else{ | |
436 | + compileError("{ / }がありません。"); | |
437 | + } | |
438 | + genObjCode(call, indx); // call命令を生成する | |
439 | + break; | |
440 | + } | |
441 | + }else if (NextToken.type == Num){ // 定数 | |
442 | + genObjCode(literl, NextToken.value); | |
443 | + NextToken = nextToken(); | |
444 | + }else if (NextToken.type == Lparen){ // 「(」「因子」「)」 | |
445 | + NextToken = nextToken(); | |
446 | + expression(); | |
447 | + NextToken = checkAndgetToken(NextToken, Rparen); | |
448 | + } | |
449 | + | |
450 | + switch (NextToken.type){ | |
451 | + case Id: | |
452 | + case Num: | |
453 | + case Lparen: | |
454 | + compileError("演算子がありません。"); // 因子の後がまた因子ならエラー | |
455 | + factor(); | |
456 | + default: | |
457 | + return; | |
458 | + } | |
459 | +} | |
460 | + | |
461 | +/* | |
462 | + * 式の項をコンパイルする | |
463 | + */ | |
464 | +void term() | |
465 | +{ | |
466 | + factor(); | |
467 | + TokType id = NextToken.type; | |
468 | + while (id == Mult || id == Div){ | |
469 | + NextToken = nextToken(); | |
470 | + factor(); | |
471 | + if (id == Mult) | |
472 | + genObjCode(mul); | |
473 | + else | |
474 | + genObjCode(divide); | |
475 | + id = NextToken.type; | |
476 | + } | |
477 | +} | |
478 | + | |
479 | +/* | |
480 | + * 式をコンパイルする | |
481 | + */ | |
482 | +void expression() | |
483 | +{ | |
484 | + TokType id = NextToken.type; | |
485 | + if (id == Plus || id == Minus){ | |
486 | + NextToken = nextToken(); | |
487 | + term(); // 式の項のコンパイル | |
488 | + if (id == Minus) | |
489 | + genObjCode(neg); | |
490 | + }else | |
491 | + term(); | |
492 | + | |
493 | + id = NextToken.type; | |
494 | + while (id == Plus || id == Minus){ | |
495 | + NextToken = nextToken(); | |
496 | + term(); // 式の項のコンパイル | |
497 | + if (id == Minus) | |
498 | + genObjCode(sub); | |
499 | + else | |
500 | + genObjCode(add); | |
501 | + id = NextToken.type; | |
502 | + } | |
503 | +} | |
504 | + | |
505 | +/* | |
506 | + * 条件式をコンパイルする | |
507 | + */ | |
508 | +void condition() | |
509 | +{ | |
510 | + expression(); | |
511 | + TokType id = NextToken.type; | |
512 | + switch(id){ | |
513 | + case Equal: | |
514 | + case Lss: | |
515 | + case Gtr: | |
516 | + case NotEq: | |
517 | + case LssEq: | |
518 | + case GtrEq: | |
519 | + break; | |
520 | + default: | |
521 | + compileError("条件式が不正です。"); | |
522 | + break; | |
523 | + } | |
524 | + NextToken = nextToken(); | |
525 | + expression(); | |
526 | + switch(id){ | |
527 | + case Equal: | |
528 | + genObjCode(equals); | |
529 | + break; | |
530 | + case Lss: | |
531 | + genObjCode(ls); | |
532 | + break; | |
533 | + case Gtr: | |
534 | + genObjCode(gr); | |
535 | + break; | |
536 | + case NotEq: | |
537 | + genObjCode(neq); | |
538 | + break; | |
539 | + case LssEq: | |
540 | + genObjCode(lseq); | |
541 | + break; | |
542 | + case GtrEq: | |
543 | + genObjCode(greq); | |
544 | + break; | |
545 | + } | |
546 | +} | |
547 | + | |
548 | +/* | |
549 | + * ステートメント(文)をコンパイルする | |
550 | + */ | |
551 | +void statement() | |
552 | +{ | |
553 | + int indx; | |
554 | + TypeOfID k; | |
555 | + int patchAddrss, patchAddrss1; | |
556 | + | |
557 | + while(1) { | |
558 | + switch (NextToken.type) { | |
559 | + case Id: // 代入文のコンパイル | |
560 | + indx = searchId(NextToken.name, varId); // 左辺の変数のインデックス | |
561 | + k = getIDType(indx); | |
562 | + if (k != varId && k != parId) | |
563 | + compileError("変数名か仮引数名が間違っています。"); | |
564 | + NextToken = checkAndgetToken(nextToken(), Assign); // 「:=」のはず | |
565 | + expression(); | |
566 | + genObjCode(store, indx); // 代入命令 | |
567 | + return; | |
568 | + case If: // if文のコンパイル | |
569 | + NextToken = nextToken(); | |
570 | + condition(); // 条件式のコンパイル | |
571 | + NextToken = checkAndgetToken(NextToken, Then); // 「then」のはず | |
572 | + patchAddrss = genObjCode(jpc, 0); | |
573 | + statement(); // 文のコンパイル | |
574 | + backPatch(patchAddrss); // 上のjpc命令にバックパッチ | |
575 | + return; | |
576 | + case Ret: // return文のコンパイル | |
577 | + NextToken = nextToken(); | |
578 | + expression(); | |
579 | + genRetCode(); | |
580 | + return; | |
581 | + case LBrace: // { . . }ブロックのコンパイル | |
582 | + NextToken = nextToken(); | |
583 | + while(1){ | |
584 | + statement(); | |
585 | + while(1){ | |
586 | + if (NextToken.type == Semicolon){ // 次のトークンが「;」であれば | |
587 | + NextToken = nextToken(); // 文が続く | |
588 | + break; | |
589 | + } | |
590 | + if (NextToken.type == RBrace){ // 次のトークンが「}」であれば | |
591 | + NextToken = nextToken(); // {}ブロックは終わり | |
592 | + return; | |
593 | + } | |
594 | + if (isStBeginKey(NextToken)){ // 次が文の先頭記号なら | |
595 | + compileError(";がありません。"); //「;」を忘れた可能性が高い | |
596 | + break; | |
597 | + } | |
598 | + compileError("シンタックスエラーです。トークンを削除します。"); | |
599 | + NextToken = nextToken(); | |
600 | + } | |
601 | + } | |
602 | + case While: | |
603 | + NextToken = nextToken(); | |
604 | + patchAddrss1 = getNextCodeAddrs(); // whileの先頭 | |
605 | + condition(); // 条件式 | |
606 | + NextToken = checkAndgetToken(NextToken, Do); // 「while」の後の | |
607 | + // トークンは「do」 | |
608 | + patchAddrss = genObjCode(jpc, 0); // 条件式がfalseのとき | |
609 | + // ループを終了するためのjpc命令 | |
610 | + statement(); | |
611 | + genObjCode(jmp, patchAddrss1); // while文の先頭へのジャンプ命令 | |
612 | + backPatch(patchAddrss); // 条件式がfalseのときループを | |
613 | + // 終了するためのバックパッチ | |
614 | + return; | |
615 | + case Call: | |
616 | + NextToken = nextToken(); | |
617 | + expression(); | |
618 | + return; | |
619 | + case Write: | |
620 | + NextToken = nextToken(); | |
621 | + expression(); | |
622 | + genObjCode(wrt); | |
623 | + return; | |
624 | + case WriteLn: | |
625 | + NextToken = nextToken(); | |
626 | + genObjCode(wrtln); | |
627 | + return; | |
628 | + case WriteSp: | |
629 | + NextToken = nextToken(); | |
630 | + genObjCode(wrtsp); | |
631 | + return; | |
632 | + case RBrace: // ブロックの終わり | |
633 | + case Semicolon: | |
634 | + return; | |
635 | + default: | |
636 | + compileError("シンタックスエラーです。トークンを削除します。"); | |
637 | + NextToken = nextToken(); | |
638 | + continue; | |
639 | + } | |
640 | + } | |
641 | +} | |
642 | + | |
643 | + | |
644 | +/* | |
645 | + * ブロックをコンパイルする | |
646 | + * | |
647 | + * indx:このブロックの関数名のインデックス | |
648 | + */ | |
649 | +void compileBlock(int indx) | |
650 | +{ | |
651 | + int patchAddrss = genObjCode(jmp, 0); | |
652 | + // 宣言部のコンパイル | |
653 | + while (1) { | |
654 | + switch (NextToken.type){ | |
655 | + case Const: // 定数宣言 | |
656 | + NextToken = nextToken(); | |
657 | + compileConstDecl(); | |
658 | + continue; | |
659 | + case Integer: // 変数宣言 | |
660 | + NextToken = nextToken(); | |
661 | + compileVarDecl(); | |
662 | + continue; | |
663 | + case Func: // 関数宣言 | |
664 | + NextToken = nextToken(); | |
665 | + compileFuncDecl(); | |
666 | + continue; | |
667 | + case Prog: // プログラム文 | |
668 | + backPatch(0); | |
669 | + NextToken = nextToken(); | |
670 | + compileProgDecl(); | |
671 | + return; | |
672 | + default: // それ以外なら宣言終わり | |
673 | + break; | |
674 | + } | |
675 | + break; | |
676 | + } | |
677 | + backPatch(patchAddrss); | |
678 | + | |
679 | + changeV(indx, getNextCodeAddrs()); | |
680 | + genObjCode(incmnt, getLastVarAddr()); | |
681 | + statement(); | |
682 | + genRetCode(); | |
683 | + | |
684 | + finBlock(); | |
685 | +} | |
686 | + | |
687 | +// E.O.F. |
@@ -0,0 +1,55 @@ | ||
1 | +/* | |
2 | + * compile.h | |
3 | + */ | |
4 | + | |
5 | +#ifndef COMPILE_H | |
6 | +#define COMPILE_H 1 | |
7 | + | |
8 | +#include <iostream> | |
9 | +#include <string> | |
10 | + | |
11 | +#define MAX_TABLE_ENTRY 100 // 名前表に保存できる名前の数 | |
12 | +#define MAX_LEVEL 5 // ブロックの最大深さ | |
13 | + | |
14 | +typedef enum IDTypes { // IDの種類 | |
15 | + varId, funcId, progId, parId, constId, IDNull | |
16 | +} TypeOfID; | |
17 | + | |
18 | +class NameValues { // 名前表のエントリーの内容を表すクラス | |
19 | +public: | |
20 | + TypeOfID type; // 名前の種類 | |
21 | + int value; // 定数の場合:値 | |
22 | + int param2; | |
23 | + int param1; | |
24 | + int params; // 関数の場合:仮引数数 | |
25 | +}; | |
26 | + | |
27 | +class NameItem { // 名前表のエントリーのクラス | |
28 | +public: | |
29 | + string name; // 名前 | |
30 | + NameValues val; // 名前に対応する値 | |
31 | +}; | |
32 | + | |
33 | + | |
34 | +// プロトタイプ宣言 | |
35 | +void initBlock(int firstAddr); | |
36 | +void finBlock(); | |
37 | +int getCurLevel(); | |
38 | +int getFuncParams(); | |
39 | +int regProgName(string id, int v); | |
40 | +int regFuncName(string id, int v); | |
41 | +int regVarName(string id); | |
42 | +int regFuncParam(string id); | |
43 | +int regConst(string id, int v); | |
44 | +void finParamDecl(); | |
45 | +void changeV(int ti, int newVal); | |
46 | +int searchId(string id, TypeOfID k); | |
47 | +TypeOfID getIDType(int i); | |
48 | +int getAddress(int ti); | |
49 | +int getLevel(int ti); | |
50 | +int getVal(int ti); | |
51 | +int getNumOfParams(int ti); | |
52 | +int getLastVarAddr(); | |
53 | +bool compile(); | |
54 | + | |
55 | +#endif |
@@ -0,0 +1,146 @@ | ||
1 | + | |
2 | +// | |
3 | +// gencode.cpp | |
4 | +// | |
5 | +#include "trifle.h" | |
6 | +#include <vector> | |
7 | + | |
8 | +string ObjFileName; | |
9 | + | |
10 | +vector <Instruction> Codes; // オブジェクトコードを保存するベクタ | |
11 | + | |
12 | +// プロトタイプ宣言 | |
13 | +static void newCode(); | |
14 | + | |
15 | +int getNextCodeAddrs() | |
16 | +{ | |
17 | + return Codes.size(); | |
18 | +} | |
19 | + | |
20 | +/* | |
21 | + * パラメータなしの命令 | |
22 | + * (Writexx、演算命令) | |
23 | + */ | |
24 | +int genObjCode(OpCode op) | |
25 | +{ | |
26 | + Instruction inst = Instruction(op); | |
27 | + Codes.push_back( inst ); | |
28 | + return Codes.size() - 1; | |
29 | +} | |
30 | + | |
31 | +/* | |
32 | + * パラメータ1,2個の命令 | |
33 | + */ | |
34 | +int genObjCode(OpCode op, int v) | |
35 | +{ | |
36 | + Instruction inst;// = Instruction(op); | |
37 | + if (op == load || op == call || op == store) { | |
38 | + inst = Instruction(op, getLevel(v), getAddress(v)); | |
39 | + } else { | |
40 | + inst = Instruction(op, v); | |
41 | + } | |
42 | + Codes.push_back( inst ); | |
43 | + return Codes.size() - 1; | |
44 | +} | |
45 | + | |
46 | +/* | |
47 | + * ret命令 | |
48 | + */ | |
49 | +int genRetCode() | |
50 | +{ | |
51 | + // 直前の命令が同じret命令なら、命令を生成しない | |
52 | + if (Codes[Codes.size() - 1].opCode == ret) | |
53 | + return Codes.size() - 1; | |
54 | + | |
55 | + Instruction inst = Instruction( ret, getCurLevel(), getFuncParams() ); | |
56 | + Codes.push_back( inst ); | |
57 | + return Codes.size() - 1; | |
58 | +} | |
59 | + | |
60 | + | |
61 | +/* | |
62 | + * 命令語をバックパッチする | |
63 | + */ | |
64 | +void backPatch(int indx) | |
65 | +{ | |
66 | + // 次のアドレスをi番目の命令に設定する | |
67 | + Codes[indx].param1 = Codes.size(); | |
68 | +} | |
69 | + | |
70 | + | |
71 | +/* | |
72 | + * 命令コードのリストを出力する | |
73 | + */ | |
74 | +void listCode() | |
75 | +{ | |
76 | + cout << "生成されたコード" << endl; | |
77 | + int n = (int)Codes.size(); | |
78 | + for(int i=0; i< n; i++){ | |
79 | + cout << setw(3) << i; | |
80 | + cout << ": "; | |
81 | + printCode(Codes[i]); | |
82 | + } | |
83 | +} | |
84 | + | |
85 | +/* | |
86 | + * 命令コードを出力する | |
87 | + */ | |
88 | +void outputCode(ofstream &fout, Instruction instrct) | |
89 | +{ | |
90 | + int flag; | |
91 | + // 命令コードを出力する | |
92 | + fout << (char)( instrct.opCode & 0xff); | |
93 | + // パラメータ数を決定する | |
94 | + switch(instrct.opCode){ | |
95 | + case ret: | |
96 | + case load: | |
97 | + case call: | |
98 | + case store: | |
99 | + flag=2; | |
100 | + break; | |
101 | + case literl: | |
102 | + case incmnt: | |
103 | + case jmp: | |
104 | + case jpc: | |
105 | + flag=1; | |
106 | + break; | |
107 | + default: | |
108 | + flag=0; | |
109 | + break; | |
110 | + } | |
111 | + // パラメータを出力する | |
112 | + switch(flag){ | |
113 | + case 1: | |
114 | + fout << setw(8) << instrct.param1; | |
115 | + break; | |
116 | + case 2: | |
117 | + fout << (char)(instrct.param1 & 0xff); | |
118 | + fout << (char)(instrct.param2 & 0xff) ; | |
119 | + break; | |
120 | + } | |
121 | +} | |
122 | + | |
123 | + | |
124 | +/* | |
125 | + * オブジェクトコードをファイルに出力する | |
126 | + */ | |
127 | +int outputObjectCode() | |
128 | +{ | |
129 | + ObjFileName = SrcFileName.replace(SrcFileName.find(".tri"), 4, ".exf"); | |
130 | + cout << "コンパイル終了。出力ファイル=" << ObjFileName << endl; | |
131 | + char fname[MAX_PATH_LEN]; | |
132 | + strcpy(fname, ObjFileName.c_str()); | |
133 | + // 出力ファイルを開く。 | |
134 | + ofstream fout( (const char *)fname , ios::out | ios::binary ); | |
135 | + if (! (fout.good()) ) | |
136 | + return errorMessage(ObjFileName + "を開けません。"); | |
137 | + int n = (int)Codes.size(); | |
138 | + for(int i=0; i<n; i++){ | |
139 | + outputCode(fout, Codes[i]); | |
140 | + } | |
141 | + fout.close(); | |
142 | + return 0; | |
143 | +} | |
144 | + | |
145 | +// E.O.F | |
146 | + |
@@ -0,0 +1,45 @@ | ||
1 | +/* | |
2 | + * gencode.h | |
3 | + */ | |
4 | +#ifndef GODEGEN_H | |
5 | +#define GODEGEN_H 1 | |
6 | + | |
7 | +#include <fstream> | |
8 | + | |
9 | +using namespace std; | |
10 | + | |
11 | +#define MAX_LEVEL 5 // ブロックの最大深さ | |
12 | +#define MAX_LOOP 20 // 無限ループ(何らかのエラー)とみなす繰り返し回数 | |
13 | + | |
14 | +typedef enum codes{ // 命令コード | |
15 | + literl, load, store, call, ret, incmnt, jmp, jpc, | |
16 | + neg, add, sub, mul, divide, // 演算命令 | |
17 | + equals, ls, gr, neq, lseq, greq, // 比較 | |
18 | + wrt, wrtln, wrtsp, // 出力 | |
19 | + nop, end, dummy // その他 | |
20 | +} OpCode; | |
21 | + | |
22 | +class Instruction{ // 命令のクラス | |
23 | +public: | |
24 | + OpCode opCode; | |
25 | + int param1; // 値、レベル、 | |
26 | + int param2; // アドレス | |
27 | + // コンストラクタ | |
28 | + Instruction(OpCode opcode = nop, int p1 = 0, int p2 = 0){ | |
29 | + opCode = opcode; | |
30 | + param1 = p1; | |
31 | + param2 = p2; | |
32 | + } | |
33 | +}; | |
34 | + | |
35 | +// プロトタイプ宣言 | |
36 | +int genObjCode(OpCode op, int v); | |
37 | +int genObjCode(OpCode op); | |
38 | +int genRetCode(); | |
39 | +void backPatch(int indx); | |
40 | +int getNextCodeAddrs(); | |
41 | +void listCode(); | |
42 | +int outputObjectCode(); | |
43 | + | |
44 | + | |
45 | +#endif |
@@ -0,0 +1,388 @@ | ||
1 | +// | |
2 | +// gettoken.cpp | |
3 | +// | |
4 | +#include "trifle.h" | |
5 | + | |
6 | +using namespace std; | |
7 | + | |
8 | +char LineBuffer[MAX_LINE_LEN]; // 入力バッファ | |
9 | +int CurLineNo; // 現在のソースコード行番号 | |
10 | +int LineIndex; // 次に読む文字の位置 | |
11 | +char Chr; // 最後に読み込んだ文字 | |
12 | + | |
13 | +Token CurToken; // 現在のトークン | |
14 | +Token PrevToken; // ひとつ前のトークン | |
15 | +TypeOfID IdType; // 現在のトークンの種類 | |
16 | + | |
17 | +int NumberOfErrors = 0; // 検出したエラーの数 | |
18 | +int isKeySym(TokType k); // トークンは記号か? | |
19 | +int isKeyWd(TokType k); // トークンは予約語か? | |
20 | + | |
21 | +struct keyWd { // 予約語や記号と名前(TokType) | |
22 | + string name; | |
23 | + TokType keyId; | |
24 | +}; | |
25 | + | |
26 | +static struct keyWd KeyWdT[] = { // キーワード | |
27 | + {"{", LBrace}, {"}", RBrace}, | |
28 | + {"if", If}, {"then", Then}, | |
29 | + {"while", While}, {"do", Do}, | |
30 | + {"call", Call},{"return", Ret}, | |
31 | + {"function", Func}, {"program", Prog}, | |
32 | + {"int", Integer}, {"const", Const}, | |
33 | + {"write", Write}, {"writeln",WriteLn}, {"writesp",WriteSp}, | |
34 | + {"$dummy1",end_of_KeyWd}, | |
35 | + // 記号 | |
36 | + {"+", Plus}, {"-", Minus}, {"*", Mult}, {"/", Div}, | |
37 | + {"(", Lparen}, {")", Rparen}, | |
38 | + {"=", Equal}, {"<", Lss}, {">", Gtr}, | |
39 | + {"<>", NotEq}, {"<=", LssEq}, {">=", GtrEq}, | |
40 | + {",", Comma}, {".", Period}, {";", Semicolon}, | |
41 | + {":=", Assign}, | |
42 | + {"$dummy2",end_of_KeySym} | |
43 | +}; | |
44 | + | |
45 | +string keyname[] = { // キーワードと記号 | |
46 | + "LBrace", "RBrace", // { , "} | |
47 | + "If", "Then", // 予約語 | |
48 | + "While", "Do", | |
49 | + "Call", "Return", "Function", "Program", | |
50 | + "int", "Const",// "Odd", | |
51 | + "Write", "WriteLn", "WriteSp", | |
52 | + "end_of_KeyWd", // ここまで予約語 | |
53 | + // 演算子と区切り記号の名前 | |
54 | + "Plus", "Minus", | |
55 | + "Mult", "Div", | |
56 | + "Lparen", "Rparen", | |
57 | + "Equal", "Lss", "Gtr", | |
58 | + "NotEq", "LssEq", "GtrEq", | |
59 | + "Comma", "Period", "Semicolon", | |
60 | + "Assign", | |
61 | + "end_of_KeySym", // ここまで演算子と区切り記号の名前 | |
62 | + "Id", "Num", "Nul", // トークンの種類 | |
63 | + "end_of_Token", | |
64 | + "Letter", "Digit", "Colon", "Others", // その他の文字の種類 | |
65 | + "EndOfFile" | |
66 | +} ; | |
67 | + | |
68 | +ifstream Fin; // 入力(ソース)ファイルストリーム | |
69 | + | |
70 | +/* | |
71 | + * 予約語ならtrueを返す | |
72 | + */ | |
73 | +int isKeyWd(TokType k) | |
74 | +{ | |
75 | + return (k < end_of_KeyWd); | |
76 | +} | |
77 | + | |
78 | +/* | |
79 | + * 記号ならtrueを返す | |
80 | + */ | |
81 | +int isKeySym(TokType k) | |
82 | +{ | |
83 | + if (k < end_of_KeyWd) | |
84 | + return 0; | |
85 | + return (k < end_of_KeySym); | |
86 | +} | |
87 | + | |
88 | +/* | |
89 | + * 文字の種類を返す | |
90 | + */ | |
91 | +static TokType getCharType(char chr) | |
92 | +{ | |
93 | + if (chr >='0' && chr<='9') | |
94 | + return Digit; | |
95 | + if ((chr >='A' && chr<='Z') || (chr >='a' && chr<='z')) | |
96 | + return Letter; | |
97 | + | |
98 | + switch (chr) { | |
99 | + case '{': return LBrace; | |
100 | + case '}': return RBrace; | |
101 | + case '+': return Plus; | |
102 | + case '-': return Minus; | |
103 | + case '*': return Mult; | |
104 | + case '/': return Div; | |
105 | + case '(': return Lparen; | |
106 | + case ')': return Rparen; | |
107 | + case '=': return Equal; | |
108 | + case '<': return Lss; | |
109 | + case '>': return Gtr; | |
110 | + case ',': return Comma; | |
111 | + case '.': return Period; | |
112 | + case ';': return Semicolon; | |
113 | + case ':': return Colon; | |
114 | + default: | |
115 | + break; | |
116 | + } | |
117 | + return Others; | |
118 | +} | |
119 | + | |
120 | +/* | |
121 | + * 初期設定を行う | |
122 | + */ | |
123 | +void init() | |
124 | +{ | |
125 | + LineIndex = -1; | |
126 | + Chr = 0; // NULL文字 | |
127 | + CurToken = Token(); | |
128 | + //if (fVerbose) // 詳細情報を出力したいときはコメント記号を削除する | |
129 | + // cout << "初期化開始" << endl; | |
130 | +} | |
131 | + | |
132 | +/* | |
133 | + * エラー数をカウントし、エラーが多すぎたら終了する | |
134 | + */ | |
135 | +void numberOfErrorsCheck() | |
136 | +{ | |
137 | + if (NumberOfErrors++ > MAX_ERROR) | |
138 | + errorMsgExit("エラーの数が多すぎます。コンパイルを中止します。"); | |
139 | +} | |
140 | + | |
141 | +void compileError(string msc) | |
142 | +{ | |
143 | + errorMessage(CurLineNo, msc); | |
144 | + numberOfErrorsCheck(); | |
145 | +} | |
146 | + | |
147 | +/* | |
148 | + * エラーの個数を返す | |
149 | + */ | |
150 | +int getNumberOfErrors() | |
151 | +{ | |
152 | + return NumberOfErrors; | |
153 | +} | |
154 | + | |
155 | +/* | |
156 | + * ソースファイルを開く | |
157 | + */ | |
158 | +int openSource(string fileName) | |
159 | +{ | |
160 | + Fin.open( fileName.c_str(), ios::in); | |
161 | + if (!Fin) { | |
162 | + cout << "ファイル" << fileName << "を開けません。" << endl; | |
163 | + return -1; | |
164 | + } | |
165 | + CurLineNo = 0; | |
166 | + | |
167 | + return 0; | |
168 | +} | |
169 | + | |
170 | +/* | |
171 | + * ソースファイルを閉じる | |
172 | + */ | |
173 | +void closeSource() | |
174 | +{ | |
175 | + Fin.close(); | |
176 | +} | |
177 | + | |
178 | +/* | |
179 | + * コメントを削除する | |
180 | + */ | |
181 | +static char *removeComment(char *s) | |
182 | +{ | |
183 | + int len = strlen(s); | |
184 | + char ws[MAX_LINE_LEN]; | |
185 | + char chr = 0; | |
186 | + int j = 0; | |
187 | + for (int i=0; i<len; i++) { | |
188 | + chr = s[i]; | |
189 | + if ((chr == '/') & (i<len-1)) { | |
190 | + if (s[i+1] == '/') | |
191 | + break; | |
192 | + } | |
193 | + ws[j++] = chr; | |
194 | + } | |
195 | + ws[j] = 0; | |
196 | + strcpy(s, ws); | |
197 | + | |
198 | + return s; | |
199 | +} | |
200 | + | |
201 | +/* | |
202 | + * 次の1文字を返す | |
203 | + */ | |
204 | +static int nextChar() | |
205 | +{ | |
206 | + int ch; | |
207 | + if (LineIndex == -1){ | |
208 | + Fin.getline(LineBuffer, MAX_LINE_LEN); | |
209 | + | |
210 | + if (Fin){ | |
211 | + CurLineNo += 1; | |
212 | + if (fPrintLine) { | |
213 | + cout << setw(3) << CurLineNo; | |
214 | + cout << ": " << LineBuffer << endl; | |
215 | + } | |
216 | + LineIndex = 0; | |
217 | + removeComment(LineBuffer); // コメントを削除する | |
218 | + } else if (Fin.eof()) // End Of Fileならコンパイル終了 | |
219 | + return EOF; | |
220 | + else // その他の読み込みエラーでコンパイル終了 | |
221 | + errorMsgExit("ファイル読み込みエラーです。"); | |
222 | + } | |
223 | + | |
224 | + ch = (int)LineBuffer[LineIndex++]; // chは次の1文字 | |
225 | + if (ch == 0){ // ch=null | |
226 | + LineIndex = -1; // 次の行を入力する準備をする(NULL文字を返す) | |
227 | + } | |
228 | + | |
229 | + return ch; | |
230 | +} | |
231 | + | |
232 | +/* | |
233 | + * 次のトークンを読み込んで返す | |
234 | + */ | |
235 | +Token nextToken() | |
236 | +{ | |
237 | + PrevToken = CurToken; | |
238 | + TokType prvType = PrevToken.type; | |
239 | + int i = 0; | |
240 | + int num; | |
241 | + Token temp; | |
242 | + string id; | |
243 | + while (1){ | |
244 | + if (Chr == ' ' || Chr == 0x9 || // 0x9='\t'(TAB) | |
245 | + Chr == 0xa || Chr == 0xd || Chr == 0) // CR ,LF(改行)かnull | |
246 | + ; | |
247 | + else break; | |
248 | + Chr = nextChar(); | |
249 | + } | |
250 | + | |
251 | + TokType cc = getCharType(Chr); | |
252 | + switch (cc) { | |
253 | + case LBrace: // 「{」 | |
254 | + case RBrace: // 「}」 | |
255 | + id.append(1, Chr); | |
256 | + Chr = nextChar(); | |
257 | + for (i=0; i<end_of_KeyWd; i++) { | |
258 | + if (id == KeyWdT[i].name) { | |
259 | + temp.type = KeyWdT[i].keyId; // 予約語 | |
260 | + CurToken = temp; | |
261 | + //if (fVerbose) // 詳細情報を出力したいときはコメント記号を削除する | |
262 | + // cout << "トークン:" << keyname[ temp.type ] << endl; | |
263 | + return temp; | |
264 | + } | |
265 | + } | |
266 | + errorMessage("シンタックスエラー"); | |
267 | + break; | |
268 | + case Letter: // 識別子 | |
269 | + do { | |
270 | + if (i < MAXNAME) | |
271 | + id.append(1, Chr); | |
272 | + i++; | |
273 | + Chr = nextChar(); | |
274 | + } while ( getCharType(Chr) == Letter || getCharType(Chr) == Digit ); | |
275 | + if (i >= MAXNAME){ | |
276 | + errorMessage("名前が長すぎます。"); | |
277 | + i = MAXNAME - 1; | |
278 | + } | |
279 | + for (i=0; i<end_of_KeyWd; i++) { | |
280 | + if ( id == KeyWdT[i].name ) { // 予約語か? | |
281 | + temp.type = KeyWdT[i].keyId; | |
282 | + CurToken = temp; | |
283 | + //if (fVerbose) // 詳細情報を出力したいときはコメント記号を削除する | |
284 | + // cout << "トークン:" << keyname[ temp.type ] << endl; | |
285 | + return temp; | |
286 | + } | |
287 | + } | |
288 | + temp.type = Id; // ユーザの宣言した名前 | |
289 | + temp.name = id; | |
290 | + break; | |
291 | + case Digit: // 数値 | |
292 | + num = 0; | |
293 | + do { // 10新数値文字列を数値に変換する | |
294 | + num = 10 * num + (Chr-'0'); | |
295 | + i++; | |
296 | + Chr = nextChar(); | |
297 | + } while ( getCharType(Chr) == Digit); | |
298 | + if (i>MAX_NUM_LEN) | |
299 | + errorMessage("数値として長すぎます。"); | |
300 | + temp.type = Num; | |
301 | + temp.value = num; | |
302 | + break; | |
303 | + case Minus: // -か数値 | |
304 | + if (prvType == Assign || prvType == Lparen || prvType == Comma | |
305 | + || prvType == Plus || prvType == Minus | |
306 | + || prvType == Mult || prvType == Div) { //負の符号(-nm) | |
307 | + Chr = nextChar(); | |
308 | + num = 0; | |
309 | + do { // 10新数値文字列を数値に変換する | |
310 | + num = 10 * num + (Chr-'0'); | |
311 | + i++; | |
312 | + Chr = nextChar(); | |
313 | + } while ( getCharType(Chr) == Digit); | |
314 | + if (i>MAX_NUM_LEN) | |
315 | + errorMessage("数値として長すぎます。"); | |
316 | + temp.type = Num; | |
317 | + temp.value = -1 * num; | |
318 | + } else { | |
319 | + temp.type = Minus; | |
320 | + Chr = nextChar(); | |
321 | + } | |
322 | + break; | |
323 | + case Colon: | |
324 | + if ((Chr = nextChar()) == '=') { // 「:=」 | |
325 | + Chr = nextChar(); | |
326 | + temp.type = Assign; | |
327 | + break; | |
328 | + } else { | |
329 | + temp.type = Nul; | |
330 | + break; | |
331 | + } | |
332 | + case Lss: | |
333 | + if ((Chr = nextChar()) == '=') { // 「<=」 | |
334 | + Chr = nextChar(); | |
335 | + temp.type = LssEq; | |
336 | + break; | |
337 | + } else if (Chr == '>') { // 「<>」 | |
338 | + Chr = nextChar(); | |
339 | + temp.type = NotEq; | |
340 | + break; | |
341 | + } else { | |
342 | + temp.type = Lss; | |
343 | + break; | |
344 | + } | |
345 | + case Gtr: | |
346 | + if ((Chr = nextChar()) == '=') { // 「>=」 | |
347 | + Chr = nextChar(); | |
348 | + temp.type = GtrEq; | |
349 | + } else | |
350 | + temp.type = Gtr; | |
351 | + break; | |
352 | + default: | |
353 | + temp.type = cc; | |
354 | + Chr = nextChar(); | |
355 | + break; | |
356 | + } | |
357 | + CurToken = temp; | |
358 | + /*if (fVerbose) { // 詳細情報を出力したいときはコメント記号を削除する | |
359 | + cout << "トークン:" << keyname[ temp.type ]; | |
360 | + if (temp.type == Id ) | |
361 | + cout << "(" << temp.name << ")"; | |
362 | + if (temp.type == Num ) | |
363 | + cout << "(" << temp.value << ")"; | |
364 | + cout << endl; | |
365 | + }*/ | |
366 | + return temp; | |
367 | +} | |
368 | + | |
369 | +/* | |
370 | + * 引数のトークンの種類を調べ、次のトークンを取得する | |
371 | + */ | |
372 | +Token checkAndgetToken(Token t, TokType k) | |
373 | +{ | |
374 | + if (t.type == k) | |
375 | + return nextToken(); | |
376 | + // トークンの種類が異なる場合、 | |
377 | + // おそらくエラーであるので修復を試みる | |
378 | + if ((isKeyWd(k) && isKeyWd(t.type)) || (isKeySym(k) && isKeySym(t.type))){ | |
379 | + compileError("シンタックスエラーです。トークンを削除します。"); | |
380 | + compileError( keyname[k] + "がありません。"); | |
381 | + return nextToken(); | |
382 | + } | |
383 | + compileError( keyname[k] + "がありません。"); | |
384 | + return t; | |
385 | +} | |
386 | +// E.O.F. | |
387 | + | |
388 | + |
@@ -0,0 +1,56 @@ | ||
1 | +// | |
2 | +// gettoken.h | |
3 | +// | |
4 | + | |
5 | +#ifndef GETSOURCE_H | |
6 | +#define GETSOURCE_H | |
7 | + | |
8 | +using namespace std; | |
9 | + | |
10 | +extern bool DispLine; // 読み込んだ行を出力するときtrue | |
11 | +extern int CurLineNo; // 現在のソースコード行番号 | |
12 | + | |
13 | +#define MAXNAME 31 // 名前の最大長さ | |
14 | + | |
15 | +typedef enum types { // キーワードと記号 | |
16 | + LBrace, RBrace, // { , } | |
17 | + If, Then, // 予約語 | |
18 | + While, Do, | |
19 | + Call, Ret, Func, Prog, | |
20 | + Integer, Const, | |
21 | + Write, WriteLn, WriteSp, | |
22 | + end_of_KeyWd, // ここまで予約語 | |
23 | + // 演算子と区切り記号の名前 | |
24 | + Plus, Minus, | |
25 | + Mult, Div, | |
26 | + Lparen, Rparen, | |
27 | + Equal, Lss, Gtr, | |
28 | + NotEq, LssEq, GtrEq, | |
29 | + Comma, Period, Semicolon, | |
30 | + Assign, | |
31 | + end_of_KeySym, // ここまで演算子と区切り記号の名前 | |
32 | + Id, Num, Nul, // トークンの種類 | |
33 | + end_of_Token, | |
34 | + Letter, Digit, Colon, Others, // その他の文字の種類 | |
35 | + EndOfFile | |
36 | +} TokType; | |
37 | + | |
38 | +class Token { // トークンのクラス | |
39 | +public: | |
40 | + TokType type; // トークンの種類 | |
41 | + string name; // 識別子(その名前) | |
42 | + int value; // 数値の場合の値 | |
43 | + Token () {type = Others; name =""; value=0; } | |
44 | +}; | |
45 | + | |
46 | +int openSource(string ); // ソースファイルを開く | |
47 | +void init(); | |
48 | +void closeSource(); // ソースファイルを閉じる | |
49 | +Token nextToken(); | |
50 | +Token checkAndgetToken(Token t, TokType k); | |
51 | +void compileError(string s); | |
52 | +int getNumberOfErrors(); | |
53 | + | |
54 | + | |
55 | +#endif | |
56 | + |
@@ -0,0 +1,142 @@ | ||
1 | +// | |
2 | +// main.cpp - コンパイラ(trifleプログラム)のメイン | |
3 | +// | |
4 | +#include "trifle.h" | |
5 | + | |
6 | +using namespace std; | |
7 | + | |
8 | +#ifdef _MSC_VER | |
9 | +#include <process.h> | |
10 | +#define Exec _execlp | |
11 | +#define TVM "tvm" | |
12 | +#else | |
13 | +#include <unistd.h> | |
14 | +#define Exec execlp | |
15 | +#define TVM "./tvm" | |
16 | +#endif | |
17 | + | |
18 | +// グローバル変数 | |
19 | +string SrcFileName; // ソースプログラムファイル名 | |
20 | + | |
21 | +// コンパイル(と実行)オプションのためのフラグ | |
22 | +bool fPrintLine = false; | |
23 | +bool fGenerateList = false; | |
24 | +bool fExec = false; | |
25 | +bool fDispCode = false; | |
26 | +bool fVerbose = false; | |
27 | +// プロトタイプ宣言 | |
28 | +int usage(); | |
29 | +int processCmdLine(int argc, char *argv[]); | |
30 | + | |
31 | +/* | |
32 | + * コンパイラのメイン関数 | |
33 | + */ | |
34 | +int main(int argc, char *argv[]) | |
35 | +{ | |
36 | + // コマンドラインの処理 | |
37 | + if (argc<2) | |
38 | + return usage(); | |
39 | + for (int i=1; i<argc; i++) { | |
40 | + if (processCmdLine(argc, argv)) | |
41 | + return -1; | |
42 | + } | |
43 | + | |
44 | + cout << SrcFileName << "をコンパイルします。" << endl; | |
45 | + | |
46 | + if (openSource(SrcFileName)) // ソースプログラムファイルを開く | |
47 | + return -1; | |
48 | + | |
49 | + bool fSuccess = compile(); // コンパイルする | |
50 | + | |
51 | + closeSource(); // ソースプログラムファイルを閉じる | |
52 | + | |
53 | + if (fExec & fSuccess) // 実行オプションが指定されていて | |
54 | + { // コンパイルが成功したら実行する | |
55 | + cout << "「tvm " << ObjFileName << "」を実行します。" << endl; | |
56 | + char fname[MAX_PATH_LEN]; | |
57 | + strcpy(fname, ObjFileName.c_str()); | |
58 | + string CmdOpt = ""; | |
59 | + CmdOpt.clear(); | |
60 | + if (fVerbose) | |
61 | + CmdOpt = "-v "; | |
62 | + if (fDispCode) | |
63 | + CmdOpt += "-d "; | |
64 | + CmdOpt = trim(CmdOpt); | |
65 | + if (CmdOpt.length() == 0) { | |
66 | + if ( Exec(TVM, fname, NULL) == -1) | |
67 | + cout << TVM << "(" << ObjFileName <<")実行エラー" << endl; | |
68 | + } | |
69 | + if ( Exec(TVM, CmdOpt.c_str(), fname, NULL) == -1) | |
70 | + cout << TVM << "(" << ObjFileName <<")実行エラー" << endl; | |
71 | + } | |
72 | + return 0; | |
73 | +} | |
74 | + | |
75 | +/* | |
76 | + * 使い方を出力する | |
77 | + */ | |
78 | +int usage() | |
79 | +{ | |
80 | + cout << "使い方:trifle [options] source" << endl; | |
81 | + cout << "options -PrintLine:コンパイルしているコード行を出力する。" << endl; | |
82 | + cout << " -GenList :リスティングファイルを生成する。" << endl; | |
83 | + cout << " -Exec :仮想マシンで実行する。" << endl; | |
84 | + cout << " -DispCode :仮想マシンで実行しているコードを出力する。" << endl; | |
85 | + cout << " -Verbose :仮想マシンで実行の際に詳細な情報を出力する。" << endl; | |
86 | + return 0; | |
87 | +} | |
88 | + | |
89 | +/* | |
90 | + * 拡張子が.triであるかどうか調べる | |
91 | + */ | |
92 | +int checkFileName(string fName) | |
93 | +{ | |
94 | + string lfName = lowerString(fName); | |
95 | + if (lfName.find(".tri", lfName.length() - 4, 4) == string::npos) | |
96 | + return -1; | |
97 | + return 0; | |
98 | +} | |
99 | + | |
100 | +/* | |
101 | + * コマンドラインを処理する | |
102 | + */ | |
103 | +int processCmdLine(int argc, char *argv[]) | |
104 | +{ | |
105 | + for (int i=1; i<argc; i++){ | |
106 | + string option = string(argv[i]); | |
107 | + if (option[0] == '-') { // オプション | |
108 | + // オプション文字列の検査は大文字/小文字を区別しないで比較する | |
109 | + if (compareIgnCase(option, "-printline")) | |
110 | + fPrintLine = true; | |
111 | + else if (compareIgnCase(option, "-p")) | |
112 | + fPrintLine = true; | |
113 | + else if (compareIgnCase(option, "-exec")) | |
114 | + fExec = true; | |
115 | + else if (compareIgnCase(option, "-e")) | |
116 | + fExec = true; | |
117 | + else if (compareIgnCase(option, "-GenList")) | |
118 | + fGenerateList = true; | |
119 | + else if (compareIgnCase(option, "-G")) | |
120 | + fGenerateList = true; | |
121 | + else if (compareIgnCase(option, "-DispCode")) | |
122 | + fDispCode = true; | |
123 | + else if (compareIgnCase(option, "-D")) | |
124 | + fDispCode = true; | |
125 | + else if (compareIgnCase(option, "-Verbose")) | |
126 | + fVerbose = true; | |
127 | + else if (compareIgnCase(option, "-V")) | |
128 | + fVerbose = true; | |
129 | + else { | |
130 | + cout << "無効なオプションが指定されています。" << endl; | |
131 | + return -1; | |
132 | + } | |
133 | + } else { // オプションでなければコンパイルするプログラムのソースファイル名 | |
134 | + SrcFileName = option; | |
135 | + if ( checkFileName(SrcFileName) ) { | |
136 | + cout << "拡張子が不正です(入力ファイル名:" << SrcFileName << ")" << endl; | |
137 | + return -1; | |
138 | + } | |
139 | + } | |
140 | + } | |
141 | + return 0; | |
142 | +} |
@@ -0,0 +1,33 @@ | ||
1 | +#define _CRT_SECURE_NO_WARNINGS | |
2 | + | |
3 | +// trifle.h | |
4 | +// | |
5 | +#ifndef TRIFLE_H | |
6 | +#define TRIFLE_H | |
7 | + | |
8 | +#include <iostream> | |
9 | +#include <fstream> | |
10 | +#include <string> | |
11 | +#include <vector> | |
12 | +#include <cctype> | |
13 | +#include <iomanip> | |
14 | + | |
15 | + | |
16 | +#define MAX_LINE_LEN 128 // 1行の最大文字数 | |
17 | +#define MAX_ERROR 30 // コンパイルを終了するエラー数 | |
18 | +#define MAX_NUM_LEN 14 // 定数の最大の長さ | |
19 | + | |
20 | +using namespace std; | |
21 | + | |
22 | +#include "gencode.h" | |
23 | +#include "gettoken.h" | |
24 | +#include "compile.h" | |
25 | +#include "util.h" | |
26 | + | |
27 | +extern string SrcFileName; | |
28 | +extern string ObjFileName; | |
29 | +extern bool fExec; | |
30 | +extern bool fPrintLine; | |
31 | +extern bool fGenerateList; | |
32 | +extern bool fVerbose; | |
33 | +#endif |
@@ -0,0 +1,14 @@ | ||
1 | +// | |
2 | +// tvm.h | |
3 | +// | |
4 | +#ifndef TVM_H | |
5 | +#define TVM_H | |
6 | + | |
7 | +#include <iostream> | |
8 | +#include <fstream> | |
9 | +#include <string> | |
10 | +#include <iomanip> | |
11 | +#include "gencode.h" | |
12 | +#include "util.h" | |
13 | + | |
14 | +#endif // TVM_H |
@@ -0,0 +1,167 @@ | ||
1 | +#define _CRT_SECURE_NO_WARNINGS | |
2 | +// | |
3 | +// util.cpp | |
4 | +// | |
5 | +#include <iostream> | |
6 | +#include <string> | |
7 | +#include <cstring> | |
8 | +#include <algorithm> | |
9 | +#include "util.h" | |
10 | + | |
11 | +using namespace std; | |
12 | + | |
13 | +/* | |
14 | + * 目的コードを見やすい形で出力する | |
15 | + */ | |
16 | +void printCode(Instruction instrct) | |
17 | +{ | |
18 | + int flag = 0; | |
19 | + // 命令を出力する | |
20 | + switch(instrct.opCode){ | |
21 | + case literl: cout << "literl "; flag=1; break; | |
22 | + case neg: cout << "neg"; break; | |
23 | + case add: cout << "add"; break; | |
24 | + case sub: cout << "sub"; break; | |
25 | + case mul: cout << "mul"; break; | |
26 | + case divide: cout << "div"; break; | |
27 | + case equals: cout << "eq"; break; | |
28 | + case ls: cout << "ls"; break; | |
29 | + case gr: cout << "gr"; break; | |
30 | + case neq: cout << "neq"; break; | |
31 | + case lseq: cout << "lseq"; break; | |
32 | + case greq: cout << "greq"; break; | |
33 | + case wrt: cout << "wrt"; break; | |
34 | + case wrtln: cout << "wrtln"; flag=0;break; | |
35 | + case wrtsp: cout << "wrtsp"; break; | |
36 | + case load: cout << "load "; flag=2; break; | |
37 | + case store: cout << "store "; flag=2; break; | |
38 | + case call: cout << "call "; flag=2; break; | |
39 | + case ret: cout << "ret "; flag=2; break; | |
40 | + case incmnt: cout << "incmnt "; flag=1; break; | |
41 | + case jmp: cout << "jmp "; flag=1; break; | |
42 | + case jpc: cout << "jpc "; flag=1; break; | |
43 | + } | |
44 | + | |
45 | + // 命令パラメータを出力する | |
46 | + switch(flag){ | |
47 | + case 0: | |
48 | + cout << endl; | |
49 | + return; | |
50 | + case 1: | |
51 | + cout << instrct.param1 << endl; | |
52 | + break; | |
53 | + default: | |
54 | + cout << instrct.param1 << ","; | |
55 | + cout << instrct.param2 << endl; | |
56 | + break; | |
57 | + } | |
58 | +} | |
59 | + | |
60 | +/* | |
61 | + * 文字列を小文字文字列に変換して返す。 | |
62 | + */ | |
63 | +string lowerString(string s) | |
64 | +{ | |
65 | + string str = ""; | |
66 | + char buff[1024]; | |
67 | + strcpy(buff, s.c_str()); | |
68 | + int len = strlen(buff); | |
69 | + for (int i=0; i<len; i++) { | |
70 | + int c = s[i]; | |
71 | + int lc = tolower(c); | |
72 | + str.append(1, lc); | |
73 | + } | |
74 | + return str; | |
75 | +} | |
76 | + | |
77 | +/* | |
78 | + * 大文字小文字を区別しないで文字を比較する | |
79 | + * 同じであればtrueを、そうではなければfalseを返す。 | |
80 | + */ | |
81 | +bool compCharIgnCase(char c1, char c2) { | |
82 | + return (tolower(c1) == tolower(c2)); | |
83 | +} | |
84 | +bool compareIgnCase(string s1, string s2) | |
85 | +{ | |
86 | + if (s1.length() != s2.length()) | |
87 | + return false; | |
88 | + // 大文字小文字を区別しない比較を行う。 | |
89 | + return equal(s1.begin(), s1.end(), | |
90 | + s2.begin(), compCharIgnCase); | |
91 | +} | |
92 | + | |
93 | +/* | |
94 | + * 大文字/小文字を無視して部分文字列を検索する | |
95 | + * str:検索する文字列。substr:探す部分文字列 | |
96 | + * 戻り値:一致した場合は先頭の反復子、一致しない場合はstr.end() | |
97 | + */ | |
98 | +string::iterator searchIgnCase(string &str, const string &substr) { | |
99 | + return search(str.begin(), str.end(), | |
100 | + substr.begin(), substr.end(), compCharIgnCase); | |
101 | +} | |
102 | + | |
103 | +/* | |
104 | + * 子プロセスであるか調べる | |
105 | + */ | |
106 | +bool isChildProcess(char *firstarg, const char *exefname) | |
107 | +{ | |
108 | + // 最初の引数の最後の部分が実行可能ファイル名と同じなら子プロセスではないとする | |
109 | + string s1 = lowerString(string(firstarg)); | |
110 | + string::size_type pos = s1.find(".exe", 1); | |
111 | + if (pos != string::npos) | |
112 | + s1 = s1.substr(0, pos); | |
113 | + char buff[MAX_PATH_LEN]; | |
114 | + strcpy(buff, s1.c_str()); | |
115 | + int len1 = strlen(buff); | |
116 | + int len2 = strlen(exefname); | |
117 | + for (int i=1; i<=len2; i++) { | |
118 | + if (tolower(buff[len1-i]) != tolower(exefname[len2-i])) | |
119 | + return true; | |
120 | + } | |
121 | + return false; | |
122 | +} | |
123 | + | |
124 | +/* | |
125 | + * エラーメッセージを出力する | |
126 | + */ | |
127 | +int errorMessage(string s) | |
128 | +{ | |
129 | + cout << "エラー :" << s << endl; | |
130 | + return -1; | |
131 | +} | |
132 | +int errorMessage(int lineNuber, string s) | |
133 | +{ | |
134 | + cout << "エラー 行:" << lineNuber << ":" << s << endl; | |
135 | + return -1; | |
136 | +} | |
137 | + | |
138 | +/* | |
139 | + * エラーメッセージを出力してプログラムを終了する | |
140 | + */ | |
141 | +int errorMsgExit(string s) | |
142 | +{ | |
143 | + cout << s << endl; | |
144 | + cout << "致命的エラー。" << endl; | |
145 | + exit(-1); | |
146 | +} | |
147 | + | |
148 | +/* | |
149 | + * 文字列の前後の空白を除く | |
150 | + */ | |
151 | +string trim(string s) | |
152 | +{ | |
153 | + string ss = ""; | |
154 | + bool instr = false; | |
155 | + int len = s.length(); | |
156 | + for (int i=0; i<len; i++) { | |
157 | + char c = s[i]; | |
158 | + if ( (c == 0x20 || c == 0x8) && !instr) | |
159 | + continue; | |
160 | + else { | |
161 | + ss += c; | |
162 | + instr = true; | |
163 | + } | |
164 | + } | |
165 | + return ss; | |
166 | +} | |
167 | +// E.O.F. |
@@ -0,0 +1,29 @@ | ||
1 | +#define _CRT_SECURE_NO_WARNINGS | |
2 | +// | |
3 | +// util.h | |
4 | +// | |
5 | +#ifndef UTIL_H | |
6 | +#define UTIL_H 1 | |
7 | + | |
8 | +#ifndef CODEGEN_H | |
9 | +#include "gencode.h" | |
10 | +#endif | |
11 | + | |
12 | +using namespace std; | |
13 | + | |
14 | +#define MAX_PATH_LEN 1024 // パス名の最大長さ | |
15 | +#define MAX_NAME_LEN 64 // 名前の最大長さ | |
16 | + | |
17 | +void printCode(Instruction instrct); | |
18 | +string lowerString(string s); // 文字列を小文字文字列に変換して返す。 | |
19 | +bool compCharIgnCase(char c1, char c2); | |
20 | +bool compareIgnCase(string s1, string s2); | |
21 | +string::iterator searchIgnCase(string &str, const string &substr) ; | |
22 | +bool isChildProcess(char *firtstarg, const char *exe); | |
23 | +int errorMessage(string s); | |
24 | +int errorMessage(int lineNuber, string s); | |
25 | +int errorMsgExit(string s); | |
26 | +string trim(string s); | |
27 | +#endif | |
28 | + | |
29 | + |
@@ -0,0 +1,387 @@ | ||
1 | +// | |
2 | +// vmmain.cpp - 仮想マシンtvm(trifle virtual machine)のメイン | |
3 | +// | |
4 | +#include <vector> | |
5 | +#include "tvm.h" | |
6 | + | |
7 | +using namespace std; | |
8 | + | |
9 | +#define MEMSIZE 4096 // 仮想マシンメモリサイズ | |
10 | +#define MAX_REG 64 // 演算レジスタスタックの最大長さ | |
11 | +#define MAX_LEVEL 5 // ブロックの最大のレベル | |
12 | + | |
13 | +// フラグ | |
14 | +bool fDispCode = false; | |
15 | +bool fVerbose = false; | |
16 | + | |
17 | +// プロトタイプ宣言 | |
18 | +int processCmdLine(int argc, char *argv[]); | |
19 | +int openFile(); | |
20 | +void closeFile(); | |
21 | +int loadBinData(); | |
22 | +void listObjCodes() ; | |
23 | +int usage(); | |
24 | + | |
25 | +// グローバル変数 | |
26 | +vector <Instruction> ObjCodes; | |
27 | +string ObjFileName; | |
28 | + | |
29 | +ifstream fin; // 入力ファイルストリーム | |
30 | + | |
31 | +class VirtualMachine { | |
32 | + vector <int> vmemory; // 仮想マシンのメモリ | |
33 | + int pc; // プログラムカウンタ | |
34 | + int stcktop; // スタックのトップ | |
35 | + int display[MAX_LEVEL]; // 現在見える各ブロックの先頭アドレスのディスプレイ | |
36 | +public: | |
37 | + VirtualMachine() { | |
38 | + vmemory = vector<int>(MEMSIZE); | |
39 | + stcktop = 0; | |
40 | + pc = 0; | |
41 | + } | |
42 | + void storemem(int addr, int getVal){ | |
43 | + if (addr < 0 || addr > MEMSIZE) { | |
44 | + errorMsgExit("無効なアドレスにアクセスしようとしました。"); | |
45 | + } | |
46 | + vmemory[addr] = getVal; | |
47 | + } | |
48 | + int loadmem(int addr){ | |
49 | + if (addr < 0 || addr > MEMSIZE) { | |
50 | + errorMsgExit("無効なアドレスにアクセスしようとしました。"); | |
51 | + } | |
52 | + return vmemory[addr]; | |
53 | + } | |
54 | + void push(int getVal) { vmemory[stcktop++] = getVal;} | |
55 | + int pop1() { return vmemory[--stcktop]; } | |
56 | + int peek() { return vmemory[stcktop]; } | |
57 | + int peek1() { return vmemory[stcktop-1]; } | |
58 | + int getStckTop() { return stcktop; } | |
59 | + int setStckTop(int addr) { | |
60 | + if (addr < 0 || addr > MEMSIZE) { | |
61 | + errorMsgExit("無効なスタックアドレスが指定されました。"); | |
62 | + return -1; | |
63 | + } | |
64 | + stcktop = addr; | |
65 | + return stcktop; | |
66 | + } | |
67 | + int getPc() { return pc; } | |
68 | + void setPc(int addr) { | |
69 | + if (addr < 0 || addr > MEMSIZE) { | |
70 | + errorMsgExit("無効なPCが指定されました。"); | |
71 | + return; | |
72 | + } | |
73 | + pc = addr; | |
74 | + } | |
75 | + int incPc() { return pc++; } | |
76 | + int getDisplay(int lvl){ | |
77 | + if (lvl < 0 || lvl > MAX_LEVEL) { | |
78 | + errorMsgExit("無効なディスプレイレベルが指定されました。"); | |
79 | + return 0; | |
80 | + } | |
81 | + return display[lvl]; | |
82 | + } | |
83 | + bool setDisplay(int lvl, int getVal) { | |
84 | + if (lvl < 0 || lvl > MAX_LEVEL) { | |
85 | + errorMsgExit("無効なディスプレイレベルが指定されました。"); | |
86 | + return false; | |
87 | + } | |
88 | + if (getVal < 0) { | |
89 | + errorMsgExit("無効なディスプレイ値が指定されました。"); | |
90 | + return false; | |
91 | + } | |
92 | + display[lvl] = getVal; | |
93 | + return true; | |
94 | + } | |
95 | + | |
96 | + // オブジェクトコードを実行する | |
97 | + void execute(); | |
98 | +}; | |
99 | + | |
100 | +VirtualMachine vm; | |
101 | + | |
102 | +int main(int argc, char *argv[]) | |
103 | +{ | |
104 | + if (fVerbose) | |
105 | + cout << "tvm(trifle virtual machine)" << ObjFileName << " ..." << endl; | |
106 | + | |
107 | + // コマンドラインの処理 | |
108 | + if ((argc < 2) & compareIgnCase(argv[0], "tvm")) | |
109 | + return usage(); | |
110 | + | |
111 | + if (processCmdLine(argc, argv)) | |
112 | + return usage(); | |
113 | + | |
114 | + if (fVerbose) | |
115 | + cout << ObjFileName << "を実行します。" << endl; | |
116 | + if (openFile()) // プログラムファイルをロードする | |
117 | + return -1; // 読み込みに失敗すれば終わり | |
118 | + | |
119 | + loadBinData(); | |
120 | + | |
121 | + if (fDispCode) | |
122 | + listObjCodes(); | |
123 | + | |
124 | + vm.execute(); // 実行 | |
125 | + | |
126 | + closeFile(); | |
127 | + | |
128 | + return 0; | |
129 | +} | |
130 | + | |
131 | +// 拡張子が.exfであるかどうか調べる | |
132 | +int checkFileName(string fName) | |
133 | +{ | |
134 | + string lfName = lowerString(fName); | |
135 | + if (lfName.find(".exf", lfName.length() - 4, 4) == string::npos) | |
136 | + return -1; | |
137 | + return 0; | |
138 | +} | |
139 | + | |
140 | +// コマンドラインを処理する | |
141 | +int processCmdLine(int argc, char *argv[]) | |
142 | +{ | |
143 | + int j = 1; | |
144 | + if (isChildProcess(argv[0], "tvm")) | |
145 | + j = 0; | |
146 | + | |
147 | + for (int i=j; i<argc; i++){ | |
148 | + string option = string(argv[i]); | |
149 | + if (option[0] == '-') { // オプション | |
150 | + if (compareIgnCase(option, "-DispCode")) | |
151 | + fDispCode = true; | |
152 | + else if (compareIgnCase(option, "-D")) | |
153 | + fDispCode = true; | |
154 | + else if (compareIgnCase(option, "-Verbose")) | |
155 | + fVerbose = true; | |
156 | + else if (compareIgnCase(option, "-V")) | |
157 | + fVerbose = true; | |
158 | + else { | |
159 | + cout << "無効なオプションが指定されています。" << endl; | |
160 | + return -1; | |
161 | + } | |
162 | + } else { | |
163 | + ObjFileName = option; | |
164 | + if ( checkFileName(ObjFileName) ) { | |
165 | + cout << "拡張子が不正です(入力ファイル名:" << ObjFileName << ")" << endl; | |
166 | + return -1; | |
167 | + } | |
168 | + } | |
169 | + } | |
170 | + return 0; | |
171 | +} | |
172 | + | |
173 | +int usage() | |
174 | +{ | |
175 | + cout << "使い方:tvm [options] exf_file" << endl; | |
176 | + cout << " options -DispCode:実行しているコードを出力する。" << endl; | |
177 | + cout << " -Verbose :詳細な情報を出力する。" << endl; | |
178 | + return 0; | |
179 | +} | |
180 | + | |
181 | +int openFile() | |
182 | +{ | |
183 | + // 入力ファイルを開く | |
184 | + fin.open(ObjFileName.c_str(), ios::binary | ios::in); | |
185 | + if (!fin) | |
186 | + return errorMessage(ObjFileName + "を開けません。"); | |
187 | + int lines = 0; | |
188 | + | |
189 | + return 0; | |
190 | +} | |
191 | + | |
192 | +void closeFile() | |
193 | +{ | |
194 | + fin.close(); | |
195 | +} | |
196 | + | |
197 | +/* | |
198 | + * 次の1バイトを読み込んで返す | |
199 | + */ | |
200 | +int getNextChar() | |
201 | +{ | |
202 | + int c = fin.get(); | |
203 | + if (c > 126) | |
204 | + c = c - 256; | |
205 | + return c; | |
206 | +} | |
207 | + | |
208 | +int getValue(){ | |
209 | + int v; | |
210 | + fin >> setw(8) >> v; | |
211 | + return v; | |
212 | +} | |
213 | + | |
214 | +void listObjCodes() | |
215 | +{ | |
216 | + cout << endl << "読み込んだコード" << endl; | |
217 | + int nCodes = (int)ObjCodes.size(); | |
218 | + for(int i=0; i<nCodes; i++){ | |
219 | + cout << setw(3) << i << ": "; | |
220 | + printCode( ObjCodes[i] ); | |
221 | + } | |
222 | +} | |
223 | + | |
224 | +// オブジェクトコードを読み込む | |
225 | +int loadBinData() | |
226 | +{ | |
227 | + Instruction instrct = Instruction(); | |
228 | + if (fVerbose) | |
229 | + cout << "オブジェクトコードを読み込みます。" << endl; | |
230 | + | |
231 | + // オブジェクトコードを読み込んでObjCodesという名前の | |
232 | + // 要素がInstruction型のObjCodesに保存する | |
233 | + int c; | |
234 | + while( true ) { | |
235 | + c = getNextChar(); | |
236 | + if ( fin.eof() ) | |
237 | + break; | |
238 | + instrct.opCode = (OpCode)c; | |
239 | + switch(c){ | |
240 | + case literl: | |
241 | + case incmnt: | |
242 | + case jmp: | |
243 | + case jpc: | |
244 | + instrct.param1 = getValue(); | |
245 | + break; | |
246 | + case ret: | |
247 | + case load: | |
248 | + case call: | |
249 | + case store: | |
250 | + instrct.param1 = getNextChar(); | |
251 | + instrct.param2 = getNextChar(); | |
252 | + break; | |
253 | + default: | |
254 | + break; | |
255 | + } | |
256 | + ObjCodes.push_back( instrct ); | |
257 | + } | |
258 | + | |
259 | + return 0; | |
260 | +} | |
261 | + | |
262 | +Instruction getNextCode() | |
263 | +{ | |
264 | + if (vm.getPc() >= (int)ObjCodes.size() ) | |
265 | + return Instruction(codes::end); | |
266 | + return ObjCodes[vm.incPc()]; | |
267 | +} | |
268 | + | |
269 | +// オブジェクトコードを実行する | |
270 | +void VirtualMachine::execute() | |
271 | +{ | |
272 | + int lev, temp; | |
273 | + Instruction instrct; | |
274 | + | |
275 | + if (fVerbose) | |
276 | + cout << "プログラム実行開始" << endl; | |
277 | + | |
278 | + storemem(0, 0); | |
279 | + storemem(1, 0); | |
280 | + display[0] = 0; | |
281 | + do { | |
282 | + instrct = getNextCode(); | |
283 | + if ( instrct.opCode == codes::end ) | |
284 | + break; | |
285 | + | |
286 | + if (fDispCode) | |
287 | + printCode( instrct ); | |
288 | + | |
289 | + switch(instrct.opCode){ | |
290 | + case literl: | |
291 | + push(instrct.param1); | |
292 | + break; | |
293 | + case load: | |
294 | + push(loadmem( getDisplay(instrct.param1) + instrct.param2) ); | |
295 | + break; | |
296 | + case store: | |
297 | + storemem( getDisplay(instrct.param1) + instrct.param2, pop1() ); | |
298 | + break; | |
299 | + case call: | |
300 | + lev = instrct.param1 +1; | |
301 | + storemem(getStckTop(), display[lev]); | |
302 | + storemem(getStckTop()+1, getPc()); | |
303 | + setDisplay( lev, getStckTop()); | |
304 | + setPc( instrct.param2) ; | |
305 | + break; | |
306 | + case ret: | |
307 | + temp = pop1(); | |
308 | + setStckTop( getDisplay(instrct.param1) ); | |
309 | + if (instrct.param1 == 0) { // レベル0からのリターンは | |
310 | + setPc( 0 ); // プログラムの終了 | |
311 | + break; | |
312 | + } | |
313 | + setDisplay(instrct.param1, peek()); | |
314 | + setPc( loadmem( getStckTop()+1 )); | |
315 | + setStckTop( getStckTop() - instrct.param2); | |
316 | + push( temp ); | |
317 | + break; | |
318 | + case incmnt: | |
319 | + setStckTop( getStckTop() + instrct.param1); | |
320 | + if (getStckTop() >= MEMSIZE-MAX_REG) | |
321 | + errorMsgExit("スタックがオーバーフローしました。"); | |
322 | + break; | |
323 | + case jmp: | |
324 | + setPc( instrct.param1); | |
325 | + break; | |
326 | + case jpc: | |
327 | + if (pop1() == 0) | |
328 | + setPc( instrct.param1 ); | |
329 | + break; | |
330 | + case neg: | |
331 | + storemem(getStckTop()-1, -1 * loadmem(peek()-1)); | |
332 | + break; | |
333 | + case add: | |
334 | + pop1(); | |
335 | + storemem( getStckTop()-1, peek1() + peek()); | |
336 | + break; | |
337 | + case sub: | |
338 | + pop1(); | |
339 | + storemem( getStckTop()-1, peek1() - peek()); | |
340 | + break; | |
341 | + case mul: | |
342 | + pop1(); | |
343 | + storemem( getStckTop()-1, peek1() * peek() ); | |
344 | + break; | |
345 | + case divide: | |
346 | + pop1(); | |
347 | + storemem( getStckTop()-1, peek1() / peek() ); | |
348 | + break; | |
349 | + case equals: | |
350 | + pop1(); | |
351 | + storemem( getStckTop()-1, (peek1() == peek()) ); | |
352 | + break; | |
353 | + case ls: | |
354 | + pop1(); | |
355 | + storemem( getStckTop()-1, (peek1() < peek()) ); | |
356 | + break; | |
357 | + case gr: | |
358 | + pop1(); | |
359 | + storemem( getStckTop()-1, (peek1() > peek()) ); | |
360 | + break; | |
361 | + case neq: | |
362 | + pop1(); | |
363 | + storemem( getStckTop()-1, (peek1() != peek()) ); | |
364 | + break; | |
365 | + case lseq: | |
366 | + pop1(); | |
367 | + storemem( getStckTop()-1, (peek1() <= peek()) ); | |
368 | + break; | |
369 | + case greq: | |
370 | + pop1(); | |
371 | + storemem( getStckTop()-1, (peek1() >= peek()) ); | |
372 | + break; | |
373 | + case wrt: | |
374 | + cout << pop1(); | |
375 | + break; | |
376 | + case wrtln: | |
377 | + cout << endl; | |
378 | + break; | |
379 | + case wrtsp: | |
380 | + cout << " "; | |
381 | + break; | |
382 | + } | |
383 | + } while (getPc() != 0); | |
384 | + | |
385 | +} | |
386 | + | |
387 | +// E.O.F |