From 4681e861efcdf9b0b73e3803e70712bc55162863 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 8 Aug 2026 10:38:18 +0900 Subject: feat(slides): improve slide controller --- .../make-tiny-self-hosted-c-compiler/index.html | 80 ++++++++++++---------- 1 file changed, 42 insertions(+), 38 deletions(-) (limited to 'services/nuldoc/public/blog/posts/2025-05-05') diff --git a/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html b/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html index a5bbbcea..cef5c6e1 100644 --- a/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html +++ b/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html @@ -15,7 +15,7 @@ セルフホスト可能な C コンパイラを作った|REPL: Rest-Eat-Program Loop - +
@@ -359,9 +359,10 @@ compilerbook では整数一つのパース・コード生成から始めるが、今回は以下のようなソースをパースしてコード生成するところからスタートすることにした。

-
int main() { -
return 42; -
}
+
int main() {
+    return 42;
+}
+

この時点で、struct Tokenstruct Parserstruct AstNodestruct CodeGen といった主要なデータ構造が定義され、この後もほぼ同じソース設計のまま進めている。 @@ -408,23 +409,24 @@ 一日の終わりには、次のようなプログラムのテストが通るようになった。

-
int printf(); -
-
int main() { -
int i; -
for (i = 1; i <= 100; i = i + 1) { -
if (i % 15 == 0) { -
printf("FizzBuzz\n"); -
} else if (i % 3 == 0) { -
printf("Fizz\n"); -
} else if (i % 5 == 0) { -
printf("Buzz\n"); -
} else { -
printf("%d\n", i); -
} -
} -
return 0; -
}
+
int printf();
+
+int main() {
+    int i;
+    for (i = 1; i <= 100; i = i + 1) {
+        if (i % 15 == 0) {
+            printf("FizzBuzz\n");
+        } else if (i % 3 == 0) {
+            printf("Fizz\n");
+        } else if (i % 5 == 0) {
+            printf("Buzz\n");
+        } else {
+            printf("%d\n", i);
+        }
+    }
+    return 0;
+}
+
@@ -513,13 +515,14 @@ 記念すべき (?) 最後のバグはこちら。

-
gen_expr(g, ast->expr1, GEN_RVAL); -
} else { -
gen_expr(g, ast->expr1, GEN_RVAL); -
- gen_lval2rval(ast->expr1->ty); -
+ gen_lval2rval(ast->expr1->ty->to); -
} -
}
+
         gen_expr(g, ast->expr1, GEN_RVAL);
+     } else {
+         gen_expr(g, ast->expr1, GEN_RVAL);
+-        gen_lval2rval(ast->expr1->ty);
++        gen_lval2rval(ast->expr1->ty->to);
+     }
+ }
+

メモリアドレスから参照先の値を得る際、その型によってロードする命令の種類を変える必要があるのだが、その切替をポインタ型でおこなっていた。正しくは、そのポインタ型が指す型を元にして切り替えなければならない。 @@ -534,16 +537,17 @@ 一体どこが異なるのか。hexdump の差分がこちら。

-
$ diff -u <(hexdump -C p4dcc2) <(hexdump -C p4dcc3) -
@@ -5090,7 +5090,7 @@ -
00015db0 72 72 61 79 5f 65 6e 74 72 79 00 66 72 61 6d 65 |rray_entry.frame| -
00015dc0 5f 64 75 6d 6d 79 00 5f 5f 66 72 61 6d 65 5f 64 |_dummy.__frame_d| -
00015dd0 75 6d 6d 79 5f 69 6e 69 74 5f 61 72 72 61 79 5f |ummy_init_array_| -
-00015de0 65 6e 74 72 79 00 63 63 6d 69 42 49 59 6b 2e 6f |entry.ccmiBIYk.o| -
+00015de0 65 6e 74 72 79 00 63 63 53 71 64 47 76 57 2e 6f |entry.ccSqdGvW.o| -
00015df0 00 66 61 74 61 6c 5f 65 72 72 6f 72 00 72 65 61 |.fatal_error.rea| -
00015e00 64 5f 61 6c 6c 00 74 6f 6b 65 6e 69 7a 65 00 74 |d_all.tokenize.t| -
00015e10 79 70 65 5f 6e 65 77 00 74 79 70 65 5f 6e 65 77 |ype_new.type_new|
+
$ diff -u <(hexdump -C p4dcc2) <(hexdump -C p4dcc3)
+@@ -5090,7 +5090,7 @@
+ 00015db0  72 72 61 79 5f 65 6e 74  72 79 00 66 72 61 6d 65  |rray_entry.frame|
+ 00015dc0  5f 64 75 6d 6d 79 00 5f  5f 66 72 61 6d 65 5f 64  |_dummy.__frame_d|
+ 00015dd0  75 6d 6d 79 5f 69 6e 69  74 5f 61 72 72 61 79 5f  |ummy_init_array_|
+-00015de0  65 6e 74 72 79 00 63 63  6d 69 42 49 59 6b 2e 6f  |entry.ccmiBIYk.o|
++00015de0  65 6e 74 72 79 00 63 63  53 71 64 47 76 57 2e 6f  |entry.ccSqdGvW.o|
+ 00015df0  00 66 61 74 61 6c 5f 65  72 72 6f 72 00 72 65 61  |.fatal_error.rea|
+ 00015e00  64 5f 61 6c 6c 00 74 6f  6b 65 6e 69 7a 65 00 74  |d_all.tokenize.t|
+ 00015e10  79 70 65 5f 6e 65 77 00  74 79 70 65 5f 6e 65 77  |ype_new.type_new|
+

fatal_errorread_alltokenize type_new はいずれも main.c で定義された関数の名前である。このことから考えると、これは GCC が埋め込んだシンボルテーブルである可能性が高い。わずかに異なっている 6バイトは、ランダム生成された何かのように見える。 -- cgit v1.3.1