Support zero-arity function definition

This commit is contained in:
Rui Ueyama 2020-09-04 19:01:33 +09:00
parent 660479e2de
commit 3706bb32a3
5 changed files with 142 additions and 96 deletions

View File

@ -56,6 +56,8 @@ struct Var {
// Function
typedef struct Function Function;
struct Function {
Function *next;
char *name;
Node *body;
Var *locals;
int stack_size;
@ -121,6 +123,7 @@ Function *parse(Token *tok);
typedef enum {
TY_INT,
TY_PTR,
TY_FUNC,
} TypeKind;
struct Type {
@ -131,12 +134,16 @@ struct Type {
// Declaration
Token *name;
// Function type
Type *return_ty;
};
extern Type *ty_int;
bool is_integer(Type *ty);
Type *pointer_to(Type *base);
Type *func_type(Type *return_ty);
void add_type(Node *node);
//

View File

@ -2,6 +2,7 @@
static int depth;
static char *argreg[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"};
static Function *current_fn;
static void gen_expr(Node *node);
@ -161,7 +162,7 @@ static void gen_stmt(Node *node) {
return;
case ND_RETURN:
gen_expr(node->lhs);
printf(" jmp .L.return\n");
printf(" jmp .L.return.%s\n", current_fn->name);
return;
case ND_EXPR_STMT:
gen_expr(node->lhs);
@ -173,30 +174,37 @@ static void gen_stmt(Node *node) {
// Assign offsets to local variables.
static void assign_lvar_offsets(Function *prog) {
int offset = 0;
for (Var *var = prog->locals; var; var = var->next) {
offset += 8;
var->offset = -offset;
for (Function *fn = prog; fn; fn = fn->next) {
int offset = 0;
for (Var *var = fn->locals; var; var = var->next) {
offset += 8;
var->offset = -offset;
}
fn->stack_size = align_to(offset, 16);
}
prog->stack_size = align_to(offset, 16);
}
void codegen(Function *prog) {
assign_lvar_offsets(prog);
printf(" .globl main\n");
printf("main:\n");
for (Function *fn = prog; fn; fn = fn->next) {
printf(" .globl %s\n", fn->name);
printf("%s:\n", fn->name);
current_fn = fn;
// Prologue
printf(" push %%rbp\n");
printf(" mov %%rsp, %%rbp\n");
printf(" sub $%d, %%rsp\n", prog->stack_size);
// Prologue
printf(" push %%rbp\n");
printf(" mov %%rsp, %%rbp\n");
printf(" sub $%d, %%rsp\n", fn->stack_size);
gen_stmt(prog->body);
assert(depth == 0);
// Emit code
gen_stmt(fn->body);
assert(depth == 0);
printf(".L.return:\n");
printf(" mov %%rbp, %%rsp\n");
printf(" pop %%rbp\n");
printf(" ret\n");
// Epilogue
printf(".L.return.%s:\n", fn->name);
printf(" mov %%rbp, %%rsp\n");
printf(" pop %%rbp\n");
printf(" ret\n");
}
}

46
parse.c
View File

@ -22,6 +22,8 @@
// accumulated to this list.
Var *locals;
static Type *typespec(Token **rest, Token *tok);
static Type *declarator(Token **rest, Token *tok, Type *ty);
static Node *declaration(Token **rest, Token *tok);
static Node *compound_stmt(Token **rest, Token *tok);
static Node *stmt(Token **rest, Token *tok);
@ -96,16 +98,25 @@ static Type *typespec(Token **rest, Token *tok) {
return ty_int;
}
// declarator = "*"* ident
// type-suffix = ("(" func-params)?
static Type *type_suffix(Token **rest, Token *tok, Type *ty) {
if (equal(tok, "(")) {
*rest = skip(tok->next, ")");
return func_type(ty);
}
*rest = tok;
return ty;
}
// declarator = "*"* ident type-suffix
static Type *declarator(Token **rest, Token *tok, Type *ty) {
while (consume(&tok, tok, "*"))
ty = pointer_to(ty);
if (tok->kind != TK_IDENT)
error_tok(tok, "expected a variable name");
ty = type_suffix(rest, tok->next, ty);
ty->name = tok;
*rest = tok->next;
return ty;
}
@ -470,12 +481,27 @@ static Node *primary(Token **rest, Token *tok) {
error_tok(tok, "expected an expression");
}
// program = stmt*
Function *parse(Token *tok) {
tok = skip(tok, "{");
static Function *function(Token **rest, Token *tok) {
Type *ty = typespec(&tok, tok);
ty = declarator(&tok, tok, ty);
Function *prog = calloc(1, sizeof(Function));
prog->body = compound_stmt(&tok, tok);
prog->locals = locals;
return prog;
locals = NULL;
Function *fn = calloc(1, sizeof(Function));
fn->name = get_ident(ty->name);
tok = skip(tok, "{");
fn->body = compound_stmt(rest, tok);
fn->locals = locals;
return fn;
}
// program = function-definition*
Function *parse(Token *tok) {
Function head = {};
Function *cur = &head;
while (tok->kind != TK_EOF)
cur = cur->next = function(&tok, tok);
return head.next;
}

134
test.sh
View File

@ -27,87 +27,85 @@ assert() {
fi
}
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 'int main() { return 0; }'
assert 42 'int main() { return 42; }'
assert 21 'int main() { return 5+20-4; }'
assert 41 'int main() { return 12 + 34 - 5 ; }'
assert 47 'int main() { return 5+6*7; }'
assert 15 'int main() { return 5*(9-6); }'
assert 4 'int main() { return (3+5)/2; }'
assert 10 'int main() { return -10+20; }'
assert 10 'int main() { return - -10; }'
assert 10 'int main() { return - - +10; }'
assert 0 '{ return 0==1; }'
assert 1 '{ return 42==42; }'
assert 1 '{ return 0!=1; }'
assert 0 '{ return 42!=42; }'
assert 0 'int main() { return 0==1; }'
assert 1 'int main() { return 42==42; }'
assert 1 'int main() { return 0!=1; }'
assert 0 'int main() { return 42!=42; }'
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 'int main() { return 0<1; }'
assert 0 'int main() { return 1<1; }'
assert 0 'int main() { return 2<1; }'
assert 1 'int main() { return 0<=1; }'
assert 1 'int main() { return 1<=1; }'
assert 0 'int main() { return 2<=1; }'
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 1 'int main() { return 1>0; }'
assert 0 'int main() { return 1>1; }'
assert 0 'int main() { return 1>2; }'
assert 1 'int main() { return 1>=0; }'
assert 1 'int main() { return 1>=1; }'
assert 0 'int main() { return 1>=2; }'
assert 3 '{ int a; a=3; return a; }'
assert 3 '{ int a=3; return a; }'
assert 8 '{ int a=3; int z=5; return a+z; }'
assert 3 'int main() { int a; a=3; return a; }'
assert 3 'int main() { int a=3; return a; }'
assert 8 'int main() { int a=3; int z=5; return a+z; }'
assert 3 '{ int a=3; return a; }'
assert 8 '{ int a=3; int z=5; return a+z; }'
assert 6 '{ int a; int b; a=b=3; return a+b; }'
assert 3 '{ int foo=3; return foo; }'
assert 8 '{ int foo123=3; int bar=5; return foo123+bar; }'
assert 1 'int main() { return 1; 2; 3; }'
assert 2 'int main() { 1; return 2; 3; }'
assert 3 'int main() { 1; 2; return 3; }'
assert 1 '{ return 1; 2; 3; }'
assert 2 '{ 1; return 2; 3; }'
assert 3 '{ 1; 2; return 3; }'
assert 3 'int main() { int a=3; return a; }'
assert 8 'int main() { int a=3; int z=5; return a+z; }'
assert 6 'int main() { int a; int b; a=b=3; return a+b; }'
assert 3 'int main() { int foo=3; return foo; }'
assert 8 'int main() { int foo123=3; int bar=5; return foo123+bar; }'
assert 3 '{ {1; {2;} return 3;} }'
assert 5 '{ ;;; return 5; }'
assert 3 'int main() { if (0) return 2; return 3; }'
assert 3 'int main() { if (1-1) return 2; return 3; }'
assert 2 'int main() { if (1) return 2; return 3; }'
assert 2 'int main() { if (2-1) return 2; return 3; }'
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; } }'
assert 55 'int main() { int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; return j; }'
assert 3 'int main() { for (;;) return 3; return 5; }'
assert 55 '{ int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; return j; }'
assert 3 '{ for (;;) return 3; return 5; }'
assert 10 'int main() { int i=0; while(i<10) i=i+1; return i; }'
assert 10 '{ int i=0; while(i<10) i=i+1; return i; }'
assert 3 'int main() { {1; {2;} return 3;} }'
assert 5 'int main() { ;;; return 5; }'
assert 3 '{ {1; {2;} return 3;} }'
assert 10 'int main() { int i=0; while(i<10) i=i+1; return i; }'
assert 55 'int main() { int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} return j; }'
assert 10 '{ int i=0; while(i<10) i=i+1; return i; }'
assert 55 '{ int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} return j; }'
assert 3 'int main() { int x=3; return *&x; }'
assert 3 'int main() { int x=3; int *y=&x; int **z=&y; return **z; }'
assert 5 'int main() { int x=3; int y=5; return *(&x+1); }'
assert 3 'int main() { int x=3; int y=5; return *(&y-1); }'
assert 5 'int main() { int x=3; int *y=&x; *y=5; return x; }'
assert 7 'int main() { int x=3; int y=5; *(&x+1)=7; return y; }'
assert 7 'int main() { int x=3; int y=5; *(&y-2+1)=7; return x; }'
assert 5 'int main() { int x=3; return (&x+2)-&x+3; }'
assert 8 'int main() { int x, y; x=3; y=5; return x+y; }'
assert 8 'int main() { int x=3, y=5; return x+y; }'
assert 3 '{ int x=3; return *&x; }'
assert 3 '{ int x=3; int *y=&x; int **z=&y; return **z; }'
assert 5 '{ int x=3; int y=5; return *(&x+1); }'
assert 3 '{ int x=3; int y=5; return *(&y-1); }'
assert 5 '{ int x=3; int *y=&x; *y=5; return x; }'
assert 7 '{ int x=3; int y=5; *(&x+1)=7; return y; }'
assert 7 '{ int x=3; int y=5; *(&y-2+1)=7; return x; }'
assert 5 '{ int x=3; return (&x+2)-&x+3; }'
assert 8 '{ int x, y; x=3; y=5; return x+y; }'
assert 8 '{ int x=3, y=5; return x+y; }'
assert 3 'int main() { return ret3(); }'
assert 5 'int main() { return ret5(); }'
assert 8 'int main() { return add(3, 5); }'
assert 2 'int main() { return sub(5, 3); }'
assert 21 'int main() { return add6(1,2,3,4,5,6); }'
assert 66 'int main() { return add6(1,2,add6(3,4,5,6,7,8),9,10,11); }'
assert 136 'int main() { return add6(1,2,add6(3,add6(4,5,6,7,8,9),10,11,12,13),14,15,16); }'
assert 3 '{ return ret3(); }'
assert 5 '{ return ret5(); }'
assert 8 '{ return add(3, 5); }'
assert 2 '{ return sub(5, 3); }'
assert 21 '{ return add6(1,2,3,4,5,6); }'
assert 66 '{ return add6(1,2,add6(3,4,5,6,7,8),9,10,11); }'
assert 136 '{ return add6(1,2,add6(3,add6(4,5,6,7,8,9),10,11,12,13),14,15,16); }'
assert 32 'int main() { return ret32(); } int ret32() { return 32; }'
echo OK

7
type.c
View File

@ -13,6 +13,13 @@ Type *pointer_to(Type *base) {
return ty;
}
Type *func_type(Type *return_ty) {
Type *ty = calloc(1, sizeof(Type));
ty->kind = TY_FUNC;
ty->return_ty = return_ty;
return ty;
}
void add_type(Node *node) {
if (!node || node->ty)
return;