コンパイラ作成

コンパイラ作成(76) 浮動小数点数

今回はお勉強 char型のサポートが粗方終わったんで、次に何やるかって考えたよ。最初はshort型にしようかと思ったんだけど、やることはchar型と大体同じで詰まらないから、double型に手を出してみるよ。今まで浮動小数点数を使ったプログラミングはあんまり…

コンパイラ作成(75) char型の比較演算、単項マイナス演算

今回の目標 今回もchar型のサポートだよ。 // char型 int main() { char a = 11, b = 4; if( a == b ) printf("%hhu == %hhu\n", a, b); else printf("%hhu != %hhu\n", a, b); } // char型 int main() { char a = 11, b = -a; printf("a = %hhu b = %hhu\n"…

コンパイラ作成(74) char型の乗除余算

今回の目標 引き続きchar型のサポート。 // char型 int main() { char a = 11, b = 4, c; c = a * b; printf("%hhu * %hhu = %hhu\n", a, b, c); c = a / b; printf("%hhu / %hhu = %hhu\n", a, b, c); c = a % b; printf("%hhu %% %hhu = %hhu\n", a, b, c)…

コンパイラ作成(73) char型の加減算

今回の目標 char型のサポートを進めるよ。 // char型 int main() { char a = 10, b = 8, c; c = a + b; printf("%hhu + %hhu = %hhu\n", a, b, c); c = a - b; printf("%hhu - %hhu = %hhu\n", a, b, c); } 今回は加減算。 codegen_els # 式のコード生成(二…

コンパイラ作成(72) char型

今回の目標 char型のサポートを頑張るよ。 // char型 int main() { char ch = 'A'; // char ch = '\n'; printf("ch = %c\n",ch); } 今回は文字リテラルとchar型への代入と参照までだよ。一気にやるのはしんどいからちょっとずつ。 Lexerクラス まずは文字リ…

コンパイラ作成(71) ポインタのポインタ型

今回の目標 ポインタのポインタ型に対応するよ。 // 間接参照演算子 int main() { int a = 55; int *p = &a; int **pp = &p; printf("a = %d **pp = %d\n",a,**pp); **pp = 123; printf("a = %d **pp = %d\n",a,**pp); } 変数宣言と連続した単項演算子の扱い…

コンパイラ作成(70) ポインタ型とint型の演算

今回の目標 引き続きポインタ型のサポートを頑張るよ。 // int*型+int型 extern void *malloc(size_t size); extern void free(void *ptr); extern int puts(char *s); int main() { int *p = malloc(10*4); for(int i = 0; i < 10; i = i + 1) printf("p + …

コンパイラ作成(69) 間接参照演算子

今回の目標 前回の続きで間接参照演算子を追加するよ。 // 間接参照演算子 int main() { int a = 55; int *p = &a; printf("a = %d *p = %d\n",a,*p); *p = 123; printf("a = %d *p = %d\n",a,*p); } 右辺値の場合と左辺値の場合があるよ。 read_modify_el …

コンパイラ作成(68) int*型、アドレス演算子

今回の目標 アドレス演算子を追加するよ。 // アドレス演算子 int main() { int a = 55; int *p = &a; printf("p = %016lx\n",p); } それとint*型の対応も頑張るよ。char*型の時よりもうちょっと汎用的になるようにしたいなあ。 Lexerクラス まずは演算子の…

コンパイラ作成(67) for文での変数宣言

今回の目標 前回の続きでfor文の頭での変数宣言だよ。 // for文での変数宣言 extern int puts(char *str); int main() { int a = 10, b = 20; printf("1: a = %d b = %d\n",a,b); for(int i = 0; i < 3; i = i +1) { int a = 55; printf("2: a = %d b = %d\n…

コンパイラ作成(66) ブロック内での変数宣言

今回の目標 ブロック{...}を追加して、その中での変数宣言にも対応するよ。 // block中の変数宣言 extern int puts(char *str); int main() { int a = 10, b = 20; printf("1: a = %d b = %d\n",a,b); { int a = 55; printf("2: a = %d b = %d\n",a,b); } in…

