Skip to content

c compiler chains logs

hiromi-mi edited this page Mar 5, 2023 · 1 revision

hoge

作業ログ

8cc -> 9cc

- コンパイルは通るがテストが一部成功しない
- ソースコード変更なしでOK
hiromimi@tachyon:~/dev/compile/9cc$ ls -1 *.c | xargs -L 1 ../8cc/8cc -c 
hiromimi@tachyon:~/dev/compile/9cc$ make
cc -o 9cc gen_ir.o gen_x86.o irdump.o liveness.o main.o opt.o parse.o preprocess.o regalloc.o sema.o token.o util.o util_test.o 

test/test.c のコンパイルが通らない

hiromimi@tachyon:~/dev/compile/9cc$ make test
./9cc -test
error at test/test.c:7:269

#define EXPECT(expected, expr)                                    do {                                                              int e1 = (expected);                                            int e2 = (expr);                                                if (e1 == e2) {                                                   fprintf(stderr, "%s => %d\n", #expr, e2);                     } else {                                                          fprintf(stderr, "line %d: %s: %d expected, but got %d\n",               __LINE__, #expr, e1, e2);                               exit(1);                                                      }                                                             } while (0)
                                                                                                                                                                                                                                                                            ^

primary expression expected
make: *** [Makefile:12: test] エラー 1
- Hello, World を手元で作ったら (PIE周りのエラーを除き) 普通にビルドできたので、100%壊れているわけではない
- 9cc -> 8cc が通らないのに 8cc -> 9cc は通るのはおもしろい

9cc -> sk2cc

コンパイル不可

hiromimi@tachyon:~/dev/compile/sk2cc$ ../9cc/9cc_orig as_gen.c 
error at sk2cc.h:45:14

#define EOF (-1)
             ^

parameter name expected

関数形式マクロだと誤解していそう

chibicc -> hoc_nyan

ビルド+セルフホストOK。diffは以下の通り。

diff --git a/Makefile b/Makefile
index d2be0c9..146e957 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ build/g0/%.o : src/%.c src/hoc.h
        $(CC) $(CFLAGS) -c $< -o $@
 
 build/g1/%.s: src/%.c hoc
-       ./hoc $< > $@
+       ./hoc_chibicc $< > $@
 
 build_g1: $(G1_ASMS)
        $(CC) -g -static -o build/g1/hoc $(G1_ASMS) $(CFLAGS) $(LDFLAGS)
@@ -26,7 +26,7 @@ build_g2: $(G2_ASMS)
 
 test: hoc build_g1 build_g2 FORCE
        ./test.sh
-       ./hoc test/pp_test.c > test/pp_test.s
+       ./hoc_chibicc test/pp_test.c > test/pp_test.s
        $(CC) -g -static -o test/pp_test.out test/pp_test.s
        ./test/pp_test.out
 
diff --git a/test.sh b/test.sh
index 4655adb..91dad34 100755
--- a/test.sh
+++ b/test.sh
@@ -5,7 +5,7 @@ echo "~~~ gcc ~~~" &&
     ./test/tmp.out &&
     gcc -I./include -D__hoc__ -E -P test/test.c > test/tmp.c &&
     echo "~~~ generation 0 ~~~" &&
-    ./hoc test/tmp.c > test/tmp.s &&
+    ./hoc_chibicc test/tmp.c > test/tmp.s &&
     gcc -static -o test/tmp.out test/tmp.s &&
     ./test/tmp.out &&
     echo "~~~ generation 1 ~~~" &&

{8cc, 9cc, sk2cc} + gcc -E -D__hoc__ -> hoc_nyan

まず、以下を実行してビルド可能にする

  • $ for x in *.c; do gcc -E -D__hoc__ $x > ../src2/$x; done
  • $ sed -e "s/^# [0-9].*$//g" -i *.c

hoc_nyan -> 8cc

hiromimi@tachyon:~/dev/compile/hoc_nyan/src2$ ls -1 *.c | xargs -L 1 ../../8cc/8cc_gcc -S 
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: emit.c:468:11: assume returning int: va_start()
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: emit.c:480:11: assume returning int: va_start()
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: gen_x86.c:470:11: assume returning int: va_start()
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: parse.c:1273:2: type specifier missing, assuming int
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: parse.c:1282:2: type specifier missing, assuming int
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: utils.c:450:11: assume returning int: va_start()
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: utils.c:463:11: assume returning int: va_start()
[WARN] /home/hiromimi/dev/compile/8cc/8cc.h:427: utils.c:477:11: assume returning int: va_start()

