diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-02 17:19:15 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-02 17:54:31 -0500 |
| commit | 55f61417c7d3f6a2f4685e21b7e409ec23b7f41f (patch) | |
| tree | ad5d78d16f3f66046bdac74c2eade63414e55c0c | |
| parent | Fix examples to include return type on main function (diff) | |
| download | cup-55f61417c7d3f6a2f4685e21b7e409ec23b7f41f.tar.xz cup-55f61417c7d3f6a2f4685e21b7e409ec23b7f41f.zip | |
Move type-related stuff to a separate file
It was getting a bit unwieldy in `parser.c`, and this will potentially
help when we start dealing with more complex type-stuff such as
casting / conversions / etc.
| -rw-r--r-- | src/ast.c | 59 | ||||
| -rw-r--r-- | src/ast.h | 21 | ||||
| -rw-r--r-- | src/parser.c | 119 | ||||
| -rw-r--r-- | src/types.c | 186 | ||||
| -rw-r--r-- | src/types.h | 26 |
5 files changed, 217 insertions, 194 deletions
@@ -43,48 +43,6 @@ NodeType binary_token_to_op(TokenType type) } } - -char *data_type_to_str(DataType type) -{ - switch (type) - { - case TYPE_NONE: return "void"; - case TYPE_INT: return "int"; - case TYPE_PTR: return "*"; - default: assert(false && "Unreachable"); - } -} - -bool type_equals(Type *a, Type *b) -{ - if (a == NULL && b == NULL) - return true; - if (a == NULL || b == NULL) - return false; - return a->type == b->type && type_equals(a->ptr, b->ptr); -} - -i64 size_for_type(Type *type) -{ - switch (type->type) - { - case TYPE_INT: return 8; - case TYPE_PTR: return 8; - default: assert(false && "Unreachable type"); - } -} -Type *type_new(DataType type) -{ - // For the core types, we don't need to allocate any memory, just - // return a pointer to a static instance. - static Type type_int = {.type = TYPE_INT, .ptr = NULL}; - if (type == TYPE_INT) return &type_int; - - Type *self = calloc(sizeof(Type), 1); - self->type = type; - return self; -} - Node *Node_from_int_literal(i64 value) { Node *self = Node_new(AST_LITERAL); @@ -93,13 +51,6 @@ Node *Node_from_int_literal(i64 value) return self; } -void print_type_to_file(FILE *out, Type *type) -{ - if (type->type == TYPE_PTR) - print_type_to_file(out, type->ptr); - fprintf(out, "%s", data_type_to_str(type->type)); -} - char *node_type_to_str(NodeType type) { switch (type) @@ -205,9 +156,7 @@ static void do_print_ast(Node *node, int depth) assert(node->variable && node->variable->name); printf("%s\n", node->variable->name); } else if (node->type == AST_VARDECL) { - printf("var %s (", node->var_decl.var.name); - print_type_to_file(stdout, node->var_decl.var.type); - printf(")"); + printf("var %s (%s)", node->var_decl.var.name, type_to_str(node->var_decl.var.type)); if (node->var_decl.value != NULL) { printf(" = \n"); do_print_ast(node->var_decl.value, depth + 1); @@ -233,15 +182,13 @@ void dump_func(Node *node, int depth) printf("fn %s(", node->func.name); for (int i = 0; i < node->func.num_args; i++) { if (i > 0) printf(", "); - printf("%s: ", node->func.args[i].name); - print_type_to_file(stdout, node->func.args[i].type); + printf("%s: %s", node->func.args[i].name, type_to_str(node->func.args[i].type)); printf("[[%lld]]", node->func.args[i].offset); } printf(")"); if (node->func.return_type->type != TYPE_NONE) { // FIXME: Print return type properly - printf(" -> "); - print_type_to_file(stdout, node->func.return_type); + printf(" -> %s", type_to_str(node->func.return_type)); } do_print_ast(node->func.body, depth + 1); @@ -1,7 +1,7 @@ #pragma once -#include "common.h" #include "tokens.h" +#include "types.h" #define ENUM_AST_TYPES(F) \ F(OP_NEG, "neg") \ @@ -55,27 +55,8 @@ char *node_type_to_str(NodeType type); bool is_binary_op(NodeType type); bool is_unary_op(NodeType type); bool is_expression(NodeType type); - bool is_lvalue(NodeType type); -typedef enum { - TYPE_NONE, - TYPE_INT, - TYPE_PTR, -} DataType; - -char *data_type_to_str(DataType type); - -typedef struct data_type_node { - DataType type; - struct data_type_node *ptr; -} Type; - -Type *type_new(DataType type); -i64 size_for_type(Type *type); -bool type_equals(Type *a, Type *b); -void print_type_to_file(FILE *out, Type *type); - typedef struct { char *name; Type *type; diff --git a/src/parser.c b/src/parser.c index e391500..fe0802f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -329,123 +329,6 @@ Node *parse_identifier(Lexer *lexer) return NULL; } -Node *handle_unary_expr_types(Node *node, Token *token) -{ - Type *old_type = node->unary_expr->expr_type; - - if (node->type == OP_NOT) { - node->expr_type = type_new(TYPE_INT); - } else if (node->type == OP_ADDROF) { - Type *ptr = type_new(TYPE_PTR); - ptr->ptr = old_type; - node->expr_type = ptr; - } else if (node->type == OP_DEREF) { - if (old_type->type != TYPE_PTR) - die_location(token->loc, "Cannot dereference non-pointer type"); - node->expr_type = old_type->ptr; - } else if (node->type == OP_NEG) { - if (old_type->type != TYPE_INT) - die_location(token->loc, "Cannot negate non-integer type"); - node->expr_type = type_new(TYPE_INT); - } else { - // Default to not changing the type - node->expr_type = old_type; - } - // die_location(token->loc, "Unknown unary expression type in handle_unary_expr_types\n"); - return node; -} - -Node *handle_binary_expr_types(Node *node, Token *token) -{ - Type *left = node->binary.left->expr_type; - Type *right = node->binary.right->expr_type; - - switch (node->type) - { - case OP_PLUS: { - if (left->type == TYPE_INT && right->type == TYPE_INT) { - node->expr_type = type_new(TYPE_INT); - } else if (left->type == TYPE_PTR && right->type == TYPE_INT) { - node->expr_type = left; - // Pointer arithmetic! - Node *mul = Node_new(OP_MUL); - mul->binary.left = node->binary.right; - mul->binary.right = Node_new(AST_LITERAL); - mul->binary.right->literal.type = type_new(TYPE_INT); - mul->binary.right->literal.as_int = size_for_type(left->ptr); - node->binary.right = mul; - } else if (left->type == TYPE_INT && right->type == TYPE_PTR) { - node->expr_type = right; - // Pointer arithmetic! - Node *mul = Node_new(OP_MUL); - mul->binary.left = node->binary.left; - mul->binary.right = Node_new(AST_LITERAL); - mul->binary.right->literal.type = type_new(TYPE_INT); - mul->binary.right->literal.as_int = size_for_type(right->ptr); - node->binary.left = mul; - } else { - die_location(token->loc, "Cannot add non-integer types"); - } - } break; - - case OP_MINUS: { - if (left->type == TYPE_INT && right->type == TYPE_INT) { - node->expr_type = type_new(TYPE_INT); - } else if (left->type == TYPE_PTR && right->type == TYPE_INT) { - node->expr_type = left; - // Pointer arithmetic! - Node *mul = Node_new(OP_MUL); - mul->binary.left = node->binary.right; - mul->binary.right = Node_from_int_literal(size_for_type(left->ptr)); - node->binary.right = mul; - } else if (left->type == TYPE_INT && right->type == TYPE_PTR) { - node->expr_type = right; - // Pointer arithmetic! - Node *mul = Node_new(OP_MUL); - mul->binary.left = node->binary.left; - mul->binary.right = Node_from_int_literal(size_for_type(right->ptr)); - node->binary.left = mul; - } else if (left->type == TYPE_PTR && right->type == TYPE_PTR) { - // TODO: Check for different pointer types - node->expr_type = type_new(TYPE_INT); - // Divide by size of pointer - Node *div = Node_new(OP_DIV); - div->binary.left = node; - div->binary.right = Node_from_int_literal(size_for_type(left->ptr)); - div->expr_type = node->expr_type; - node = div; - } else { - die_location(token->loc, "Cannot subtract non-integer types"); - } - } break; - - case OP_DIV: - case OP_MOD: - case OP_MUL: { - if (left->type == TYPE_INT && right->type == TYPE_INT) { - node->expr_type = left; - } else { - die_location(token->loc, "Cannot do operation `%s` non-integer types", node_type_to_str(node->type)); - } - } break; - - case OP_EQ: - case OP_NEQ: - case OP_LT: - case OP_GT: - case OP_LEQ: - case OP_GEQ: - case OP_AND: - case OP_OR: { - node->expr_type = type_new(TYPE_INT); - } break; - - default: - die_location(token->loc, "Unknown binary expression type in handle_binary_expr_types\n"); - } - return node; -} - Node *parse_factor(Lexer *lexer) { // TODO: We need to properly handle type conversions / operations with different types @@ -506,7 +389,7 @@ Node *parse_factor(Lexer *lexer) Node *right = next_parser(lexer); \ op->binary.left = expr; \ op->binary.right = right; \ - op = handle_binary_expr_types(op, &token); \ + op = handle_binary_expr_types(op, &token); \ expr = op; \ token = Lexer_peek(lexer); \ } \ diff --git a/src/types.c b/src/types.c new file mode 100644 index 0000000..bf855de --- /dev/null +++ b/src/types.c @@ -0,0 +1,186 @@ +#include "parser.h" +#include "utils.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + + +bool type_equals(Type *a, Type *b) +{ + if (a == NULL && b == NULL) + return true; + if (a == NULL || b == NULL) + return false; + return a->type == b->type && type_equals(a->ptr, b->ptr); +} + +i64 size_for_type(Type *type) +{ + switch (type->type) + { + case TYPE_INT: return 8; + case TYPE_PTR: return 8; + default: assert(false && "Unreachable type"); + } +} + +Type *type_new(DataType type) +{ + // For the core types, we don't need to allocate any memory, just + // return a pointer to a static instance. + static Type type_int = {.type = TYPE_INT, .ptr = NULL}; + if (type == TYPE_INT) return &type_int; + + Type *self = calloc(sizeof(Type), 1); + self->type = type; + return self; +} + +static char *data_type_to_str(DataType type) +{ + switch (type) + { + case TYPE_NONE: return "void"; + case TYPE_INT: return "int"; + case TYPE_PTR: return "*"; + default: assert(false && "Unreachable"); + } +} + +char *type_to_str(Type *type) +{ + // FIXME: Handle array types. + + // TODO: This allocates memory and we probably don't want to do that. + // TODO: Probably want to increase this size once we have longer types + char *str = calloc(sizeof(char), 32); + int ptr_count = 0; + for (; type->type == TYPE_PTR; type = type->ptr) + ptr_count++; + + + // FIXME: This is inefficient as all hell but this will only really be + // used for error reporting. + strcat(str, data_type_to_str(type->type)); + for (int i = 0; i < ptr_count; i++) + strcat(str, "*"); + return str; +} + +Node *handle_unary_expr_types(Node *node, Token *token) +{ + Type *old_type = node->unary_expr->expr_type; + + if (node->type == OP_NOT) { + node->expr_type = type_new(TYPE_INT); + } else if (node->type == OP_ADDROF) { + Type *ptr = type_new(TYPE_PTR); + ptr->ptr = old_type; + node->expr_type = ptr; + } else if (node->type == OP_DEREF) { + if (old_type->type != TYPE_PTR) + die_location(token->loc, "Cannot dereference non-pointer type"); + node->expr_type = old_type->ptr; + } else if (node->type == OP_NEG) { + if (old_type->type != TYPE_INT) + die_location(token->loc, "Cannot negate non-integer type"); + node->expr_type = type_new(TYPE_INT); + } else { + // Default to not changing the type + node->expr_type = old_type; + } + // die_location(token->loc, "Unknown unary expression type in handle_unary_expr_types\n"); + return node; +} + +Node *handle_binary_expr_types(Node *node, Token *token) +{ + Type *left = node->binary.left->expr_type; + Type *right = node->binary.right->expr_type; + + switch (node->type) + { + case OP_PLUS: { + if (left->type == TYPE_INT && right->type == TYPE_INT) { + node->expr_type = type_new(TYPE_INT); + } else if (left->type == TYPE_PTR && right->type == TYPE_INT) { + node->expr_type = left; + // Pointer arithmetic! + Node *mul = Node_new(OP_MUL); + mul->binary.left = node->binary.right; + mul->binary.right = Node_new(AST_LITERAL); + mul->binary.right->literal.type = type_new(TYPE_INT); + mul->binary.right->literal.as_int = size_for_type(left->ptr); + node->binary.right = mul; + } else if (left->type == TYPE_INT && right->type == TYPE_PTR) { + node->expr_type = right; + // Pointer arithmetic! + Node *mul = Node_new(OP_MUL); + mul->binary.left = node->binary.left; + mul->binary.right = Node_new(AST_LITERAL); + mul->binary.right->literal.type = type_new(TYPE_INT); + mul->binary.right->literal.as_int = size_for_type(right->ptr); + node->binary.left = mul; + } else { + die_location(token->loc, "Cannot add non-integer types"); + } + } break; + + case OP_MINUS: { + if (left->type == TYPE_INT && right->type == TYPE_INT) { + node->expr_type = type_new(TYPE_INT); + } else if (left->type == TYPE_PTR && right->type == TYPE_INT) { + node->expr_type = left; + // Pointer arithmetic! + Node *mul = Node_new(OP_MUL); + mul->binary.left = node->binary.right; + mul->binary.right = Node_from_int_literal(size_for_type(left->ptr)); + node->binary.right = mul; + } else if (left->type == TYPE_INT && right->type == TYPE_PTR) { + node->expr_type = right; + // Pointer arithmetic! + Node *mul = Node_new(OP_MUL); + mul->binary.left = node->binary.left; + mul->binary.right = Node_from_int_literal(size_for_type(right->ptr)); + node->binary.left = mul; + } else if (left->type == TYPE_PTR && right->type == TYPE_PTR) { + // TODO: Check for different pointer types + node->expr_type = type_new(TYPE_INT); + // Divide by size of pointer + Node *div = Node_new(OP_DIV); + div->binary.left = node; + div->binary.right = Node_from_int_literal(size_for_type(left->ptr)); + div->expr_type = node->expr_type; + node = div; + } else { + die_location(token->loc, "Cannot subtract non-integer types"); + } + } break; + + case OP_DIV: + case OP_MOD: + case OP_MUL: { + if (left->type == TYPE_INT && right->type == TYPE_INT) { + node->expr_type = left; + } else { + die_location(token->loc, "Cannot do operation `%s` non-integer types", node_type_to_str(node->type)); + } + } break; + + case OP_EQ: + case OP_NEQ: + case OP_LT: + case OP_GT: + case OP_LEQ: + case OP_GEQ: + case OP_AND: + case OP_OR: { + node->expr_type = type_new(TYPE_INT); + } break; + + default: + die_location(token->loc, "Unknown binary expression type in handle_binary_expr_types\n"); + } + return node; +} diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..5f6f45a --- /dev/null +++ b/src/types.h @@ -0,0 +1,26 @@ +#pragma once + +#include "common.h" +#include <stdio.h> + +typedef enum { + TYPE_NONE, + TYPE_INT, + TYPE_PTR, +} DataType; + +typedef struct data_type_node { + DataType type; + struct data_type_node *ptr; +} Type; + +Type *type_new(DataType type); +i64 size_for_type(Type *type); +bool type_equals(Type *a, Type *b); +char *type_to_str(Type *type); + +// Type checking / casting expressions to right types +typedef struct ast_node Node; + +Node *handle_unary_expr_types(Node *, Token *); +Node *handle_binary_expr_types(Node *, Token *);
\ No newline at end of file |