aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-02 03:03:01 -0500
committerMustafa Quraish <[email protected]>2022-02-02 03:03:01 -0500
commitec29bfb9563bcec1cc2a054cc2c1942fd5c65cb1 (patch)
tree7911b1e6fe12c4154656ed4915e5be7c95729707 /src
parentRefactor variable access+assignment in terms of `generate_lvalue()` (diff)
downloadcup-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.
Diffstat (limited to 'src')
-rw-r--r--src/ast.c1
-rw-r--r--src/ast.h3
-rw-r--r--src/generator.c29
-rw-r--r--src/parser.c14
4 files changed, 30 insertions, 17 deletions
diff --git a/src/ast.c b/src/ast.c
index 2a388bb..4d4eb9b 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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;
}
diff --git a/src/ast.h b/src/ast.h
index 287f51b..0966550 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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);