aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/ast.c21
-rw-r--r--src/ast.h7
-rw-r--r--src/codegen.c2
-rw-r--r--src/parse.c257
-rw-r--r--tests/059.sh12
5 files changed, 204 insertions, 95 deletions
diff --git a/src/ast.c b/src/ast.c
index 78fb2b9..1e444ba 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -45,6 +45,8 @@ const char* type_kind_stringify(TypeKind k) {
return "<pointer>";
else if (k == TypeKind_array)
return "<array>";
+ else if (k == TypeKind_func)
+ return "<function>";
else
unreachable();
}
@@ -60,16 +62,14 @@ Type* type_new(TypeKind kind) {
}
Type* type_new_ptr(Type* base) {
- Type* ty = calloc(1, sizeof(Type));
- ty->kind = TypeKind_ptr;
+ Type* ty = type_new(TypeKind_ptr);
ty->base = base;
return ty;
}
-Type* type_new_array(Type* elem, int size) {
- Type* ty = calloc(1, sizeof(Type));
- ty->kind = TypeKind_array;
- ty->base = elem;
+Type* type_new_array(Type* base, int size) {
+ Type* ty = type_new(TypeKind_array);
+ ty->base = base;
ty->array_size = size;
return ty;
}
@@ -82,8 +82,15 @@ Type* type_array_to_ptr(Type* ty) {
return type_new_ptr(ty->base);
}
+Type* type_new_func(Type* result, AstNode* params) {
+ Type* ty = type_new(TypeKind_func);
+ ty->result = result;
+ ty->params = params;
+ return ty;
+}
+
BOOL type_is_unsized(Type* ty) {
- return ty->kind == TypeKind_void;
+ return ty->kind == TypeKind_void || ty->kind == TypeKind_func;
}
int type_sizeof(Type* ty) {
diff --git a/src/ast.h b/src/ast.h
index 00b0171..f5fc98f 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -37,6 +37,7 @@ typedef enum {
TypeKind_enum,
TypeKind_ptr,
TypeKind_array,
+ TypeKind_func,
} TypeKind;
const char* type_kind_stringify(TypeKind k);
@@ -45,7 +46,7 @@ struct AstNode;
typedef struct AstNode AstNode;
typedef struct {
- struct AstNode* defs;
+ AstNode* defs;
size_t index;
} TypeRef;
@@ -56,6 +57,8 @@ typedef struct Type {
struct Type* base;
int array_size;
TypeRef ref;
+ struct Type* result;
+ AstNode* params;
} Type;
Type* type_new(TypeKind kind);
@@ -63,6 +66,7 @@ Type* type_new_ptr(Type* base);
Type* type_new_array(Type* elem, int size);
Type* type_new_static_string(int len);
Type* type_array_to_ptr(Type* ty);
+Type* type_new_func(Type* result, AstNode* params);
BOOL type_is_unsized(Type* ty);
int type_sizeof_struct(Type* ty);
@@ -141,7 +145,6 @@ typedef enum {
#define node_op __i1
#define node_stack_offset __i1
#define node_stack_size __i1
-#define node_function_is_static __i2
struct AstNode {
AstNodeKind kind;
diff --git a/src/codegen.c b/src/codegen.c
index bce71c9..006ae20 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -548,7 +548,7 @@ static void codegen_stmt(CodeGen* g, AstNode* ast) {
static void codegen_func(CodeGen* g, AstNode* ast) {
g->current_func = ast;
- if (!ast->node_function_is_static) {
+ if (ast->ty->result->storage_class != StorageClass_static) {
fprintf(g->out, ".globl %s\n", ast->name);
}
fprintf(g->out, "%s:\n", ast->name);
diff --git a/src/parse.c b/src/parse.c
index 9c5eaff..4abfebd 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -391,7 +391,7 @@ static AstNode* parse_primary_expr(Parser* p) {
fatal_error("undefined function: %s", name);
}
e->name = name;
- e->ty = p->funcs.data[func_idx].ty;
+ e->ty = p->funcs.data[func_idx].ty->result;
return e;
}
@@ -870,6 +870,119 @@ static Type* parse_pointer_opt(Parser* p, Type* ty) {
return ty;
}
+static Type* parse_array_declarator_suffix(Parser* p, Type* ty);
+static Type* parse_function_declarator_suffix(Parser* p, Type* ty);
+
+// declarator | abstract-declarator?:
+// pointer? identifier TODO attribute-specifier-sequence? { direct-declarator-suffix }*
+// pointer? '(' declarator ')' { direct-declarator-suffix }*
+// pointer? '(' abstract-declarator ')' { direct-declarator-suffix }*
+// pointer? { direct-declarator-suffix }*
+//
+// direct-declarator-suffix:
+// array-declarator-suffix TODO attribute-specifier-sequence?
+// function-declarator-suffix TODO attribute-specifier-sequence?
+static AstNode* parse_declarator_or_abstract_declarator_opt(Parser* p, Type* ty) {
+ ty = parse_pointer_opt(p, ty);
+
+ AstNode* decl;
+ if (peek_token(p)->kind == TokenKind_ident) {
+ decl = ast_new(AstNodeKind_declarator);
+ decl->name = parse_ident(p)->value.string;
+ decl->ty = ty;
+ } else if (peek_token(p)->kind == TokenKind_paren_l && !is_type_token(p, peek_token2(p))) {
+ next_token(p);
+ if (peek_token(p)->kind == TokenKind_paren_r) {
+ Token* tok = peek_token(p);
+ fatal_error("%s:%d: expected declarator, but got '%s'", tok->loc.filename, tok->loc.line,
+ token_stringify(tok));
+ }
+ decl = parse_declarator_or_abstract_declarator_opt(p, ty);
+ } else {
+ decl = ast_new(AstNodeKind_declarator);
+ decl->ty = ty;
+ }
+
+ while (1) {
+ if (peek_token(p)->kind == TokenKind_bracket_l) {
+ decl->ty = parse_array_declarator_suffix(p, decl->ty);
+ } else if (peek_token(p)->kind == TokenKind_paren_l) {
+ decl->ty = parse_function_declarator_suffix(p, decl->ty);
+ } else {
+ break;
+ }
+ }
+
+ return decl;
+}
+
+static Type* parse_declaration_specifiers(Parser* p);
+
+// parameter-declaration:
+// TODO attribute-specifier-sequence? declaration-specifiers declarator
+// TODO attribute-specifier-sequence? declaration-specifiers abstract-declarator?
+static AstNode* parse_parameter_declaration(Parser* p) {
+ if (consume_token_if(p, TokenKind_ellipsis)) {
+ AstNode* decl = ast_new(AstNodeKind_declarator);
+ decl->name = "...";
+ return decl;
+ }
+
+ Type* base_ty = parse_declaration_specifiers(p);
+ return parse_declarator_or_abstract_declarator_opt(p, base_ty);
+}
+
+// parameter-list:
+// { parameter-declaration | ',' }
+static AstNode* parse_parameter_list(Parser* p) {
+ AstNode* params = ast_new_list(4);
+
+ while (1) {
+ AstNode* param = parse_parameter_declaration(p);
+ ast_append(params, param);
+
+ if (!consume_token_if(p, TokenKind_comma)) {
+ break;
+ }
+ }
+
+ return params;
+}
+
+// parameter-type-list:
+// parameter-list
+// parameter-list ',' '...'
+// '...'
+static AstNode* parse_parameter_type_list(Parser* p) {
+ AstNode* params = parse_parameter_list(p);
+
+ BOOL has_void = FALSE;
+ for (int i = 0; i < params->node_len; ++i) {
+ if (params->node_items[i].name && strcmp(params->node_items[i].name, "...") == 0) {
+ if (i != params->node_len - 1) {
+ fatal_error("...");
+ }
+ --params->node_len;
+ break;
+ }
+ // TODO: |= is not supported
+ // has_void |= params->node_items[i].ty->kind == TypeKind_void;
+ has_void = has_void | (params->node_items[i].ty->kind == TypeKind_void);
+ }
+
+ if (params->node_len > 6) {
+ fatal_error("too many parameters");
+ }
+ if (has_void) {
+ if (params->node_len != 1) {
+ fatal_error("invalid use of void param");
+ }
+ params->node_len = 0;
+ }
+
+ return params;
+}
+
static int eval(AstNode* e);
// array-declarator:
@@ -887,16 +1000,33 @@ static Type* parse_array_declarator_suffix(Parser* p, Type* ty) {
return type_new_array(ty, size);
}
+// function-declarator:
+// direct-declarator '(' parameter-type-list? ')'
+static Type* parse_function_declarator_suffix(Parser* p, Type* ty) {
+ next_token(p); // skip '('
+ AstNode* params;
+ if (consume_token_if(p, TokenKind_paren_r)) {
+ params = ast_new_list(1);
+ } else {
+ params = parse_parameter_type_list(p);
+ expect(p, TokenKind_paren_r);
+ }
+
+ return type_new_func(ty, params);
+}
+
// direct-declarator:
// identifier TODO attribute-specifier-sequence?
// TODO '(' declarator ')'
// array-declarator TODO attribute-specifier-sequence?
-// TODO function-declarator TODO attribute-specifier-sequence?
+// function-declarator TODO attribute-specifier-sequence?
static AstNode* parse_direct_declarator(Parser* p, Type* ty) {
const Token* name = parse_ident(p);
while (1) {
if (peek_token(p)->kind == TokenKind_bracket_l) {
ty = parse_array_declarator_suffix(p, ty);
+ } else if (peek_token(p)->kind == TokenKind_paren_l) {
+ ty = parse_function_declarator_suffix(p, ty);
} else {
break;
}
@@ -1127,84 +1257,63 @@ static void register_func(Parser* p, const char* name, Type* ty) {
func->ty = ty;
}
-static AstNode* parse_param(Parser* p) {
- Type* ty = parse_type_name(p);
- const Token* name = NULL;
- TokenKind tk = peek_token(p)->kind;
- if (tk != TokenKind_comma && tk != TokenKind_paren_r) {
- name = parse_ident(p);
- }
- AstNode* param = ast_new(AstNodeKind_param);
- param->ty = ty;
- if (name) {
- param->name = name->value.string;
- }
- return param;
-}
-
-static AstNode* parse_param_list(Parser* p) {
- BOOL has_void = FALSE;
- AstNode* list = ast_new_list(6);
- while (peek_token(p)->kind != TokenKind_paren_r) {
- if (consume_token_if(p, TokenKind_ellipsis)) {
- break;
- }
- AstNode* param = parse_param(p);
- has_void = has_void || param->ty->kind == TypeKind_void;
- ast_append(list, param);
- if (!consume_token_if(p, TokenKind_comma)) {
- break;
- }
- }
- if (list->node_len > 6) {
- fatal_error("too many parameters");
- }
- if (has_void) {
- if (list->node_len != 1) {
- fatal_error("invalid use of void param");
- }
- list->node_len = 0;
- }
- return list;
-}
-
-static AstNode* parse_global_var_decl(Parser* p, AstNode* decls) {
+static AstNode* parse_global_func_or_var_decl(Parser* p, AstNode* decls) {
expect(p, TokenKind_semicolon);
for (int i = 0; i < decls->node_len; ++i) {
AstNode* decl = &decls->node_items[i];
- if (find_gvar(p, decl->name) != -1) {
- fatal_error("parse_global_var_decl: %s redeclared", decl->name);
- }
- GlobalVar* gvar = gvars_push_new(&p->gvars);
- gvar->name = decl->name;
- gvar->ty = decl->ty;
+ if (decl->ty->kind == TypeKind_func) {
+ if (decls->node_len != 1) {
+ fatal_error("parse_global_func_or_var_decl: todo");
+ }
+ // TODO: refactor
+ decl->ty->storage_class = decl->ty->result->storage_class;
+ decl->ty->result->storage_class = StorageClass_unspecified;
+ register_func(p, decl->name, decl->ty);
+ decl->kind = AstNodeKind_func_decl;
+ } else {
+ if (find_gvar(p, decl->name) != -1) {
+ fatal_error("parse_global_func_or_var_decl: %s redeclared", decl->name);
+ }
+ // TODO: refactor
+ Type* base_ty = decl->ty;
+ while (base_ty->base) {
+ base_ty = base_ty->base;
+ }
+ decl->ty->storage_class = base_ty->storage_class;
+ base_ty->storage_class = StorageClass_unspecified;
- decl->kind = AstNodeKind_gvar_decl;
- decl->node_expr = decl->node_init;
+ GlobalVar* gvar = gvars_push_new(&p->gvars);
+ gvar->name = decl->name;
+ gvar->ty = decl->ty;
+
+ if (decl->ty->storage_class == StorageClass_extern) {
+ decl->kind = AstNodeKind_nop;
+ } else {
+ decl->kind = AstNodeKind_gvar_decl;
+ decl->node_expr = decl->node_init;
+ }
+ }
}
return decls;
}
-static AstNode* parse_func_decl_or_def(Parser* p, AstNode* decls) {
+static AstNode* parse_func_def(Parser* p, AstNode* decls) {
if (decls->node_len != 1) {
- fatal_error("parse_func_decl_or_def: invalid syntax");
+ fatal_error("parse_func_def: invalid syntax");
}
Type* ty = decls->node_items[0].ty;
const char* name = decls->node_items[0].name;
+ AstNode* params = ty->params;
register_func(p, name, ty);
- AstNode* params = parse_param_list(p);
- expect(p, TokenKind_paren_r);
- if (consume_token_if(p, TokenKind_semicolon)) {
- return ast_new(AstNodeKind_func_decl);
- }
enter_func(p);
register_params(p, params);
AstNode* body = parse_block_stmt(p);
leave_func(p);
+
AstNode* func = ast_new(AstNodeKind_func_def);
func->ty = ty;
func->name = name;
@@ -1216,7 +1325,6 @@ static AstNode* parse_func_decl_or_def(Parser* p, AstNode* decls) {
func->node_stack_size =
p->lvars.data[p->lvars.len - 1].stack_offset + type_sizeof(p->lvars.data[p->lvars.len - 1].ty);
}
- func->node_function_is_static = ty->storage_class == StorageClass_static;
return func;
}
@@ -1327,21 +1435,6 @@ void parse_typedef_decl(Parser* p, AstNode* decls) {
}
}
-void parse_extern_var_decl(Parser* p, AstNode* decls) {
- expect(p, TokenKind_semicolon);
-
- for (int i = 0; i < decls->node_len; ++i) {
- AstNode* decl = &decls->node_items[i];
-
- if (find_gvar(p, decl->name) != -1) {
- fatal_error("parse_extern_var_decl: %s redeclared", decl->name);
- }
- GlobalVar* gvar = gvars_push_new(&p->gvars);
- gvar->name = decl->name;
- gvar->ty = decl->ty;
- }
-}
-
static char* generate_new_anonymous_user_type_name(Parser* p) {
char* buf = calloc(32, sizeof(char));
sprintf(buf, "__anonymous_%d__", p->anonymous_user_type_counter++);
@@ -2081,18 +2174,15 @@ static AstNode* parse_toplevel(Parser* p) {
AstNode* decls = parse_init_declarator_list(p, ty);
- if (consume_token_if(p, TokenKind_paren_l)) {
- return parse_func_decl_or_def(p, decls);
+ if (peek_token(p)->kind == TokenKind_brace_l) {
+ return parse_func_def(p, decls);
}
if (ty->storage_class == StorageClass_typedef) {
parse_typedef_decl(p, decls);
return NULL;
- } else if (ty->storage_class == StorageClass_extern) {
- parse_extern_var_decl(p, decls);
- return NULL;
} else {
- return parse_global_var_decl(p, decls);
+ return parse_global_func_or_var_decl(p, decls);
}
}
@@ -2106,11 +2196,12 @@ Program* parse(TokenArray* tokens) {
continue;
if (n->kind == AstNodeKind_func_def) {
ast_append(funcs, n);
- } else if (n->kind == AstNodeKind_gvar_decl && n->ty) {
+ } else if (n->kind == AstNodeKind_gvar_decl) {
ast_append(vars, n);
} else if (n->kind == AstNodeKind_list) {
for (int i = 0; i < n->node_len; ++i) {
- ast_append(vars, &n->node_items[i]);
+ if (n->node_items[i].kind == AstNodeKind_gvar_decl)
+ ast_append(vars, &n->node_items[i]);
}
}
}
diff --git a/tests/059.sh b/tests/059.sh
index a7b92d0..b478b14 100644
--- a/tests/059.sh
+++ b/tests/059.sh
@@ -1,13 +1,21 @@
+# TODO: improve error message
+# cat <<'EOF' > expected
+# main.c:1: expected ';' or '{', but got '}'
+# EOF
cat <<'EOF' > expected
-main.c:1: expected '{', but got '}'
+main.c:1: expected ';', but got '}'
EOF
test_compile_error <<'EOF'
int main() }
EOF
+# TODO: improve error message
+# cat <<'EOF' > expected
+# main.c:1: expected ';' or '{', but got '}'
+# EOF
cat <<'EOF' > expected
-main.c:1: expected '{', but got '123'
+main.c:1: expected ';', but got '123'
EOF
test_compile_error <<'EOF'