コンパイラ作成(65) 剰余演算子

今回の目標 久々に演算子を追加するよ。 // 剰余 int main() { printf("17 * 4 = %d\n",17*4); printf("17 / 4 = %d\n",17/4); printf("17 % 4 = %d\n",17%4); } 剰余演算子だよ。 gettoken 修正いくよ。 # symbolの切り出し elsif m = @line[@idx,@line.len…

コンパイラ作成(64) printf

今回の目標 前回の続き。 // void*, size_t extern void *malloc(size_t size); int main() { char *buffer = malloc(256); printf("buffer = %016lx\n",buffer); } 何回も出てきたprintfだけど、このテストプログラムは上手くコンパイルできないよ。printf…

コンパイラ作成(63) void*型・size_t型

今回の目標 いきなりmalloc。いきなりvoid*。いきなりsize_t。 // void*, size_t extern void *malloc(size_t size); int main() { char *buffer = malloc(256); } mallocなら簡単に呼べるかと思ったんだけど、現実は厳しいよ。void*型はchar*型に置き換えち…

コンパイラ作成(62) 引数のチェック

今回の目標 関数コール時の引数の型・個数をチェックするよ。 // 誤った関数コール extern int add(int a, int b); int main() { int a = 5, b = 12, c; c = add(a,"must be int"); printf("%d + %d = %d\n",a,b,c); } // 誤った関数コール extern int add(i…

コンパイラ作成(61) 引数のある関数の修正

バグ テストをしてたらバグを見つけたよ。 main() { print(2 * 3 + 5); print(2 + 3 * 5); } これなんだけど、計算結果が合わない。 ~/myc$ myc -d i7.myc print.o [[print, (), [2, *, 3, +, 5]]] [[print, (), [2, *, 3, +, 5]]] [[print, (), [2, +, 3, *…

コンパイラ作成(60) 関数のextern宣言

今回の目標 いきなりだけどextern行ってみるよ。 // 関数のextern宣言 extern int add(int a, int b); int main() { int a = 5, b = 12, c; c = add(a,b); printf("%d + %d = %d\n",a,b,c); } 本来はextern宣言の場合、仮引数の名前は省略できるんだけど、面…

コンパイラ作成(59) char*型変数の代入・参照を修正

今回の目標 引き続きchar*型。 // char*型の変数 int main() { char *p = "Hello, World!"; puts(p); } これ前々回のテストプログラム。コンパイルできてちゃんと動いたんだけどさ、アセンブリコード見てて変なことに気が付いたよ。 .intel_syntax noprefix …

コンパイラ作成(58) char*型の値を返す関数

今回の目標 引き続きchar*型のサポートを頑張るよ。 // char*型を返す関数の呼び出し char *answer() { // Answer to the Ultimate Question of Life, the Universe, and Everything return "forty-two"; } int main() { puts(answer()); } 今回はchar*型を…

コンパイラ作成(57) char*型の変数

今回の目標 簡単にできそうなところからこつこつと。 // char*型の変数 int main() { char *p = "Hello, World!"; puts(p); } char*型の変数だよ。引数と大して違わないから簡単だと思う。 statement 変数の宣言部をちょこちょこっと修正。 elsif kind == TK…

コンパイラ作成(56) char*型+int型の式

今回の目標 型をミックスした式のサポートを頑張るよ。 // char* + int int main() { int i; for(i = 0; i < 10; i = i + 1) puts("Hello, World!" + i); } 前々回、char*型をサポートしたけど、対応が不十分なとこがいくつもあった。で、今回少しだけ改善す…

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

バグ いくつかテストをしてたらバグが見つかったよ。 // セミコロンがない int main() { sub() sub(); } int sub() { printf("sub\n"); return 0; } 関数コールの後ろのセミコロンが無い場合、コンパイラが異常終了しちゃってたよ。 modify_el ここを修正。 …

コンパイラ作成(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ってコードが出力されてたよ。これでも動くから問題ないんだけど、恰…