Skip to content

Commit a2bac58

Browse files
committed
Devide 9cc.c -> main.c, parse.c, codegen.c, 9cc.h.
1 parent 5f18678 commit a2bac58

File tree

6 files changed

+176
-159
lines changed

6 files changed

+176
-159
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ tmp*
44
a.out
55
9cc
66
.git
7-
*.json
7+
*.json
8+
foo*

9cc.c

-158
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,7 @@
55
#include <stdlib.h>
66
#include <string.h>
77

8-
typedef enum {
9-
TK_RESERVED, // 記号
10-
TK_NUM, // 整数トークン
11-
TK_EOF, // 入力の終わりを表すトークン
12-
} TokenKind;
138

14-
typedef struct Token Token;
15-
16-
// トークン型
17-
struct Token {
18-
TokenKind kind; // トークンの型
19-
Token *next; // 次の入力トークン
20-
int val; // kindがTK_NUMの場合、その数値
21-
char *str; // トークン文字列
22-
int len; // トークンの長さ
23-
};
24-
25-
// 抽象構文木のノードの種類
26-
typedef enum {
27-
ND_ADD, // +
28-
ND_SUB, // -
29-
ND_MUL, // *
30-
ND_DIV, // /
31-
ND_EQ, // ==
32-
ND_NE, // !=
33-
ND_LT, // <
34-
ND_LE, // <=
35-
ND_NUM, // integer
36-
} NodeKind;
37-
38-
typedef struct Node Node;
39-
40-
struct Node {
41-
NodeKind kind; // ノードの型
42-
Node *lhs; // 左辺 left-hand side
43-
Node *rhs; // 右辺 right-hand side
44-
int val; // kindがND_NUMの場合のみ使う
45-
};
46-
47-
// 現在着目しているトークン
48-
Token *token;
49-
char *user_input;
509

5110
// エラーを報告するための関数
5211
// printfと同じ引数を取る
@@ -111,46 +70,6 @@ bool startswith(char *p, char *q) {
11170
return memcmp(p, q, strlen(q)) == 0;
11271
}
11372

