aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-02 17:19:15 -0500
committerMustafa Quraish <[email protected]>2022-02-02 17:54:31 -0500
commit55f61417c7d3f6a2f4685e21b7e409ec23b7f41f (patch)
treead5d78d16f3f66046bdac74c2eade63414e55c0c /src
parentFix examples to include return type on main function (diff)
downloadcup-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.
Diffstat (limited to 'src')
-rw-r--r--src/ast.c59
-rw-r--r--src/ast.h21
-rw-r--r--src/parser.c119
-rw-r--r--src/types.c186
-rw-r--r--src/types.h26
5 files changed, 217 insertions, 194 deletions
diff --git a/src/ast.c b/src/ast.c
index 7d9f053..3eaaf61 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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);
diff --git a/src/ast.h b/src/ast.h
index 6773c0b..2056505 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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