Skip to content

Commit 479a6a2

Browse files
committed
Add limited local var, but the bug need to be fixed; where is global var 'token'?
1 parent 0df1c4f commit 479a6a2

7 files changed

Lines changed: 132 additions & 46 deletions

File tree

9cc

5.24 KB
Binary file not shown.

9cc.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
//----------------------------------------------------------------------
1010
// 型宣言(Type declaration)
1111
//----------------------------------------------------------------------
12+
typedef struct Token Token;
1213

1314
typedef enum {
1415
TK_RESERVED, // 記号
16+
TK_IDENT, // 識別子
1517
TK_NUM, // 整数トークン
1618
TK_EOF, // 入力の終わりを表すトークン
1719
} TokenKind;
1820

19-
typedef struct Token Token;
2021

2122
// トークン型
2223
struct Token {
@@ -33,6 +34,8 @@ typedef enum {
3334
ND_SUB, // -
3435
ND_MUL, // *
3536
ND_DIV, // /
37+
ND_ASSIGN, // =
38+
ND_LVAR, // ローカル変数
3639
ND_EQ, // ==
3740
ND_NE, // !=
3841
ND_LT, // <
@@ -47,30 +50,42 @@ struct Node {
4750
Node *lhs; // 左辺 left-hand side
4851
Node *rhs; // 右辺 right-hand side
4952
int val; // kindがND_NUMの場合のみ使う
53+
int offset; // kindがND_LVARの場合のみ使う
54+
// ローカル変数のRBPからのオフセット
5055
};
5156

5257
// 現在着目しているトークン
5358
Token *token;
5459
char *user_input;
60+
Node *code[100];
5561

5662
//----------------------------------------------------------------------
5763
// プロトタイプ宣言(Prototype declaration)
5864
//----------------------------------------------------------------------
65+
void error(char *fmt, ...);
5966
void error_at(char *loc, char *fmt, ...);
6067
bool consume(char *op);
68+
Token *consume_ident();
6169
void expect(char *op);
6270
int expect_number();
6371
bool at_eof();
6472
Token *new_token(TokenKind kind, Token *cur, char *str, int len);
6573
bool startswith(char *p, char *q);
6674
Node *new_node(NodeKind kind, Node *lhs, Node *rhs);
6775
Node *new_node_num(int val);
76+
77+
void program();
78+
Node *stmt();
6879
Node *expr();
80+
Node *assign();
81+
Node *equality();
6982
Node *equality();
7083
Node *relational();
7184
Node *add();
7285
Node *mul();
7386
Node *unary();
7487
Node *primary();
7588
Token *tokenize();
89+
90+
void gen_lval(Node *node);
7691
void gen(Node *node);

codegen.c

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,43 @@
66
#include <stdlib.h>
77
#include <string.h>
88

9+
// program = stmt*
10+
// stmt = expr ";"
11+
// expr = assign
12+
// assign = equality ("=" assign)?
13+
// equality = relational ("==" relational | "!=" relational)
14+
// relational = add ("<" add | "<=" add | ">" add | ">=" add)*
15+
// add = mul ("+" mul | "-" mul)*
16+
// mul = unary ("*" unary | "/" unary)*
17+
// unary = ("+" | "-")? primary
18+
// primary = num | ident | "(" expr ")"
19+
20+
// program = stmt*
21+
void program() {
22+
int i = 0;
23+
while (!at_eof())
24+
code[i++] = stmt();
25+
code[i] = NULL;
26+
}
27+
28+
// stmt = expr ";"
29+
Node *stmt() {
30+
Node *node = expr();
31+
expect(";");
32+
return node;
33+
}
34+
35+
// expr = assign
936
Node *expr() {
10-
return equality();
37+
return assign();
38+
}
39+
40+
// assign = equality ("=" assign)?
41+
Node *assign() {
42+
Node *node = equality();
43+
if (consume("="))
44+
node = new_node(ND_ASSIGN, node, assign());
45+
return node;
1146
}
1247

1348
// equality = relatinal ("==" relational | "!=" relational)
@@ -87,17 +122,49 @@ Node *primary() {
87122
return node;
88123
}
89124

125+
Token *tok = consume_ident();
126+
if (tok) {
127+
// 次のトークンが識別子なら、それは変数のはず
128+
Node *node = calloc(1, sizeof(Node));
129+
node->kind = ND_LVAR;
130+
node->offset = (tok->str[0] - 'a' + 1) * 8;
131+
return node;
132+
}
133+
90134
// そうでなければ数値のはず
91135
return new_node_num(expect_number());
92136
}
93137

138+
void gen_lval(Node *node) {
139+
if (node->kind != ND_LVAR)
140+
error("代入の左辺値が変数ではありません");
94141

142+
printf(" mov rax, rbp");
143+
printf(" sub rax, %d\n", node->offset);
144+
printf(" push rax\n");
145+
}
95146

96147
// x86-64のスタック操作命令を使って,スタックマシンを模倣するアセンブリを吐く関数
97148
void gen(Node *node) {
98-
if (node->kind == ND_NUM) {
149+
switch (node->kind) {
150+
case ND_NUM:
99151
printf(" push %d\n", node->val);
100152
return;
153+
case ND_LVAR:
154+
gen_lval(node);
155+
printf(" pop rax\n");
156+
printf(" mov rax, [rax]\n");
157+
printf(" push rax\n");
158+
return;
159+
case ND_ASSIGN:
160+
gen_lval(node->lhs);
161+
gen(node->rhs);
162+
163+
printf(" pop rdi\n");
164+
printf(" pop rax\n");
165+
printf(" mov [rax], rdi\n");
166+
printf(" push rdi\n");
167+
return;
101168
}
102169

103170
gen(node->lhs);
@@ -107,26 +174,6 @@ void gen(Node *node) {
107174
printf(" pop rax\n");
108175

109176
switch (node->kind) {
110-
case ND_EQ:
111-
printf(" cmp rax, rdi\n");
112-
printf(" sete al\n");
113-
printf(" movzb rax, al\n");
114-
break;
115-
case ND_NE:
116-
printf(" cmp rax, rdi\n");
117-
printf(" setne al\n");
118-
printf(" movzb rax, al\n");
119-
break;
120-
case ND_LT:
121-
printf(" cmp rax, rdi\n");
122-
printf(" setl al\n");
123-
printf(" movzb rax, al\n");
124-
break;
125-
case ND_LE:
126-
printf(" cmp rax, rdi\n");
127-
printf(" setle al\n");
128-
printf(" movzb rax, al\n");
129-
break;
130177
case ND_ADD:
131178
printf(" add rax, rdi\n");
132179
break;

main.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
#include <stdlib.h>
77
#include <string.h>
88

9+
// エラーを報告するための関数
10+
void error(char *fmt, ...) {
11+
va_list ap;
12+
va_start(ap, fmt);
13+
vfprintf(stderr, fmt, ap);
14+
fprintf(stderr, fmt, ap);
15+
exit(1);
16+
}
17+
918
// エラーを報告するための関数
1019
// printfと同じ引数を取る
1120
void error_at(char *loc, char *fmt, ...) {
@@ -30,18 +39,30 @@ int main(int argc, char **argv) {
3039
// トークナイズしてパースする
3140
user_input = argv[1];
3241
token = tokenize();
33-
Node *node = expr();
42+
program();
3443

3544
// アセンブリの前半部分を出力
3645
printf(".intel_syntax noprefix\n");
3746
printf(".globl main\n");
3847
printf("main:\n");
3948

40-
// 抽象構文木を下りながらコード生成
41-
gen(node);
49+
// プロローグ
50+
// 変数26個分の領域を確保する
51+
printf(" push rbp\n");
52+
printf(" mov rbp, rsp\n");
53+
printf(" sub rsp, 208\n");
54+
55+
// 先頭の式から順にコード生成
56+
for (int i = 0; code[i]; i++) {
57+
gen(code[i]);
58+
59+
// 式の評価結果としてスタックに1つの値が残っているはずなので
60+
// それをスタックトップから取り除くためのPOP命令を出力
61+
printf(" pop rax\n");
62+
}
4263

43-
// スタックトップに式全体の値が残っているはずなので
44-
// それをRAXにロードして関数からの返り値とする
64+
// 最後の式の結果がRAXに残っているのでそれを返り値とする
65+
printf(" mov rsp, rbp\n");
4566
printf(" pop rax\n");
4667
printf(" ret\n");
4768
return 0;

parse.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ bool consume(char *op) {
1717
return true;
1818
}
1919

20+
Token *consume_ident() {
21+
if (token->kind != TK_IDENT)
22+
return NULL;
23+
Token *t = token;
24+
token = token->next;
25+
return t;
26+
}
27+
2028
// 次のトークンが期待している記号のときには、トークンを1つ読み進める。
2129
// それ以外の場合にはエラーを報告する。
2230
void expect(char *op) {
@@ -37,19 +45,19 @@ int expect_number() {
3745
return val;
3846
}
3947

40-
bool at_eof() {
41-
return token->kind == TK_EOF;
42-
}
43-
4448
Token *new_token(TokenKind kind, Token *cur, char *str, int len) {
4549
Token *tok = calloc(1, sizeof(Token));
4650
tok->kind = kind;
4751
tok->str = str;
48-
cur->next = tok;
4952
tok->len = len;
53+
cur->next = tok;
5054
return tok;
5155
}
5256

57+
bool at_eof() {
58+
return token->kind == TK_EOF;
59+
}
60+
5361
bool startswith(char *p, char *q) {
5462
return memcmp(p, q, strlen(q)) == 0;
5563
}
@@ -90,6 +98,11 @@ Token *tokenize() {
9098
continue;
9199
}
92100

101+
if ('a' <= *p && *p <= 'z') {
102+
cur = new_token(TK_IDENT, cur, p++, 1);
103+
continue;
104+
}
105+
93106
if (strchr("+-*/()<>", *p)) {
94107
cur = new_token(TK_RESERVED, cur, p++, 1);
95108
continue;

test.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,7 @@ assert 1 '1>=1'
4343
assert 0 '1>=2'
4444
assert 1 '15>=1'
4545

46+
assert 3 'a=3; a'
47+
assert 8 'a=3; z=5; a+z'
48+
4649
echo OK

tmp.s

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +0,0 @@
1-
.intel_syntax noprefix
2-
.globl main
3-
main:
4-
push 1
5-
push 15
6-
pop rdi
7-
pop rax
8-
cmp rax, rdi
9-
setle al
10-
movzb rax, al
11-
push rax
12-
pop rax
13-
ret

0 commit comments

Comments
 (0)