114-
// 新しいトークンを作成してcurに繋げる
115-
Token *tokenize() {
116-
char *p = user_input;
117-
Token head;
118-
head.next = NULL;
119-
Token *cur = &head;
120-
121-
while (*p) {
122-
if (isspace(*p)) {
123-
p++;
124-
continue;
125-
}
126-
127-
if (startswith(p, "==") || startswith(p, "!=") ||
128-
startswith(p, "<=") || startswith(p, ">=")) {
129-
cur = new_token(TK_RESERVED, cur, p, 2);
130-
p += 2;
131-
continue;
132-
}
133-
134-
if (strchr("+-*/()<>", *p)) {
135-
cur = new_token(TK_RESERVED, cur, p++, 1);
136-
continue;
137-
}
138-
139-
if (isdigit(*p)) {
140-
cur = new_token(TK_NUM, cur, p, 0);
141-
char *q = p;
142-
cur->val = strtol(p, &p, 10);
143-
cur->len = p - q;
144-
continue;
145-
}
146-
147-
error_at(p, "invalid token");
148-
}
149-
150-
new_token(TK_EOF, cur, p, 0);
151-
return head.next;
152-
}
153-
15473
Node *new_node(NodeKind kind, Node *lhs, Node *rhs) {
15574
Node *node = calloc(1, sizeof(Node));
15675
node->kind = kind;
@@ -259,80 +178,3 @@ Node *primary() {
259178
return new_node_num(expect_number());
260179
}
261180

262-
// x86-64のスタック操作命令を使って,スタックマシンを模倣するアセンブリを吐く関数
263-
void gen(Node *node) {
264-
if (node->kind == ND_NUM) {
265-
printf(" push %d\n", node->val);
266-
return;
267-
}
268-
269-
gen(node->lhs);
270-
gen(node->rhs);
271-
272-
printf(" pop rdi\n");
273-
printf(" pop rax\n");
274-
275-
switch (node->kind) {
276-
case ND_EQ:
277-
printf(" cmp rax, rdi\n");
278-
printf(" sete al\n");
279-
printf(" movzb rax, al\n");
280-
break;
281-
case ND_NE:
282-
printf(" cmp rax, rdi\n");
283-
printf(" setne al\n");
284-
printf(" movzb rax, al\n");
285-
break;
286-
case ND_LT:
287-
printf(" cmp rax, rdi\n");
288-
printf(" setl al\n");
289-
printf(" movzb rax, al\n");
290-
break;
291-
case ND_LE:
292-
printf(" cmp rax, rdi\n");
293-
printf(" setle al\n");
294-
printf(" movzb rax, al\n");
295-
break;
296-
case ND_ADD:
297-
printf(" add rax, rdi\n");
298-
break;
299-
case ND_SUB:
300-
printf(" sub rax, rdi\n");
301-
break;
302-
case ND_MUL:
303-
printf(" imul rax, rdi\n");
304-
break;
305-
case ND_DIV:
306-
printf(" cqo\n");
307-
printf(" idiv rdi\n");
308-
break;
309-
}
310-
311-
printf(" push rax\n");
312-
}
313-
314-
int main(int argc, char **argv) {
315-
if (argc != 2) {
316-
error_at(argv[1], "引数の個数が正しくありません");
317-
return 1;
318-
}
319-
// トークナイズしてパースする
320-
user_input = argv[1];
321-
token = tokenize();
322-
Node *node = expr();
323-
324-
// アセンブリの前半部分を出力
325-
printf(".intel_syntax noprefix\n");
326-
printf(".globl main\n");
327-
printf("main:\n");
328-
329-
// 抽象構文木を下りながらコード生成
330-
gen(node);
331-
332-
// スタックトップに式全体の値が残っているはずなので
333-
// それをRAXにロードして関数からの返り値とする
334-
printf(" pop rax\n");
335-
printf(" ret\n");
336-
return 0;
337-
}
338-

9cc.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//----------------------------------------------------------------------
2+
// 型宣言(Type declaration)
3+
//----------------------------------------------------------------------
4+
5+
typedef enum {
6+
TK_RESERVED, // 記号
7+
TK_NUM, // 整数トークン
8+
TK_EOF, // 入力の終わりを表すトークン
9+
} TokenKind;
10+
11+
typedef struct Token Token;
12+
13+
// トークン型
14+
struct Token {
15+
TokenKind kind; // トークンの型
16+
Token *next; // 次の入力トークン
17+
int val; // kindがTK_NUMの場合、その数値
18+
char *str; // トークン文字列
19+
int len; // トークンの長さ
20+
};
21+
22+
// 抽象構文木のノードの種類
23+
typedef enum {
24+
ND_ADD, // +
25+
ND_SUB, // -
26+
ND_MUL, // *
27+
ND_DIV, // /
28+
ND_EQ, // ==
29+
ND_NE, // !=
30+
ND_LT, // <
31+
ND_LE, // <=
32+
ND_NUM, // integer
33+
} NodeKind;
34+
35+
typedef struct Node Node;
36+
37+
struct Node {
38+
NodeKind kind; // ノードの型
39+
Node *lhs; // 左辺 left-hand side
40+
Node *rhs; // 右辺 right-hand side
41+
int val; // kindがND_NUMの場合のみ使う
42+
};
43+
44+
// 現在着目しているトークン
45+
Token *token;
46+
char *user_input;
47+
48+
//----------------------------------------------------------------------
49+
// プロトタイプ宣言(Prototype declaration)
50+
//----------------------------------------------------------------------
51+
void error_at(char *loc, char *fmt, ...);

codegen.c

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <9cc.h>
2+
3+
// x86-64のスタック操作命令を使って,スタックマシンを模倣するアセンブリを吐く関数
4+
void gen(Node *node) {
5+
if (node->kind == ND_NUM) {
6+
printf(" push %d\n", node->val);
7+
return;
8+
}
9+
10+
gen(node->lhs);
11+
gen(node->rhs);
12+
13+
printf(" pop rdi\n");
14+
printf(" pop rax\n");
15+
16+
switch (node->kind) {
17+
case ND_EQ:
18+
printf(" cmp rax, rdi\n");
19+
printf(" sete al\n");
20+
printf(" movzb rax, al\n");
21+
break;
22+
case ND_NE:
23+
printf(" cmp rax, rdi\n");
24+
printf(" setne al\n");
25+
printf(" movzb rax, al\n");
26+
break;
27+
case ND_LT:
28+
printf(" cmp rax, rdi\n");
29+
printf(" setl al\n");
30+
printf(" movzb rax, al\n");
31+
break;
32+
case ND_LE:
33+
printf(" cmp rax, rdi\n");
34+
printf(" setle al\n");
35+
printf(" movzb rax, al\n");
36+
break;
37+
case ND_ADD:
38+
printf(" add rax, rdi\n");
39+
break;
40+
case ND_SUB:
41+
printf(" sub rax, rdi\n");
42+
break;
43+
case ND_MUL:
44+
printf(" imul rax, rdi\n");
45+
break;
46+
case ND_DIV:
47+
printf(" cqo\n");
48+
printf(" idiv rdi\n");
49+
break;
50+
}
51+
52+
printf(" push rax\n");
53+
}
54+

main.c

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <9cc.h>
2+
3+
int main(int argc, char **argv) {
4+
if (argc != 2) {
5+
error_at(argv[1], "引数の個数が正しくありません");
6+
return 1;
7+
}
8+
// トークナイズしてパースする
9+
user_input = argv[1];
10+
token = tokenize();
11+
Node *node = expr();
12+
13+
// アセンブリの前半部分を出力
14+
printf(".intel_syntax noprefix\n");
15+
printf(".globl main\n");
16+
printf("main:\n");
17+
18+
// 抽象構文木を下りながらコード生成
19+
gen(node);
20+
21+
// スタックトップに式全体の値が残っているはずなので
22+
// それをRAXにロードして関数からの返り値とする
23+
printf(" pop rax\n");
24+
printf(" ret\n");
25+
return 0;
26+
}
27+

parse.c

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <9cc.h>
2+
3+
// 新しいトークンを作成してcurに繋げる
4+
Token *tokenize() {
5+
char *p = user_input;
6+
Token head;
7+
head.next = NULL;
8+
Token *cur = &head;
9+
10+
while (*p) {
11+
if (isspace(*p)) {
12+
p++;
13+
continue;
14+
}
15+
16+
if (startswith(p, "==") || startswith(p, "!=") ||
17+
startswith(p, "<=") || startswith(p, ">=")) {
18+
cur = new_token(TK_RESERVED, cur, p, 2);
19+
p += 2;
20+
continue;
21+
}
22+
23+
if (strchr("+-*/()<>", *p)) {
24+
cur = new_token(TK_RESERVED, cur, p++, 1);
25+
continue;
26+
}
27+
28+
if (isdigit(*p)) {
29+
cur = new_token(TK_NUM, cur, p, 0);
30+
char *q = p;
31+
cur->val = strtol(p, &p, 10);
32+
cur->len = p - q;
33+
continue;
34+
}
35+
36+
error_at(p, "invalid token");
37+
}
38+
39+
new_token(TK_EOF, cur, p, 0);
40+
return head.next;
41+
}
42+

0 commit comments

Comments
 (0)