hoc_nyan -> 9cc

  • $ ls -1 *.c | xargs -L 1 ../../9cc/9cc

動作しない

; expected
error at token.c:9:14

typedef long size_t;
             ^

; expected
error at utils.c:9:14

typedef long size_t;

hoc_nyan -> sk2cc

$ ls -1 *.c | xargs -L 1 ../../sk2cc/sk2cc

sema.c:454:41: error: invalid operand types. (at sema.c:866)
   for (GVar* gvar = prog->globals; gvar != 0; gvar = gvar->next) {
                                         ^
token.c:463:36: error: invalid operand types. (at sema.c:807)
   size_t len = strchr(start, '\n') - start;
                                    ^
utils.c:466:7: error: number of parameters should be 0, but got 1. (at sema.c:565)
   exit(1);
  • hsjoihs さんによるコメント:
    • 最初のは 「0 というリテラルは、ポインタの文脈の場合 null pointer となる」というのを検知していない部分がある
    • 次のはポインタ引くポインタ

C言語に標準規格があるのがいかに有用かがわかります 😇

chibicc -> 8cc

hiromimi@tachyon:~/dev/compile/8cc$ make
../chibicc/chibicc_orig    -c -o main.o main.c
../chibicc/chibicc_orig    -c -o cpp.o cpp.c
make: *** [<ビルトイン>: cpp.o] エラー 1

cpp.o が生成できていないので、試してみると

hiromimi@tachyon:~/dev/compile/8cc$ ../chibicc/chibicc_orig    -c -o cpp.o cpp.c
hiromimi@tachyon:~/dev/compile/8cc$ echo $?
1

メッセージもなく異常終了する
???
fork した子供プロセスがnull により停止していた

    // Regular struct member
    if (mem->name->len == tok->len && !strncmp(mem->name->loc, tok->loc, tok->len)) {
      *rest = tok->next;
      return mem;
    }
  }

ここの mem->name がNULL だった.

次のテストケースで再現できる. .sval = "1" が未実装.

typedef struct {
    //bool space;   // true if the token has a leading space
    int space;   // true if the token has a leading space
    //bool bol;     // true if the token is at the beginning of a line
    int bol;     // true if the token is at the beginning of a line
// 構造体中にboolが入るとだめ
    union { struct { char *sval; }; };
} Token;

int main() {
  ((Token){ .sval = "1" });

  printf("OK\n");
  return 0;
}

chibicc -> sk2cc

typedef struct __builtin_va_list va_list; としてみると:

../chibicc/chibicc  -o sk2cc vector.c string.c map.c binary.c error.c lex.c cpp.c parse.c sema.c gen.c cc.c as_error.c as_lex.c as_parse.c as_sema.c as_encode.c as_gen.c as.c main.c
binary.c:21:   va_list ap;
                       ^ variable has incomplete type
  • gccと他のコンパイラでの間の内部実装の違いがこんなところに現れるのだなあ

そのあと、いろいろとやったところビルドは通せた。diffは以下の通り。

diff --git a/Makefile b/Makefile
index f5be62d..3eae4f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
-CC = gcc
-CFLAGS = -std=c11 --pedantic-errors -Wall -Wstrict-prototypes -g
+#CC = gcc
+#CFLAGS = -std=c11 --pedantic-errors -Wall -Wstrict-prototypes -g -Wextra
+CC=../chibicc/chibicc
+CFLAGS=

 HEADERS = \
        string.h vector.h map.h binary.h \
diff --git a/sk2cc.h b/sk2cc.h
index 38f715f..7c61da6 100644
--- a/sk2cc.h
+++ b/sk2cc.h
@@ -30,11 +30,14 @@ typedef unsigned long long size_t;
 #define noreturn _Noreturn

 // stdarg.h
+#include <stdarg.h>
+/*
 #define va_start __builtin_va_start
 #define va_arg __builtin_va_arg
 #define va_end __builtin_va_end

 typedef __builtin_va_list va_list;
+*/

 // stdint.h
 typedef long int intptr_t;

Clone this wiki locally