summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-05-01 17:48:09 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-05-01 17:48:09 -0400
commitf9d970a0535ec3ae4aaff6842788a89b139cfdaa (patch)
tree2d07c1f9e0844e5b1ce12a7d69605a7fad17f8e9
parentc21fa1738ea08455f906deba2762cdbd591b29ad (diff)
made output for void pointer arithmetic standard-compliant
-rw-r--r--cgen.c32
-rw-r--r--main.c2
-rw-r--r--test.toc30
-rw-r--r--tests/ptr_arithmetic.toc33
-rw-r--r--tests/ptr_arithmetic_expected2
-rwxr-xr-xtests/test.sh1
6 files changed, 92 insertions, 8 deletions
diff --git a/cgen.c b/cgen.c
index 128ad16..2f98565 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1288,8 +1288,10 @@ static void cgen_expr(CGenerator *g, Expression *e) {
case EXPR_BINARY_OP: {
const char *s = "";
Expression *lhs = e->binary.lhs, *rhs = e->binary.rhs;
+ Type *lhs_type = &lhs->type;
bool handled = false;
- switch (e->binary.op) {
+ BinaryOp op = e->binary.op;
+ switch (op) {
case BINARY_SUB:
s = "-"; break;
case BINARY_ADD:
@@ -1327,13 +1329,11 @@ static void cgen_expr(CGenerator *g, Expression *e) {
case BINARY_SET_MOD:
s = "%="; break;
case BINARY_AT_INDEX: {
- Type *lhs_type = &lhs->type;
bool uses_ptr = false;
if (lhs_type->kind == TYPE_PTR) {
uses_ptr = true;
lhs_type = lhs_type->ptr;
}
- cgen_write(g, "(");
switch (lhs_type->kind) {
case TYPE_ARR:
if (uses_ptr) cgen_write(g, "(*");
@@ -1368,11 +1368,10 @@ static void cgen_expr(CGenerator *g, Expression *e) {
assert(0);
break;
}
- cgen_write(g, ")");
handled = true;
} break;
case BINARY_DOT: {
- Type *struct_type = &lhs->type;
+ Type *struct_type = lhs_type;
if (struct_type->kind == TYPE_PTR) struct_type = struct_type->ptr;
if (struct_type->kind == TYPE_STRUCT) {
cgen_write(g, "(");
@@ -1396,6 +1395,29 @@ static void cgen_expr(CGenerator *g, Expression *e) {
handled = true;
} break;
}
+ if (lhs_type->kind == TYPE_PTR && type_is_void(lhs_type->ptr)) {
+ if (op == BINARY_ADD || op == BINARY_SUB) {
+ cgen_write(g, "((");
+ cgen_type_pre(g, &e->type);
+ cgen_type_post(g, &e->type);
+ cgen_write(g, ")((char*)");
+ cgen_expr(g, lhs);
+ cgen_write(g, "%s", s);
+ cgen_expr(g, rhs);
+ cgen_write(g, "))");
+ } else if (op == BINARY_SET_ADD || op == BINARY_SET_SUB) {
+ /* lhs could have side effects so we can't just do lhs = (char *)lhs + rhs */
+ cgen_write(g, "{");
+ cgen_write(g, "void **t_ = &");
+ cgen_expr(g, lhs);
+ cgen_write(g, ";");
+ cgen_write(g, "*t_ = (char *)*t_ %c ", s[0]);
+ cgen_expr(g, rhs);
+ cgen_write(g, ";}");
+ }
+ handled = true;
+ }
+
if (handled) break;
cgen_write(g, "(");
cgen_expr(g, lhs);
diff --git a/main.c b/main.c
index 4ef211e..561dac6 100644
--- a/main.c
+++ b/main.c
@@ -8,8 +8,6 @@
/*
@TODO:
-fix eval pointer arithmetic - are we not multiplying by the size?
- - pointer arithmetic test
fix including something twice - just use the non-namespacey version if it exists or pick one namespace to use everywhere otherwise
- maybe store info about namespaces which are secretly the same as inline blocks/other namespaces in the Typer
&&, ||
diff --git a/test.toc b/test.toc
index d0f74fb..05975e8 100644
--- a/test.toc
+++ b/test.toc
@@ -1,5 +1,33 @@
#include "std/io.toc";
+#include "std/mem.toc";
-main ::= fn() {
+ptr_arithmetic_test ::= fn() total := 0 {
+ foo := news(int, 10);
+ for p, i := &foo {
+ *p = i;
+ }
+ p := &foo[0];
+
+ p += 2;
+ total += *p;
+ total += *(p + 3);
+ total += *(p - 1);
+
+ voidp : &void = &foo[7];
+ total += *(voidp as &int);
+ voidp = voidp + 8;
+ total += *(voidp as &int);
+ voidp += 8;
+ total += *(voidp as &int);
+ voidp = voidp - 8;
+ total += *(voidp as &int);
+ voidp -= 8;
+ total += *(voidp as &int);
+}
+main ::= fn() {
+ x ::= ptr_arithmetic_test();
+ y := ptr_arithmetic_test();
+ puti(x);
+ puti(y);
}
diff --git a/tests/ptr_arithmetic.toc b/tests/ptr_arithmetic.toc
new file mode 100644
index 0000000..05975e8
--- /dev/null
+++ b/tests/ptr_arithmetic.toc
@@ -0,0 +1,33 @@
+#include "std/io.toc";
+#include "std/mem.toc";
+
+ptr_arithmetic_test ::= fn() total := 0 {
+ foo := news(int, 10);
+ for p, i := &foo {
+ *p = i;
+ }
+ p := &foo[0];
+
+ p += 2;
+ total += *p;
+ total += *(p + 3);
+ total += *(p - 1);
+
+ voidp : &void = &foo[7];
+ total += *(voidp as &int);
+ voidp = voidp + 8;
+ total += *(voidp as &int);
+ voidp += 8;
+ total += *(voidp as &int);
+ voidp = voidp - 8;
+ total += *(voidp as &int);
+ voidp -= 8;
+ total += *(voidp as &int);
+}
+
+main ::= fn() {
+ x ::= ptr_arithmetic_test();
+ y := ptr_arithmetic_test();
+ puti(x);
+ puti(y);
+}
diff --git a/tests/ptr_arithmetic_expected b/tests/ptr_arithmetic_expected
new file mode 100644
index 0000000..930ba1a
--- /dev/null
+++ b/tests/ptr_arithmetic_expected
@@ -0,0 +1,2 @@
+47
+47
diff --git a/tests/test.sh b/tests/test.sh
index 75697ef..bf58042 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -4,6 +4,7 @@ tests='bf
control_flow
types
arrs_slices
+ptr_arithmetic
defer
sizeof
new