aboutsummaryrefslogtreecommitdiffhomepage
path: root/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c82
1 files changed, 78 insertions, 4 deletions
diff --git a/parse.c b/parse.c
index 1695c8f..2f856bd 100644
--- a/parse.c
+++ b/parse.c
@@ -30,6 +30,8 @@ struct Parser {
int n_funcs;
AstNode* structs;
int n_structs;
+ AstNode* unions;
+ int n_unions;
AstNode* enums;
int n_enums;
AstNode* typedefs;
@@ -45,6 +47,7 @@ Parser* parser_new(Token* tokens) {
p->gvars = calloc(128, sizeof(GlobalVar));
p->funcs = calloc(256, sizeof(Func));
p->structs = calloc(64, sizeof(AstNode));
+ p->unions = calloc(64, sizeof(AstNode));
p->enums = calloc(16, sizeof(AstNode));
p->typedefs = calloc(64, sizeof(AstNode));
p->str_literals = calloc(1024, sizeof(char*));
@@ -172,6 +175,16 @@ int find_struct(Parser* p, const String* name) {
return -1;
}
+int find_union(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_unions; ++i) {
+ if (string_equals(&p->unions[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
int find_enum(Parser* p, const String* name) {
int i;
for (i = 0; i < p->n_enums; ++i) {
@@ -361,7 +374,8 @@ int is_type_token(Parser* p, Token* token) {
if (token->kind == TokenKind_keyword_int || token->kind == TokenKind_keyword_short ||
token->kind == TokenKind_keyword_long || token->kind == TokenKind_keyword_char ||
token->kind == TokenKind_keyword_void || token->kind == TokenKind_keyword_enum ||
- token->kind == TokenKind_keyword_struct || token->kind == TokenKind_keyword_const) {
+ token->kind == TokenKind_keyword_struct || token->kind == TokenKind_keyword_union ||
+ token->kind == TokenKind_keyword_const) {
return 1;
}
if (token->kind != TokenKind_ident) {
@@ -414,6 +428,14 @@ Type* parse_type(Parser* p) {
fatal_error("parse_type: unknown struct, %.*s", name->len, name->data);
}
ty->def = p->structs + struct_idx;
+ } else if (t->kind == TokenKind_keyword_union) {
+ ty->kind = TypeKind_union;
+ name = parse_ident(p);
+ int union_idx = find_union(p, name);
+ if (union_idx == -1) {
+ fatal_error("parse_type: unknown union, %.*s", name->len, name->data);
+ }
+ ty->def = p->unions + union_idx;
} else {
unreachable();
}
@@ -761,7 +783,7 @@ AstNode* parse_continue_stmt(Parser* p) {
AstNode* parse_var_decl(Parser* p) {
Type* ty = parse_type(p);
- if (!type_is_unsized(ty)) {
+ if (type_is_unsized(ty)) {
fatal_error("parse_var_decl: invalid type for variable");
}
String* name = parse_ident(p);
@@ -951,7 +973,7 @@ AstNode* parse_struct_member(Parser* p) {
}
AstNode* parse_struct_members(Parser* p) {
- AstNode* list = ast_new_list(16);
+ AstNode* list = ast_new_list(32);
while (peek_token(p)->kind != TokenKind_brace_r) {
AstNode* member = parse_struct_member(p);
ast_append(list, member);
@@ -990,6 +1012,56 @@ AstNode* parse_struct_decl_or_def(Parser* p) {
return p->structs + struct_idx;
}
+AstNode* parse_union_member(Parser* p) {
+ Type* ty = parse_type(p);
+ String* name = parse_ident(p);
+ expect(p, TokenKind_semicolon);
+ AstNode* member = ast_new(AstNodeKind_union_member);
+ member->name = *name;
+ member->ty = ty;
+ return member;
+}
+
+AstNode* parse_union_members(Parser* p) {
+ AstNode* list = ast_new_list(16);
+ while (peek_token(p)->kind != TokenKind_brace_r) {
+ AstNode* member = parse_union_member(p);
+ ast_append(list, member);
+ }
+ return list;
+}
+
+AstNode* parse_union_decl_or_def(Parser* p) {
+ expect(p, TokenKind_keyword_union);
+ String* name = parse_ident(p);
+
+ if (peek_token(p)->kind != TokenKind_semicolon && peek_token(p)->kind != TokenKind_brace_l) {
+ p->pos = p->pos - 2;
+ return parse_func_decl_or_def(p);
+ }
+
+ int union_idx = find_union(p, name);
+ if (union_idx == -1) {
+ union_idx = p->n_unions;
+ p->unions[union_idx].kind = AstNodeKind_union_def;
+ p->unions[union_idx].name = *name;
+ ++p->n_unions;
+ }
+ if (peek_token(p)->kind == TokenKind_semicolon) {
+ next_token(p);
+ return ast_new(AstNodeKind_union_decl);
+ }
+ if (p->unions[union_idx].node_members) {
+ fatal_error("parse_union_decl_or_def: union %.*s redefined", name->len, name->data);
+ }
+ expect(p, TokenKind_brace_l);
+ AstNode* members = parse_union_members(p);
+ expect(p, TokenKind_brace_r);
+ expect(p, TokenKind_semicolon);
+ p->unions[union_idx].node_members = members;
+ return p->unions + union_idx;
+}
+
AstNode* parse_enum_member(Parser* p) {
String* name = parse_ident(p);
AstNode* member = ast_new(AstNodeKind_enum_member);
@@ -1056,7 +1128,7 @@ AstNode* parse_typedef_decl(Parser* p) {
AstNode* parse_extern_var_decl(Parser* p) {
expect(p, TokenKind_keyword_extern);
Type* ty = parse_type(p);
- if (!type_is_unsized(ty)) {
+ if (type_is_unsized(ty)) {
fatal_error("parse_extern_var_decl: invalid type for variable");
}
String* name = parse_ident(p);
@@ -1076,6 +1148,8 @@ AstNode* parse_toplevel(Parser* p) {
TokenKind tk = peek_token(p)->kind;
if (tk == TokenKind_keyword_struct) {
return parse_struct_decl_or_def(p);
+ } else if (tk == TokenKind_keyword_union) {
+ return parse_union_decl_or_def(p);
} else if (tk == TokenKind_keyword_enum) {
return parse_enum_def(p);
} else if (tk == TokenKind_keyword_typedef) {