Add "if" statement

This commit is contained in:
Rui Ueyama 2020-10-07 12:47:09 +09:00
parent ff8912c68e
commit 72b841508f
5 changed files with 55 additions and 1 deletions

View File

@ -72,6 +72,7 @@ typedef enum {
ND_LE, // <=
ND_ASSIGN, // =
ND_RETURN, // "return"
ND_IF, // "if"
ND_BLOCK, // { ... }
ND_EXPR_STMT, // Expression statement
ND_VAR, // Variable
@ -82,9 +83,15 @@ typedef enum {
struct Node {
NodeKind kind; // Node kind
Node *next; // Next node
Node *lhs; // Left-hand side
Node *rhs; // Right-hand side
// "if" statement
Node *cond;
Node *then;
Node *els;
// Block
Node *body;

View File

@ -2,6 +2,11 @@
static int depth;
static int count(void) {
static int i = 1;
return i++;
}
static void push(void) {
printf(" push %%rax\n");
depth++;
@ -95,6 +100,19 @@ static void gen_expr(Node *node) {
static void gen_stmt(Node *node) {
switch (node->kind) {
case ND_IF: {
int c = count();
gen_expr(node->cond);
printf(" cmp $0, %%rax\n");
printf(" je .L.else.%d\n", c);
gen_stmt(node->then);
printf(" jmp .L.end.%d\n", c);
printf(".L.else.%d:\n", c);
if (node->els)
gen_stmt(node->els);
printf(".L.end.%d:\n", c);
return;
}
case ND_BLOCK:
for (Node *n = node->body; n; n = n->next)
gen_stmt(n);

13
parse.c
View File

@ -63,6 +63,7 @@ static Obj *new_lvar(char *name) {
}
// stmt = "return" expr ";"
// | "if" "(" expr ")" stmt ("else" stmt)?
// | "{" compound-stmt
// | expr-stmt
static Node *stmt(Token **rest, Token *tok) {
@ -72,6 +73,18 @@ static Node *stmt(Token **rest, Token *tok) {
return node;
}
if (equal(tok, "if")) {
Node *node = new_node(ND_IF);
tok = skip(tok->next, "(");
node->cond = expr(&tok, tok);
tok = skip(tok, ")");
node->then = stmt(&tok, tok);
if (equal(tok, "else"))
node->els = stmt(&tok, tok->next);
*rest = tok;
return node;
}
if (equal(tok, "{"))
return compound_stmt(rest, tok->next);

View File

@ -62,4 +62,11 @@ assert 3 '{ 1; 2; return 3; }'
assert 3 '{ {1; {2;} return 3;} }'
assert 5 '{ ;;; return 5; }'
assert 3 '{ if (0) return 2; return 3; }'
assert 3 '{ if (1-1) return 2; return 3; }'
assert 2 '{ if (1) return 2; return 3; }'
assert 2 '{ if (2-1) return 2; return 3; }'
assert 4 '{ if (0) { 1; 2; return 3; } else { return 4; } }'
assert 3 '{ if (1) { 1; 2; return 3; } else { return 4; } }'
echo OK

View File

@ -79,9 +79,18 @@ static int read_punct(char *p) {
return ispunct(*p) ? 1 : 0;
}
static bool is_keyword(Token *tok) {
static char *kw[] = {"return", "if", "else"};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
if (equal(tok, kw[i]))
return true;
return false;
}
static void convert_keywords(Token *tok) {
for (Token *t = tok; t->kind != TK_EOF; t = t->next)
if (equal(t, "return"))
if (is_keyword(t))
t->kind = TK_KEYWORD;
}