学習範囲
ステップ2:加減算のできるコンパイラの作成
まとめ
- 前回との違いとして、+(プラス)や-(マイナス)を判別して、加算減算をできるようになった
今回の学習内容が完璧にわかるコード振り返り
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) { // 引数の個数と値を受け取る
if (argc != 2) { // 引数の個数が2個でない場合(1個目はファイル名)
fprintf(stderr, "引数の個数が正しくありません\n");
return 1;
}
char *p = argv[1]; // 5+20-4のような文字列を受け取る
printf(".intel_syntax noprefix\n");
printf(".globl main\n");
printf("main:\n");
printf(" mov rax, %ld\n", strtol(p, &p, 10)); // 5をraxに代入、pは次の文字列である+を指す
while (*p) {
if (*p == '+') {
p++; // 1文字進める
printf(" add rax, %ld\n", strtol(p, &p, 10)); // strtolにより2は20に変換される
continue;
// +20のような文字列を受け取り、add rax, 20を出力する
}
if (*p == '-') {
p++;
printf(" sub rax, %ld\n", strtol(p, &p, 10));
continue;
}
fprintf(stderr, "予期しない文字です: '%c'\n", *p);
return 1;
}
printf(" ret\n"); // *pが終端文字の場合、retを出力する
return 0;
}
実行結果
test.shにassert 22 "5+21-4"
と記入make test
の実行結果
docker run -it -v /Users/ikuzawakazushi/9cc:/9cc -w /9cc compilerbook ./test.sh
/usr/bin/ld: warning: /tmp/cc9SCq0c.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
5+21-4 => 22
OK
/usr/bin/ld: warning:〜``/usr/bin/ld: NOTE: 〜
部分は無視していいらしい
どのような時にエラーになるか
5 +21-4
のように文字の後に空白がある場合は空白を読み込めないのでエラーになる。
しかし5+21- 4
のように文字の前に空白がある場合はstrtolの仕様で、数字が出るまで空白部分を潰してくれるためエラーにならず、テストが通る。
メモ
- atoi→文字ストリングを整数値に変換
- strtol→文字をlong型に変換する(string to long)。連続する数字部分を1つの数値として解釈される。
- stderr→標準エラー。何も指定しない場合に、システムで用意してあるエラーを表示。
- fprintf→printfの出力先が指摘できるようにしたやつ。stdoutを指定すればprintfと挙動は一緒になる。stderrを指定すればエラーを出力する。
- %ld→10進数として入力する
- argc→引数の数
- **argv→argv[0]には必ずパスを含めたファイル名が入る。argv[1]には1つめの引数。今回の場合はargv[1]は5+20-4のこと
所感
- ようやく計算のようなものができるようになり、小さくはあるが達成感があった。
- C言語で用意されている構文を把握しておかないと、流れが微妙にわからないところがある。strtolで2を読み込んで20に変換してくれることを知らず「2を読み込んだ0読み込んだら+でも-でもないからエラーにならないか?」と思ったので、こういった疑問をもち、構文についての知識を深めよう。