Skip to content

Commit

Permalink
Merge pull request #4 from nac-39/step12-add-control-structures
Browse files Browse the repository at this point in the history
Step12 add control structures: if文を追加
  • Loading branch information
nac-39 committed Aug 21, 2023
2 parents a55c1cf + 21748c9 commit 3e87a1f
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 75 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Expand Up @@ -58,4 +58,6 @@ bin/
tmp*
a.out
9cc
log/*
log/*
.DS_Store

2 changes: 2 additions & 0 deletions README.md
@@ -1,2 +1,4 @@
# compilerbook
https://www.sigbus.info/compilerbook を進める

ステップ9からのメモ: https://nac-39.notion.site/a4c0e27f2568426db1ee5a3cec8282ea?pvs=25
8 changes: 8 additions & 0 deletions src/9cc.h
Expand Up @@ -28,6 +28,8 @@ typedef enum {
TK_NUM, // 整数トークン
TK_EOF, // 入力の終わりを表すトークン
TK_RETURN, // return
TK_IF, // if
TK_ELSE, // else
} TokenKind;

typedef struct Token Token;
Expand All @@ -54,7 +56,9 @@ typedef enum {
ND_NUM, // 整数
ND_ASSIGN, // =
ND_LVAR, // ローカル変数
ND_IF, // if
ND_RETURN, // return
ND_ELSE, // else
} NodeKind;

typedef struct LVar LVar;
Expand All @@ -78,6 +82,7 @@ struct Node {
NodeKind kind; // ノードの方
Node *lhs; // 左辺
Node *rhs; // 右辺
Node *els; // else節にのみ使う
int val; // kindがND_NUMの場合のみ使う
int offset; // kindがND_LVAR(ローカル変数)の場合のみ使う。ローカル変数のベースポインタからの オフセットを表す。
};
Expand Down Expand Up @@ -122,3 +127,6 @@ extern FILE *log_file;

// ローカル変数
extern LVar *locals;

// if文のインデックス
extern int if_index;
140 changes: 82 additions & 58 deletions src/codegen.c
@@ -1,40 +1,64 @@
#include "9cc.h"

void gen_lval(Node *node) {
if (node->kind != ND_LVAR) error("代入の左辺値が変数ではありません");
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
if (node->kind != ND_LVAR)
error("代入の左辺値が変数ではありません");
printf(" mov rax, rbp\n");
printf(" sub rax, %d\n", node->offset);
printf(" push rax\n");
}

void gen(Node *node) {
if(node->kind == ND_RETURN) {
gen(node->lhs);
printf(" pop rax\n");
printf(" mov rsp, rbp\n");
printf(" pop rbp\n");
printf(" ret\n");
return;
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
LOGGER("> %s", get_node_name(node->kind));
if (node->kind == ND_RETURN) {
gen(node->lhs);
printf(" pop rax\n");
printf(" mov rsp, rbp\n");
printf(" pop rbp\n");
printf(" ret\n");
return;
}
if (node->kind == ND_IF) {
gen(node->lhs);
printf(" pop rax\n"); // スタックトップに結果が入っているはず
printf(" cmp rax, 0\n");
char buf[24];
snprintf(buf, 24, "%d", if_index++);
LOGGER("buf: %s", buf);
if (node->els) {
printf(" je .Lelse%s\n", buf);
} else {
printf(" je .Lend%s\n", buf);
}
gen(node->rhs);
if (node->els) {
printf(" .Lelse%s:\n", buf);
gen(node->els);
}
printf(".Lend%s:\n", buf);
return;
}
// 終端記号
switch (node->kind) {
case ND_LVAR:
gen_lval(node);
printf(" pop rax\n");
printf(" mov rax, [rax]\n");
printf(" push rax\n");
return;
case ND_ASSIGN:
gen_lval(node->lhs);
gen(node->rhs);
printf(" pop rdi\n");
printf(" pop rax\n");
printf(" mov [rax], rdi\n");
printf(" push rdi\n");
return;
case ND_NUM:
printf(" push %d\n", node->val);
return;
case ND_LVAR:
gen_lval(node);
printf(" pop rax\n");
printf(" mov rax, [rax]\n");
printf(" push rax\n");
return;
case ND_ASSIGN:
gen_lval(node->lhs);
gen(node->rhs);
printf(" pop rdi\n");
printf(" pop rax\n");
printf(" mov [rax], rdi\n");
printf(" push rdi\n");
return;
case ND_NUM:
printf(" push %d\n", node->val);
return;
}

gen(node->lhs);
Expand All @@ -44,39 +68,39 @@ void gen(Node *node) {
printf(" pop rax\n");

switch (node->kind) {
case ND_ADD:
printf(" add rax, rdi\n");
break;
case ND_SUB:
printf(" sub rax, rdi\n");
break;
case ND_MUL:
printf(" imul rax, rdi\n");
break;
case ND_DIV:
printf(" cqo\n");
printf(" idiv rdi\n");
break;
case ND_EQ:
printf(" cmp rax, rdi\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
break;
case ND_NE:
printf(" cmp rax, rdi\n");
printf(" setne al\n");
printf(" movzb rax, al\n");
break;
case ND_LT:
printf(" cmp rax, rdi\n");
printf(" setl al\n");
printf(" movzb rax, al\n");
break;
case ND_LE:
printf(" cmp rax, rdi\n");
printf(" setle al\n");
printf(" movzb rax, al\n");
break;
case ND_ADD:
printf(" add rax, rdi\n");
break;
case ND_SUB:
printf(" sub rax, rdi\n");
break;
case ND_MUL:
printf(" imul rax, rdi\n");
break;
case ND_DIV:
printf(" cqo\n");
printf(" idiv rdi\n");
break;
case ND_EQ:
printf(" cmp rax, rdi\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
break;
case ND_NE:
printf(" cmp rax, rdi\n");
printf(" setne al\n");
printf(" movzb rax, al\n");
break;
case ND_LT:
printf(" cmp rax, rdi\n");
printf(" setl al\n");
printf(" movzb rax, al\n");
break;
case ND_LE:
printf(" cmp rax, rdi\n");
printf(" setle al\n");
printf(" movzb rax, al\n");
break;
}

printf(" push rax\n");
Expand Down
13 changes: 7 additions & 6 deletions src/logger.c
Expand Up @@ -35,15 +35,16 @@ void logger(char *fmt, ...) {
#endif

char *get_token_name(TokenKind kind) {
char *token_names[5] = {"TK_RESERVED", "TK_IDENT", "TK_NUM", "TK_EOF", "TK_RETURN"};
char *token_names[7] = {
"TK_RESERVED", "TK_IDENT", "TK_NUM", "TK_EOF",
"TK_RETURN", "TK_IF", "TK_ELSE",
};
return token_names[kind];
}

char *get_node_name(NodeKind kind) {
const char *node_names[12] = {
"ND_ADD", "ND_SUB", "ND_MUL", "ND_DIV", "ND_EQ", "ND_NE",
"ND_LT", "ND_LE", "ND_NUM", "ND_ASSIGN", "ND_LVAR", "ND_RETURN"
};
const char *node_names[13] = {
"ND_ADD", "ND_SUB", "ND_MUL", "ND_DIV", "ND_EQ", "ND_NE", "ND_LT",
"ND_LE", "ND_NUM", "ND_ASSIGN", "ND_LVAR", "ND_RETURN", "ND_IF"};
return node_names[kind];
}

2 changes: 2 additions & 0 deletions src/main.c
Expand Up @@ -5,6 +5,7 @@ char *user_input;
Token *token; // 現在注目しているトークン
Node *code[100];
LVar *locals; // ローカル変数
int if_index; // if文のインデックス

// エラーを報告するための関数
// printfと同じ引数を取る
Expand Down Expand Up @@ -46,6 +47,7 @@ int main(int argc, char **argv) {
}

user_input = argv[1];
if_index = 0;
LOGGER("start tokenizing...");
token = tokenize();
Token *tmp_token = token;
Expand Down
58 changes: 49 additions & 9 deletions src/parse.c
Expand Up @@ -16,7 +16,10 @@ bool consume(char *op) {
//  真を返す。それ以外の場合には偽を返す。
bool consume_token(TokenKind kind) {
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
if (token->kind != kind) return false;
LOGGER("actually: %s, expected: %s", get_token_name(token->kind),
get_token_name(kind));
if (token->kind != kind)
return false;
token = token->next;
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
return true;
Expand Down Expand Up @@ -80,8 +83,8 @@ Token *new_token(TokenKind kind, Token *cur, char *str, int len) {
tok->str = str;
tok->len = len;
cur->next = tok;
LOGGER("new_token: kind=%s, str=%s, len=%d, val=%d",
get_token_name(tok->kind), tok->str, tok->len, tok->val);
LOGGER("new_token: kind=%s, str=%.*s, len=%d, val=%d",
get_token_name(tok->kind), tok->len, tok->str, tok->len, tok->val);
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
return tok;
}
Expand Down Expand Up @@ -128,6 +131,18 @@ Token *tokenize() {
continue;
}

if (strncmp(p, "if", 2) == 0 && !is_alnum(p[2])) {
cur = new_token(TK_IF, cur, p, 2);
p += 2;
continue;
}

if (strncmp(p, "else", 4) == 0 && !is_alnum(p[4])) {
cur = new_token(TK_ELSE, cur, p, 4);
p += 4;
continue;
}

// 記号(二個進める)
if (startswith(p, "==") || startswith(p, "!=") || startswith(p, "<=") ||
startswith(p, ">=")) {
Expand All @@ -151,9 +166,9 @@ Token *tokenize() {
LOGGER("tokenizing ident(%s): ", p);
char *old_p = p;
int char_len = 0;
while(is_alnum(*p)){
p++;
char_len++;
while (is_alnum(*p)) {
p++;
char_len++;
}
cur = new_token(TK_IDENT, cur, old_p, char_len);
cur->len = char_len;
Expand Down Expand Up @@ -207,6 +222,9 @@ Node *new_num(int val) {
// 文法一覧
// program = stmt*
// stmt = expr "; | "return" expr ";"
// | "if" "(" expr ")" stmt ("else" stmt)?
// | "while" "(" expr ")" stmt
// | "for" "(" expr? ";" expr? ";" expr? ")" stmt
// expr = assign
// assign = equality ("=" assign)?
// equality = relational ("==" relational | "!=" relational)*
Expand All @@ -228,19 +246,41 @@ void program() {
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
}

// stmt = expr ";"
// stmt = expr "; | "return" expr ";"
// | "if" "(" expr ")" stmt ("else" stmt)?
// | "while" "(" expr ")" stmt
// | "for" "(" expr? ";" expr? ";" expr? ")" stmt
Node *stmt() {
LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
LOGGER("Now tokenizing... %s", get_token_name(token->kind));
Node *node;
if (consume_token(TK_RETURN)) {
node = calloc(1, sizeof(Node));
node->kind = ND_RETURN;
node->lhs = expr();
expect(";");
} else if (consume_token(TK_IF)) {
node = calloc(1, sizeof(Node));
node->kind = ND_IF;
node->lhs = expr();
LOGGER("before node->lhs");
node->rhs = stmt();
LOGGER("consumed TK_IF");
if (consume_token(TK_ELSE)) {
LOGGER("after consume_token(TK_ELSE)");
LOGGER("consuming: %s", get_token_name(token->kind));
LOGGER("remaining tokens: %s", token->str);
node->els = stmt();
} else {
node->els = NULL;
}
} else {
node = expr();
expect(";");
}
expect(";");

LOGGER("%s:l%d %s()", __FILE__, __LINE__, __func__);
LOGGER("next token is... %s", get_token_name(token->kind));
return node;
}

Expand Down Expand Up @@ -338,7 +378,7 @@ Node *primary() {
return node;
}

// ローカル変数があれば読む
// ローカル変# 数があれば読む
Token *tok = consume_ident();
if (tok) {
Node *node = calloc(1, sizeof(Node));
Expand Down
13 changes: 12 additions & 1 deletion test.sh
Expand Up @@ -53,7 +53,7 @@ assert 0 '1>=2;'
assert 1 'a=1; return a;'
assert 100 'a=100; return a;'
assert 1 'a=1; a;'
assert 3 'a=1;b=2;return a+b;'
assert 3 'a=1;b=2;return a + b;'
assert 4 'a=1;b=0; return (a+a)*(a+a)+b;'
assert 1 'a=1;b=0; return a>b;'

Expand All @@ -63,4 +63,15 @@ assert 1 'apple=1; apple;'
assert 3 'apple=1;banana=2;return apple+banana;'
assert 0 'apple=1;banana=0; return (apple+apple)*banana;'
assert 1 'apple=1;banana=0; return apple>banana;'

# if文の追加
assert 1 'if(1) return 1;'
assert 3 'if(1<2) return 3;'
assert 2 'if(1>2) return 3;return 2;'
assert 3 'if(1<2) return 3;return 2;'
assert 222 'if(1>3) return 111; else return 222;'
assert 111 'if(1<3) return 111; else return 222;'
assert 222 'a=0;b=1; if(a<b) return 222; return 111;'
assert 3 'if(1) a = 1; if (1) b=2; return a + b;'
assert 1 'if(0) a=2; else a = 1; if(1) b = 0; return a + b;'
echo OK

0 comments on commit 3e87a1f

Please sign in to comment.