From f9d970a0535ec3ae4aaff6842788a89b139cfdaa Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Fri, 1 May 2020 17:48:09 -0400 Subject: made output for void pointer arithmetic standard-compliant --- cgen.c | 32 +++++++++++++++++++++++++++----- main.c | 2 -- test.toc | 30 +++++++++++++++++++++++++++++- tests/ptr_arithmetic.toc | 33 +++++++++++++++++++++++++++++++++ tests/ptr_arithmetic_expected | 2 ++ tests/test.sh | 1 + 6 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 tests/ptr_arithmetic.toc create mode 100644 tests/ptr_arithmetic_expected 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 -- cgit v1.2.3