2019-05-01から1ヶ月間の記事一覧

コンパイラ作成(54) 文字列定数が引数の関数

今回の目標 今回は引数がint型じゃない関数に対応するよ。 // 文字列の引数 int main() { puts_x("Hello, World!", 5); } int puts_x(char *s, int n) { int i; for(i = 0; i < n; i = i + 1) puts(s); } いきなりchar型、それも*付き。C言語初心者を地獄に…

コンパイラ作成(53) 負数の計算

今回の目標 前回、不十分だった負数の計算を確かめるよ。 // 負数 int main() { printf("%d\n",(10-20)/2); } この計算が間違ってたと思うよ。 古いバージョンでテスト 一個前のバージョンでテストしてみる。 ~/myc$ git worktree add old HEAD^ Preparing o…

コンパイラ作成(52) 単項演算子

今回の目標 単項演算子の"+"と"-"を追加するよ。"+"の方はめったに使われないよね。 // 単行演算子 int main() { int a = 10; int b = -a; printf("a = %d\n",a); printf("b = %d\n",b); } それとこの機会に今までちゃんとしてなかった負数の計算を修正する…

コンパイラ作成(51) 引数のある関数の定義

今回の目標 引数のある関数を定義できるようにするよ。 // 引数のある関数の定義 int main() { int a = 5, b = 12, c; c = add(a,b); printf("%d + %d = %d\n", a, b, c); } int add(int a, int b) { printf("add: a = %d b = %d\n", a, b); return a + b; }…

コンパイラ作成(50) 引数のある関数の呼び出しを修正

今回の目標 前回、Segmentation faultになっちゃったのを頑張って修正するよ。 // 引数のある関数の呼び出し int main() { int a = 5, b = 12, c; printf("%d + %d = %d\n",a,b,add(a,b)); } printfを呼ぶためにセットしたレジスタの値が、addの呼び出しで壊…

コンパイラ作成(49) 引数のある関数の呼び出し

今回の目標 以前、引数のない関数の呼び出しはサポートしたんだけど、引数がある場合は未サポートのままになってたよ。 // 引数のある関数の呼び出し int main() { int a = 5, b = 12, c; c = add(a,b); printf("%d + %d = %d\n",a,b,c); } 今回はこれを頑張…

コンパイラ作成(48) 最適化

今回の目標 突然だけど最適化処理を追加するよ。って言っても超簡単なやつだけどね。 main() { return 42; } これ一番最初にコンパイルしたテストプログラムだよ。 .intel_syntax noprefix .global main main: push rbp mov rbp, rsp mov eax, 42 jmp .RET_m…

コンパイラ作成(47) バグ修正

バグ2件 最近恒例になってきたバグ修正。今回は2件だよ。 main() { print(42); } 前回、スタックフレームの作成を修正したけど、こういう風に変数が1個も使われてない場合に、sub rsp,0ってコードが出力されてたよ。これでも動くから問題ないんだけど、恰…

コンパイラ作成(46) ローカル変数領域のサイズ

今回の目標 ローカル変数領域のサイズが64byte固定になってる件を修正するよ。 // 変数26個 int main() { int a,b,c,d,e,f,g,h,i,j; int k,l,m,n,o,p,q,r,s,t; int u,v,w,x,y,z; } 64byteに収まらない数のint変数を宣言してる。 initialize まずはここ。 # …

コンパイラ作成(45) break文

今回の目標 今回はberak文だよ。 // break文 int main() { int i = 0, square; for(;;) { square = i * i; if(square >= 150) break; printf("%2d * %2d = %3d\n",i,i,square); i = i + 1; } return 0; } 単純な場合のbreak文。 TK::RESERVE まずはここ。 @r…

コンパイラ作成(44) コンパイラオプション

optparse rubyのgetoptみたいなのを調べたらoptparseってのがそれみたいなんで使ってみるよ。optparseライブラリを使う(in Ruby) | 雑記帳を参考にさせてもらったよ。 今回合わせてrspcheck.oみたいなのを指定できるようにする。それとprint.oを自動的にリン…

コンパイラ作成(43) バグ修正

バグ修正2件 if文、while文、for文とサポートできたけど、テストは不十分だった。でいくつかテストをしてたら案の定バグが見つかったよ。 // while文 int main() { int i = 0; puts("start"); while(i < 5) { printf("%d * %d = %d\n",i,i,i*i); i = i + 1;…

コンパイラ作成(42) for文

今回の目標 今回はfor文。 // for文 int main() { int i; puts("start"); for(i = 0; i < 5; i = i + 1) { printf("%d * %d = %d\n",i,i,i*i); } puts("end"); return 0; } 前回のwhile文から書き直しただけ。 statement 修正はここだけ。 elsif kind == TK:…

コンパイラ作成(41) while文

今回の目標 久々に機能追加。 // while文 int main() { int i = 0; puts("start"); while(i < 5) { printf("%d * %d = %d\n",i,i,i*i); i = i + 1; } puts("end"); return 0; } while文だよ。if文とそんなに変わらないんで簡単にできると思うよ。 statement …

コンパイラ作成(40) System V AMD64 ABIへの準拠

