コンパイラ作成日記 1日目

まとまった時間がとれたのでこれに挑戦する。

低レイヤを知りたい人のためのCコンパイラ作成入門

環境構築

M1 Mac編

M1 Mac で動くかどうかは書いていなかったのでとりあえず環境構築やってみた。

MacではDockerを使えとあったので、付録3に沿ってやってみた。

しかし、M1Macでは途中までは開発進めることができたが以下のエラーで詰まってしまった。

$ cc -o tmp tmp.s
tmp.s: Assembler messages:
tmp.s:1: Error: unknown pseudo-op: `.intel_syntax'
tmp.s:4: Error: operand 1 must be an integer register -- `mov rax,123'

思いっきり intel_syntax って書いてあるな 😇

あきらめて Intel Mac で開発する

Intel Mac編

Dockerのインストールから必要だった。

# docker install
$ brew install --cask docker

# 使うイメージをビルド
$ docker build -t compilerbook https://www.sigbus.info/compilerbook/Dockerfile

ちなみにこの Dockerfile 中身を見たがそんなたいしたことはしていなかった。

$ curl https://www.sigbus.info/compilerbook/Dockerfile
FROM ubuntu:latest
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive apt install -y gcc make git binutils libc6-dev gdb sudo
RUN adduser --disabled-password --gecos '' user
RUN echo 'user ALL=(root) NOPASSWD:ALL' > /etc/sudoers.d/user
USER user
WORKDIR /home/user

これで開発スタートできる。


ステップ1:整数1個をコンパイルする言語の作成

動かしてみる

最初はなにもわからないので写経してすすめていく。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  if (argc != 2) {
    fprintf(stderr, "引数の個数が正しくありません\n");
    return 1;
  }

  printf(".intel_syntax noprefix\n");
  printf(".globl main\n");
  printf("main:\n");
  printf("  mov rax, %d\n", atoi(argv[1]));
  printf("  ret\n");
  return 0;
}

このコードを動かしてみる。

$ cc -o 9cc 9cc.c
$ ./9cc 123 > tmp.s
$ cat tmp.s
.intel_syntax noprefix
.globl main
main:
  mov rax, 123
  ret
$ cc -o tmp tmp.s
$ ./tmp
$ echo $?
123

動いた!!!。大学の授業などで最初にやる Hello World! を思い出す。

教本に以下のことが書かれている。

0〜255の範囲の123以外の数を与えてみて(Unixのプロセス終了コードは0〜255ということになっています)

というわけで範囲外の数字を input してみる。

$ ./9cc 1000 > tmp.s
$ cc -o tmp tmp.s
$ ./tmp
$ echo $?
232

今時点だとなぜこうなるのかわからないが範囲外のものを input するとエラーで止まるのではなく変な挙動になることがわかった。

自動テストの作成

テスト大事。最初にテストまであるのはとても親切。

make によるビルド

あんまり Makefile 書くことがなかったので .PHONY というのは知らなかった。調べてみるとこれはダミー値で、サブコマンドとディレクトリやファイルと一致したときに動かなくなるのを想定して用意されているようだ。


疲れたので1日目はここまで。久しぶりになにもわからない世界に入って楽しい!!