Add "return" statement

This commit is contained in:
Rui Ueyama 2020-10-07 20:12:57 +09:00
parent 482c26b536
commit 6cc1c1f064
5 changed files with 67 additions and 41 deletions

View File

@ -15,10 +15,11 @@ typedef struct Node Node;
// Token
typedef enum {
TK_IDENT, // Identifiers
TK_PUNCT, // Punctuators
TK_NUM, // Numeric literals
TK_EOF, // End-of-file markers
TK_IDENT, // Identifiers
TK_PUNCT, // Punctuators
TK_KEYWORD, // Keywords
TK_NUM, // Numeric literals
TK_EOF, // End-of-file markers
} TokenKind;
// Token type
@ -70,6 +71,7 @@ typedef enum {
ND_LT, // <
ND_LE, // <=
ND_ASSIGN, // =
ND_RETURN, // "return"
ND_EXPR_STMT, // Expression statement
ND_VAR, // Variable
ND_NUM, // Integer

View File

@ -94,7 +94,12 @@ static void gen_expr(Node *node) {
}
static void gen_stmt(Node *node) {
if (node->kind == ND_EXPR_STMT) {
switch (node->kind) {
case ND_RETURN:
gen_expr(node->lhs);
printf(" jmp .L.return\n");
return;
case ND_EXPR_STMT:
gen_expr(node->lhs);
return;
}
@ -128,6 +133,7 @@ void codegen(Function *prog) {
assert(depth == 0);
}
printf(".L.return:\n");
printf(" mov %%rbp, %%rsp\n");
printf(" pop %%rbp\n");
printf(" ret\n");

View File

@ -61,8 +61,15 @@ static Obj *new_lvar(char *name) {
return var;
}
// stmt = expr-stmt
// stmt = "return" expr ";"
// | expr-stmt
static Node *stmt(Token **rest, Token *tok) {
if (equal(tok, "return")) {
Node *node = new_unary(ND_RETURN, expr(&tok, tok->next));
*rest = skip(tok, ";");
return node;
}
return expr_stmt(rest, tok);
}

70
test.sh
View File

@ -16,43 +16,47 @@ assert() {
fi
}
assert 0 '0;'
assert 42 '42;'
assert 21 '5+20-4;'
assert 41 ' 12 + 34 - 5 ;'
assert 47 '5+6*7;'
assert 15 '5*(9-6);'
assert 4 '(3+5)/2;'
assert 10 '-10+20;'
assert 10 '- -10;'
assert 10 '- - +10;'
assert 0 'return 0;'
assert 42 'return 42;'
assert 21 'return 5+20-4;'
assert 41 'return 12 + 34 - 5 ;'
assert 47 'return 5+6*7;'
assert 15 'return 5*(9-6);'
assert 4 'return (3+5)/2;'
assert 10 'return -10+20;'
assert 10 'return - -10;'
assert 10 'return - - +10;'
assert 0 '0==1;'
assert 1 '42==42;'
assert 1 '0!=1;'
assert 0 '42!=42;'
assert 0 'return 0==1;'
assert 1 'return 42==42;'
assert 1 'return 0!=1;'
assert 0 'return 42!=42;'
assert 1 '0<1;'
assert 0 '1<1;'
assert 0 '2<1;'
assert 1 '0<=1;'
assert 1 '1<=1;'
assert 0 '2<=1;'
assert 1 'return 0<1;'
assert 0 'return 1<1;'
assert 0 'return 2<1;'
assert 1 'return 0<=1;'
assert 1 'return 1<=1;'
assert 0 'return 2<=1;'
assert 1 '1>0;'
assert 0 '1>1;'
assert 0 '1>2;'
assert 1 '1>=0;'
assert 1 '1>=1;'
assert 0 '1>=2;'
assert 1 'return 1>0;'
assert 0 'return 1>1;'
assert 0 'return 1>2;'
assert 1 'return 1>=0;'
assert 1 'return 1>=1;'
assert 0 'return 1>=2;'
assert 3 'a=3; a;'
assert 8 'a=3; z=5; a+z;'
assert 3 'a=3; return a;'
assert 8 'a=3; z=5; return a+z;'
assert 3 'a=3; a;'
assert 8 'a=3; z=5; a+z;'
assert 6 'a=b=3; a+b;'
assert 3 'foo=3; foo;'
assert 8 'foo123=3; bar=5; foo123+bar;'
assert 3 'a=3; return a;'
assert 8 'a=3; z=5; return a+z;'
assert 6 'a=b=3; return a+b;'
assert 3 'foo=3; return foo;'
assert 8 'foo123=3; bar=5; return foo123+bar;'
assert 1 'return 1; 2; 3;'
assert 2 '1; return 2; 3;'
assert 3 '1; 2; return 3;'
echo OK

View File

@ -79,7 +79,13 @@ static int read_punct(char *p) {
return ispunct(*p) ? 1 : 0;
}
// Tokenize `current_input` and returns new tokens.
static void convert_keywords(Token *tok) {
for (Token *t = tok; t->kind != TK_EOF; t = t->next)
if (equal(t, "return"))
t->kind = TK_KEYWORD;
}
// Tokenize a given string and returns new tokens.
Token *tokenize(char *p) {
current_input = p;
Token head = {};
@ -101,7 +107,7 @@ Token *tokenize(char *p) {
continue;
}
// Identifier
// Identifier or keyword
if (is_ident1(*p)) {
char *start = p;
do {
@ -123,5 +129,6 @@ Token *tokenize(char *p) {
}
cur = cur->next = new_token(TK_EOF, p, p);
convert_keywords(head.next);
return head.next;
}