diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-02 03:03:01 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-02 03:03:01 -0500 |
| commit | ec29bfb9563bcec1cc2a054cc2c1942fd5c65cb1 (patch) | |
| tree | 7911b1e6fe12c4154656ed4915e5be7c95729707 | |
| parent | Refactor variable access+assignment in terms of `generate_lvalue()` (diff) | |
| download | cup-ec29bfb9563bcec1cc2a054cc2c1942fd5c65cb1.tar.xz cup-ec29bfb9563bcec1cc2a054cc2c1942fd5c65cb1.zip | |
Add support for pointers! (tests missing)
This commit adds initial support for taking pointers / dereferencing.
The type system is still a bit of a hot mess, so all type information
is actually not looked at, but the functionality still seems to be
there.
Still need to add some tests for pointers/dereferencing to ensure that
it works in some edge cases as well.
| -rw-r--r-- | src/ast.c | 1 | ||||
| -rw-r--r-- | src/ast.h | 3 | ||||
| -rw-r--r-- | src/generator.c | 29 | ||||
| -rw-r--r-- | src/parser.c | 14 |
4 files changed, 30 insertions, 17 deletions
@@ -140,6 +140,7 @@ bool is_lvalue(NodeType type) { case AST_LOCAL_VAR: case AST_GLOBAL_VAR: + case OP_DEREF: // FIXME: Should this be the case? return true; default: return false; } @@ -9,7 +9,8 @@ F(OP_BWINV, "~") \ F(OP_PLUS, "+") \ F(OP_MINUS, "-") \ - F(OP_ADDROF, "&") \ + F(OP_ADDROF, "&") \ + F(OP_DEREF, "*") \ F(OP_MUL, "*") \ F(OP_DIV, "/") \ F(OP_MOD, "%") \ diff --git a/src/generator.c b/src/generator.c index 9e898e6..8663116 100644 --- a/src/generator.c +++ b/src/generator.c @@ -26,18 +26,20 @@ void make_syscall(i64 syscall_no, FILE *out) { void generate_expr_into_rax(Node *expr, FILE *out); -void generate_lvalue_into_rbx(Node *node, FILE *out) +void generate_lvalue_into_rax(Node *node, FILE *out) { assert(is_lvalue(node->type)); i64 offset = node->variable->offset; if (node->type == AST_LOCAL_VAR) { - fprintf(out, " mov rbx, rbp\n"); - fprintf(out, " sub rbx, %lld\n", offset); + fprintf(out, " mov rax, rbp\n"); + fprintf(out, " sub rax, %lld\n", offset); } else if (node->type == AST_GLOBAL_VAR) { - fprintf(out, " mov rbx, global_vars\n"); - fprintf(out, " add rbx, %lld\n", offset); + fprintf(out, " mov rax, global_vars\n"); + fprintf(out, " add rax, %lld\n", offset); + } else if (node->type == OP_DEREF) { + generate_expr_into_rax(node->unary_expr, out); } else { - assert(false && "Unknown lvalue type in generate_lvalue_into_rbx"); + assert(false && "Unknown lvalue type in generate_lvalue_into_rax"); } } @@ -70,18 +72,19 @@ void generate_expr_into_rax(Node *expr, FILE *out) } else if (expr->type == AST_FUNCCALL) { generate_func_call(expr, out); - } else if (expr->type == AST_LOCAL_VAR) { - generate_lvalue_into_rbx(expr, out); - fprintf(out, " mov rax, [rbx]\n"); + } else if (is_lvalue(expr->type)) { + generate_lvalue_into_rax(expr, out); + fprintf(out, " mov rax, [rax]\n"); - } else if (expr->type == AST_GLOBAL_VAR) { - generate_lvalue_into_rbx(expr, out); - fprintf(out, " mov rax, [rbx]\n"); + } else if (expr->type == OP_ADDROF) { + generate_lvalue_into_rax(expr->unary_expr, out); } else if (expr->type == OP_ASSIGN) { Node *var = expr->assign.var; + generate_lvalue_into_rax(var, out); + fprintf(out, " push rax\n"); generate_expr_into_rax(expr->assign.value, out); - generate_lvalue_into_rbx(var, out); + fprintf(out, " pop rbx\n"); fprintf(out, " mov [rbx], rax\n"); } else if (expr->type == OP_NEG) { diff --git a/src/parser.c b/src/parser.c index a9a26e3..5123189 100644 --- a/src/parser.c +++ b/src/parser.c @@ -323,7 +323,7 @@ Node *parse_factor(Lexer *lexer) { // TODO: Parse more complicated things Token token = Lexer_peek(lexer); - Node *expr; + Node *expr = NULL; if (token.type == TOKEN_MINUS) { Lexer_next(lexer); expr = Node_new(OP_NEG); @@ -348,9 +348,17 @@ Node *parse_factor(Lexer *lexer) Lexer_next(lexer); expr = Node_new(OP_ADDROF); expr->unary_expr = parse_factor(lexer); + if (!is_lvalue(expr->unary_expr->type)) + die_location(token.loc, "Cannot take address of non-lvalue"); + } else if (token.type == TOKEN_STAR) { + Lexer_next(lexer); + expr = Node_new(OP_DEREF); + // TODO: IMPORTANT: Make sure the `unary_expr` is a pointer type. For this + // to work, we need to to be able to evaluate the type for complex expressions, + // which we do not support as of now. + expr->unary_expr = parse_factor(lexer); } else { die_location(token.loc, ": Expected token found in parse_factor: `%s`", token_type_to_str(token.type)); - exit(1); } return expr; } @@ -410,7 +418,7 @@ Node *parse_expression(Lexer *lexer) Node *node = parse_conditional_exp(lexer); // FIXME: This is a hack to handle assignment expressions // and can probably be done properly. - if (node->type == AST_LOCAL_VAR || node->type == AST_GLOBAL_VAR) { + if (is_lvalue(node->type)) { Token token = Lexer_peek(lexer); if (token.type == TOKEN_ASSIGN) { Lexer_next(lexer); |