aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ast.c
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-22 23:28:25 +0900
committernsfisis <nsfisis@gmail.com>2025-08-22 23:28:25 +0900
commit9c202a496e75903fe37e5c19cb97c98eba6e35f2 (patch)
tree52de494a4717a3c30c4bacb9dd9b91980be2a575 /src/ast.c
parent0ac6ac95283735dd70ebf55b26ef78a4c32c31de (diff)
downloadducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.tar.gz
ducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.tar.zst
ducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.zip
chore: move *.c and *.h files to src/
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/ast.c b/src/ast.c
new file mode 100644
index 0000000..66f7cc2
--- /dev/null
+++ b/src/ast.c
@@ -0,0 +1,475 @@
+enum TypeKind {
+ TypeKind_unknown,
+
+ TypeKind_char,
+ TypeKind_short,
+ TypeKind_int,
+ TypeKind_long,
+ TypeKind_void,
+ TypeKind_ptr,
+ TypeKind_array,
+ TypeKind_enum,
+ TypeKind_struct,
+ TypeKind_union,
+};
+typedef enum TypeKind TypeKind;
+
+const char* type_kind_stringify(TypeKind k) {
+ if (k == TypeKind_unknown)
+ return "<unknown>";
+ else if (k == TypeKind_char)
+ return "char";
+ else if (k == TypeKind_short)
+ return "short";
+ else if (k == TypeKind_int)
+ return "int";
+ else if (k == TypeKind_long)
+ return "long";
+ else if (k == TypeKind_void)
+ return "void";
+ else if (k == TypeKind_ptr)
+ return "<pointer>";
+ else if (k == TypeKind_array)
+ return "<array>";
+ else if (k == TypeKind_enum)
+ return "enum";
+ else if (k == TypeKind_struct)
+ return "struct";
+ else if (k == TypeKind_union)
+ return "union";
+ else
+ unreachable();
+}
+
+struct AstNode;
+
+struct Type {
+ TypeKind kind;
+ // Check `base` instead of `kind` to test if the type is an array or a pointer.
+ struct Type* base;
+ int array_size;
+ struct AstNode* def;
+};
+typedef struct Type Type;
+
+void type_dump(Type* ty) {
+ fprintf(stderr, "Type {\n");
+ fprintf(stderr, " kind = %s\n", type_kind_stringify(ty->kind));
+ fprintf(stderr, "}\n");
+}
+
+Type* type_new(TypeKind kind) {
+ Type* ty = calloc(1, sizeof(Type));
+ ty->kind = kind;
+ return ty;
+}
+
+Type* type_new_ptr(Type* base) {
+ Type* ty = calloc(1, sizeof(Type));
+ ty->kind = 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;
+ ty->array_size = size;
+ return ty;
+}
+
+Type* type_new_static_string(int len) {
+ return type_new_array(type_new(TypeKind_char), len + 1);
+}
+
+Type* type_array_to_ptr(Type* ty) {
+ return type_new_ptr(ty->base);
+}
+
+BOOL type_is_unsized(Type* ty) {
+ return ty->kind == TypeKind_void;
+}
+
+int type_sizeof_struct(Type* ty);
+int type_sizeof_union(Type* ty);
+int type_alignof_struct(Type* ty);
+int type_alignof_union(Type* ty);
+int type_offsetof(Type* ty, const char* name);
+Type* type_member_typeof(Type* ty, const char* name);
+
+int type_sizeof(Type* ty) {
+ if (type_is_unsized(ty)) {
+ fatal_error("type_sizeof: type size cannot be determined");
+ }
+
+ if (ty->kind == TypeKind_ptr)
+ return 8;
+ else if (ty->kind == TypeKind_char)
+ return 1;
+ else if (ty->kind == TypeKind_short)
+ return 2;
+ else if (ty->kind == TypeKind_int)
+ return 4;
+ else if (ty->kind == TypeKind_long)
+ return 8;
+ else if (ty->kind == TypeKind_enum)
+ return 4;
+ else if (ty->kind == TypeKind_array)
+ return type_sizeof(ty->base) * ty->array_size;
+ else if (ty->kind == TypeKind_struct)
+ return type_sizeof_struct(ty);
+ else if (ty->kind == TypeKind_union)
+ return type_sizeof_union(ty);
+ else
+ unreachable();
+}
+
+int type_alignof(Type* ty) {
+ if (type_is_unsized(ty)) {
+ fatal_error("type_alignof: type size cannot be determined");
+ }
+
+ if (ty->kind == TypeKind_ptr)
+ return 8;
+ else if (ty->kind == TypeKind_char)
+ return 1;
+ else if (ty->kind == TypeKind_short)
+ return 2;
+ else if (ty->kind == TypeKind_int)
+ return 4;
+ else if (ty->kind == TypeKind_long)
+ return 8;
+ else if (ty->kind == TypeKind_enum)
+ return 4;
+ else if (ty->kind == TypeKind_array)
+ return type_alignof(ty->base);
+ else if (ty->kind == TypeKind_struct)
+ return type_alignof_struct(ty);
+ else if (ty->kind == TypeKind_union)
+ return type_alignof_union(ty);
+ else
+ unreachable();
+}
+
+int to_aligned(int n, int a) {
+ return (n + a - 1) / a * a;
+}
+
+enum AstNodeKind {
+ AstNodeKind_unknown,
+ AstNodeKind_nop,
+
+ AstNodeKind_assign_expr,
+ AstNodeKind_binary_expr,
+ AstNodeKind_break_stmt,
+ AstNodeKind_cond_expr,
+ AstNodeKind_continue_stmt,
+ AstNodeKind_deref_expr,
+ AstNodeKind_do_while_stmt,
+ AstNodeKind_enum_def,
+ AstNodeKind_enum_member,
+ AstNodeKind_expr_stmt,
+ AstNodeKind_for_stmt,
+ AstNodeKind_func_call,
+ AstNodeKind_func_decl,
+ AstNodeKind_func_def,
+ AstNodeKind_gvar,
+ AstNodeKind_gvar_decl,
+ AstNodeKind_if_stmt,
+ AstNodeKind_int_expr,
+ AstNodeKind_list,
+ AstNodeKind_logical_expr,
+ AstNodeKind_lvar,
+ AstNodeKind_lvar_decl,
+ AstNodeKind_param,
+ AstNodeKind_ref_expr,
+ AstNodeKind_return_stmt,
+ AstNodeKind_str_expr,
+ AstNodeKind_struct_decl,
+ AstNodeKind_struct_def,
+ AstNodeKind_struct_member,
+ AstNodeKind_type,
+ AstNodeKind_typedef_decl,
+ AstNodeKind_unary_expr,
+ AstNodeKind_union_decl,
+ AstNodeKind_union_def,
+ AstNodeKind_union_member,
+
+ // Intermediate ASTs: they are used only in parsing, not for parse result.
+ AstNodeKind_declarator,
+};
+typedef enum AstNodeKind AstNodeKind;
+
+#define node_items __n1
+#define node_len __i1
+#define node_cap __i2
+#define node_expr __n1
+#define node_lhs __n1
+#define node_rhs __n2
+#define node_operand __n1
+#define node_cond __n1
+#define node_init __n2
+#define node_update __n3
+#define node_then __n2
+#define node_else __n3
+#define node_body __n4
+#define node_members __n1
+#define node_params __n1
+#define node_args __n1
+#define node_int_value __i1
+#define node_idx __i1
+#define node_op __i1
+#define node_stack_offset __i1
+#define node_stack_size __i1
+
+struct AstNode {
+ AstNodeKind kind;
+ const char* name;
+ Type* ty;
+ struct AstNode* __n1;
+ struct AstNode* __n2;
+ struct AstNode* __n3;
+ struct AstNode* __n4;
+ int __i1;
+ int __i2;
+};
+typedef struct AstNode AstNode;
+
+struct Program {
+ AstNode* funcs;
+ AstNode* vars;
+ const char** str_literals;
+};
+typedef struct Program Program;
+
+AstNode* ast_new(AstNodeKind kind) {
+ AstNode* ast = calloc(1, sizeof(AstNode));
+ ast->kind = kind;
+ return ast;
+}
+
+AstNode* ast_new_list(int capacity) {
+ if (capacity == 0)
+ unreachable();
+ AstNode* list = ast_new(AstNodeKind_list);
+ list->node_cap = capacity;
+ list->node_len = 0;
+ list->node_items = calloc(list->node_cap, sizeof(AstNode));
+ return list;
+}
+
+void ast_append(AstNode* list, AstNode* item) {
+ if (list->kind != AstNodeKind_list) {
+ fatal_error("ast_append: ast is not a list");
+ }
+ if (!item) {
+ return;
+ }
+ if (list->node_cap <= list->node_len) {
+ list->node_cap *= 2;
+ list->node_items = realloc(list->node_items, sizeof(AstNode) * list->node_cap);
+ memset(list->node_items + list->node_len, 0, sizeof(AstNode) * (list->node_cap - list->node_len));
+ }
+ memcpy(list->node_items + list->node_len, item, sizeof(AstNode));
+ ++list->node_len;
+}
+
+AstNode* ast_new_int(int v) {
+ AstNode* e = ast_new(AstNodeKind_int_expr);
+ e->node_int_value = v;
+ e->ty = type_new(TypeKind_int);
+ return e;
+}
+
+AstNode* ast_new_unary_expr(int op, AstNode* operand) {
+ AstNode* e = ast_new(AstNodeKind_unary_expr);
+ e->node_op = op;
+ e->node_operand = operand;
+ e->ty = type_new(TypeKind_int);
+ return e;
+}
+
+AstNode* ast_new_binary_expr(int op, AstNode* lhs, AstNode* rhs) {
+ AstNode* e = ast_new(AstNodeKind_binary_expr);
+ e->node_op = op;
+ e->node_lhs = lhs;
+ e->node_rhs = rhs;
+ if (op == TokenKind_plus) {
+ if (lhs->ty->kind == TypeKind_ptr) {
+ e->ty = lhs->ty;
+ } else if (lhs->ty->kind == TypeKind_array) {
+ e->ty = type_array_to_ptr(lhs->ty);
+ } else if (rhs->ty->kind == TypeKind_ptr) {
+ e->ty = rhs->ty;
+ } else if (rhs->ty->kind == TypeKind_array) {
+ e->ty = type_array_to_ptr(rhs->ty);
+ } else {
+ e->ty = type_new(TypeKind_int);
+ }
+ } else if (op == TokenKind_minus) {
+ if (lhs->ty->kind == TypeKind_ptr) {
+ e->ty = lhs->ty;
+ } else if (lhs->ty->kind == TypeKind_array) {
+ e->ty = type_array_to_ptr(lhs->ty);
+ } else {
+ e->ty = type_new(TypeKind_int);
+ }
+ } else {
+ e->ty = type_new(TypeKind_int);
+ }
+ return e;
+}
+
+AstNode* ast_new_assign_expr(int op, AstNode* lhs, AstNode* rhs) {
+ AstNode* e = ast_new(AstNodeKind_assign_expr);
+ e->node_op = op;
+ e->node_lhs = lhs;
+ e->node_rhs = rhs;
+ e->ty = lhs->ty;
+ return e;
+}
+
+AstNode* ast_new_assign_add_expr(AstNode* lhs, AstNode* rhs) {
+ if (lhs->ty->base) {
+ rhs = ast_new_binary_expr(TokenKind_star, rhs, ast_new_int(type_sizeof(lhs->ty->base)));
+ } else if (rhs->ty->base) {
+ lhs = ast_new_binary_expr(TokenKind_star, lhs, ast_new_int(type_sizeof(rhs->ty->base)));
+ }
+ return ast_new_assign_expr(TokenKind_assign_add, lhs, rhs);
+}
+
+AstNode* ast_new_assign_sub_expr(AstNode* lhs, AstNode* rhs) {
+ if (lhs->ty->base) {
+ rhs = ast_new_binary_expr(TokenKind_star, rhs, ast_new_int(type_sizeof(lhs->ty->base)));
+ }
+ return ast_new_assign_expr(TokenKind_assign_sub, lhs, rhs);
+}
+
+AstNode* ast_new_ref_expr(AstNode* operand) {
+ AstNode* e = ast_new(AstNodeKind_ref_expr);
+ e->node_operand = operand;
+ e->ty = type_new_ptr(operand->ty);
+ return e;
+}
+
+AstNode* ast_new_deref_expr(AstNode* operand) {
+ AstNode* e = ast_new(AstNodeKind_deref_expr);
+ e->node_operand = operand;
+ e->ty = operand->ty->base;
+ return e;
+}
+
+AstNode* ast_new_member_access_expr(AstNode* obj, const char* name) {
+ AstNode* e = ast_new(AstNodeKind_deref_expr);
+ e->node_operand = ast_new_binary_expr(TokenKind_plus, obj, ast_new_int(type_offsetof(obj->ty->base, name)));
+ e->ty = type_member_typeof(obj->ty->base, name);
+ e->node_operand->ty = type_new_ptr(e->ty);
+ return e;
+}
+
+int type_sizeof_struct(Type* ty) {
+ int next_offset = 0;
+ int struct_align = 0;
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ int size = type_sizeof(member->ty);
+ int align = type_alignof(member->ty);
+
+ next_offset = to_aligned(next_offset, align);
+ next_offset += size;
+ if (struct_align < align) {
+ struct_align = align;
+ }
+ }
+ return to_aligned(next_offset, struct_align);
+}
+
+int type_sizeof_union(Type* ty) {
+ int union_size = 0;
+ int union_align = 0;
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ int size = type_sizeof(member->ty);
+ int align = type_alignof(member->ty);
+
+ size = to_aligned(size, align);
+ if (union_size < size) {
+ union_size = size;
+ }
+ if (union_align < align) {
+ union_align = align;
+ }
+ }
+ return to_aligned(union_size, union_align);
+}
+
+int type_alignof_struct(Type* ty) {
+ int struct_align = 0;
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ int align = type_alignof(member->ty);
+
+ if (struct_align < align) {
+ struct_align = align;
+ }
+ }
+ return struct_align;
+}
+
+int type_alignof_union(Type* ty) {
+ int union_align = 0;
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ int align = type_alignof(member->ty);
+
+ if (union_align < align) {
+ union_align = align;
+ }
+ }
+ return union_align;
+}
+
+int type_offsetof(Type* ty, const char* name) {
+ if (ty->kind == TypeKind_union) {
+ return 0;
+ }
+ if (ty->kind != TypeKind_struct) {
+ fatal_error("type_offsetof: type is neither a struct nor a union");
+ }
+
+ int next_offset = 0;
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ int size = type_sizeof(member->ty);
+ int align = type_alignof(member->ty);
+
+ next_offset = to_aligned(next_offset, align);
+ if (strcmp(member->name, name) == 0) {
+ return next_offset;
+ }
+ next_offset += size;
+ }
+
+ fatal_error("type_offsetof: member not found");
+}
+
+Type* type_member_typeof(Type* ty, const char* name) {
+ if (ty->kind != TypeKind_struct && ty->kind != TypeKind_union) {
+ fatal_error("type_member_typeof: type is neither a struct nor a union");
+ }
+
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
+ AstNode* member = ty->def->node_members->node_items + i;
+ if (strcmp(member->name, name) == 0) {
+ return member->ty;
+ }
+ }
+
+ fatal_error("type_offsetof: member not found");
+}