mycの問題点 以前、ABIに付いて調べたときから気になっていた点を見直すよ。mycの問題点は2つ。1件目はrbxが保存されてないこと。これは対処はそう難しくないかな。rbxの使用をやめて、r10にすれば良いんだと思う。r10は保存する必要ないからね。2件目は…

コンパイラ作成(39) バグ修正

バグ修正2件 最近バグ修正多いけどまた2件見つかっちゃったんで修正するよ。 // 関数 int main() { sub(); sub() + 10; 10 + sub(); } int sub() { puts("sub"); return 42; } 1件目は式中の関数呼出。この中のsub() + 10;がコンパイルできずに異常終了し…

コンパイラ作成(38) 比較演算子

今回の目標 比較演算子を増やすよ。 // 比較演算子 int main() { int a, b; int cmp; a = 6; b = 7; cmp = a < b; printf("cmp = %d\n",cmp); cmp = a < 6; printf("cmp = %d\n",cmp); cmp = a < 5; printf("cmp = %d\n",cmp); } 今回は比較演算子[,=]をサポ…

コンパイラ作成(37) 非等価演算子

今回の目標 比較演算子を増やすよ。 // 非等価演算子 int main() { int a, b; int cmp; a = 6; b = 7; cmp = a != b; printf("cmp = %d\n",cmp); cmp = a != 6; printf("cmp = %d\n",cmp); } 非等価演算子。 Lexerクラス まずはここから。 # symbolの切り出…

コンパイラ作成(36) バグ修正

バグ3件 比較演算子を追加しようと思ってたんだけど、その前にテストを色々やってたら、バグが3件も見つかったよ。 // 正しくない式 int main() { int a, b; != b; } 妙竹林な代入ね。コンパイルエラーにならずに、コンパイラが異常終了しちゃったよ。 // …

コンパイラ作成(35) if-else文

今日の目標 else付きのif文行ってみるよ。 // if文 int main() { int a; a = 0; if(a == 0) printf("%d is zero\n",a); else printf("%d is not zero\n",a); a = 1; if(a == 0) { printf("%d is zero\n",a); printf("%d is zero\n",a); } else { printf("%d …

コンパイラ作成(34) if文

今回の目標 変数関連は飽きたんでif文を追加してみるよ。 // if文 int main() { int i = 0; lp: printf("Hello, World!\n"); i = i + 1; if(i == 5) goto ret; goto lp; ret: return 0; } 一番簡単なif文。まずはここから。 initialize if文で自動生成するラ…

コンパイラ作成(33) 多重代入

今回の目標 今日は多重代入だよ。 // 多重代入 int main() { int a, b, c; a = b = c = 6 * 7; printf("a = %d\n",a); printf("b = %d\n",b); printf("c = %d\n",c); } 前回の変数の初期化より難しいのかな。 expr まずはここから。 # 式の構文解析 def expr…

コンパイラ作成(32) ローカル変数の初期化

今回の目標 前回積み残したのをちょっとずつやってくよ。 // 変数 int main() { int a = 6, b = 7; int answer = a * b; printf("Answer is %d\n",answer); } 今回は変数の初期化処理に対応するよ。 statement ここを修正。 elsif kind == TK::RESERVE && st…

コンパイラ作成(31) ローカル変数

今回の目標 変数のサポート頑張るよ。 // 変数 int main() { int answer; answer = 42; printf("Answer is %d\n",answer); } ローカル変数一個の単純な場合から始める。グローバル変数については当面放置かな。 デバッグ出力 本題に行く前に準備工作。 $opt_…

コンパイラ作成(30) 字句解析の機能追加

今回の目標 変数のサポートはちょっと考えてみたけど難しそうなんで別のことやることにしたよ。水は低い方に流れるってことで。 int main() { printf("Answer is %d\n",answer_hex()); } int answer_hex() { // Answer to the Ultimate Question of Life, th…

コンパイラ作成(29) printfのバグ修正

今回の目標 前回のバグの修正をするよ。 int main() { printf("Hello, World!\n"); printf("%s\n","Hello, World!"); printf("%d %d %d\n",1,2,3); printf("%d %d %d %d %d\n",1,2,3,4,5); printf("%d %d %d %d %d\n",1,2,3,4,2*5); } 最期のprintfがバグっ…

コンパイラ作成(28) printf

今回の目標 前回ABIについて調べなおしたんで、それを活かしてprintfに挑戦してみるよ。 int main() { printf("Hello, World!\n"); } printf版のハロワ。 Lexerクラス まずLexerを二箇所修正。 @reservedword = [ "return","goto","if","else","for","while"…

コンパイラ作成(27) System V AMD64 ABI

Application Binary Interface 今回はABIのお勉強だよ。なんとなくは知ってるんだけど、細かいことまでは把握できてなかったんで、ちゃんと調べてみる。 X86 psABI · hjl-tools/x86-psABI Wiki · GitHubからpdfを開いて見てみる。 3.2 Function Calling Sequ…

コンパイラ作成(26) Lexerクラス修正

moduletest 色々テストしてたらLexerにバグを見っけた。一件目はmoduletest。 # モジュールテスト def moduletest() i = 0 loop do i += 1 kind, str = gettoken # fname, lineno, pos = position # print fname,":",lineno,":",pos," " if kind == TK::EOF …