From 6a376cfd6f89a6ceb39a8c425cf8095647170c7e Mon Sep 17 00:00:00 2001 From: Mustafa Quraish Date: Fri, 4 Feb 2022 07:38:53 -0500 Subject: Add `void` type and allow void* to be assigned to other ptr types --- src/parser.c | 12 +++++++----- src/tokens.h | 1 + src/types.c | 10 +++++++++- src/types.h | 2 +- std/common.cup | 8 ++++++-- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/parser.c b/src/parser.c index 267947c..49c9689 100644 --- a/src/parser.c +++ b/src/parser.c @@ -227,6 +227,9 @@ Type *parse_type(Lexer *lexer) } else if (token.type == TOKEN_CHAR) { Lexer_next(lexer); type = type_new(TYPE_CHAR); + } else if (token.type == TOKEN_VOID) { + Lexer_next(lexer); + type = type_new(TYPE_VOID); } else { assert_token(token, TOKEN_IDENTIFIER); // TODO: Don't allow a type to contain itself. @@ -590,7 +593,6 @@ Node *parse_factor(Lexer *lexer) } else if (token.type == TOKEN_MINUSMINUS) { die_location(token.loc, "Post-decrementing is not supported\n"); } else if (token.type == TOKEN_DOT) { - // TODO: Pointer to struct if (!is_struct_or_struct_ptr(expr->expr_type)) die_location(token.loc, "Cannot access member of non-struct type"); @@ -607,8 +609,8 @@ Node *parse_factor(Lexer *lexer) member->member.expr = expr; member->member.offset = struct_type->fields.offset[index]; member->member.is_ptr = (expr->expr_type->type == TYPE_PTR); - expr = member; + expr = decay_array_to_pointer(member, &token); } else { break; } @@ -685,8 +687,8 @@ Node *parse_expression(Lexer *lexer) Lexer_next(lexer); Node *assign = Node_new(OP_ASSIGN); assign->assign.var = node; - assign->assign.value = parse_expression(lexer); - + Node *expr = parse_expression(lexer); + assign->assign.value = expr; if (!is_convertible(node->expr_type, assign->assign.value->expr_type)) { fprintf(stderr, "- Variable type: %s\n", type_to_str(assign->assign.var->expr_type)); @@ -901,7 +903,7 @@ Node *parse_func(Lexer *lexer) func->func.return_type = parse_type(lexer); } else { // No return type, void fn. - func->func.return_type = type_new(TYPE_NONE); + func->func.return_type = type_new(TYPE_VOID); } // Make sure there's no funny business with the stack offset diff --git a/src/tokens.h b/src/tokens.h index 7045a5c..d0f216a 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -60,6 +60,7 @@ F(TOKEN_RETURN, "return") \ F(TOKEN_STRUCT, "struct") \ F(TOKEN_UNION, "union") \ + F(TOKEN_VOID, "void") \ F(TOKEN_WHILE, "while") \ F(TOKEN_IMPORT, "import") \ diff --git a/src/types.c b/src/types.c index 8ac4c77..c44f88d 100644 --- a/src/types.c +++ b/src/types.c @@ -21,6 +21,12 @@ bool is_convertible(Type *from, Type *to) { if (from->type == TYPE_ANY || to->type == TYPE_ANY) return true; + + // Allow converstions to and from void* to any other pointer type + if (from->type == TYPE_PTR && to->type == TYPE_PTR) + if (from->ptr->type == TYPE_VOID || to->ptr->type == TYPE_VOID) + return true; + // TODO: Should we rause a warning if the target type is narrower // than the source type? if (is_int_type(from) && is_int_type(to)) @@ -52,9 +58,11 @@ Type *type_new(DataType type) static Type type_int = {.type = TYPE_INT, .ptr = NULL}; static Type type_char = {.type = TYPE_CHAR, .ptr = NULL}; static Type type_any = {.type = TYPE_ANY, .ptr = NULL}; + static Type type_void = {.type = TYPE_VOID, .ptr = NULL}; if (type == TYPE_INT) return &type_int; if (type == TYPE_CHAR) return &type_char; if (type == TYPE_ANY) return &type_any; + if (type == TYPE_VOID) return &type_void; Type *self = calloc(sizeof(Type), 1); self->type = type; @@ -102,7 +110,7 @@ static char *data_type_to_str(Type *type) { switch (type->type) { - case TYPE_NONE: return "void"; + case TYPE_VOID: return "void"; case TYPE_INT: return "int"; case TYPE_PTR: return "*"; case TYPE_ARRAY: return "array"; diff --git a/src/types.h b/src/types.h index 22c0d5f..2b9353d 100644 --- a/src/types.h +++ b/src/types.h @@ -4,7 +4,7 @@ #include typedef enum { - TYPE_NONE, + TYPE_VOID, TYPE_ANY, // This is a hack for builtins till we can cast types TYPE_INT, TYPE_CHAR, diff --git a/std/common.cup b/std/common.cup index 24e24b7..68cf3a6 100644 --- a/std/common.cup +++ b/std/common.cup @@ -1,10 +1,14 @@ + const true = 1; const false = 0; +// This should really be a constant, but we only allow integers... +let null: void*; // Zero initialized by default. + /////////////////////////////////////////////////////////////////////////////// // Syscalls -fn write(fd: int, s: char*, n: int): int { +fn write(fd: int, s: void*, n: int): int { return syscall3(SYS_write, fd, s, n); } @@ -12,7 +16,7 @@ fn exit(status: int): int { return syscall1(SYS_exit, status); } -fn read(fd: int, s: char*, n: int): int { +fn read(fd: int, s: void*, n: int): int { return syscall3(SYS_read, fd, s, n); } -- cgit v1.2.3