compiler

Unnamed Compiled Systems Language Project
git clone http://frotz.net/git/compiler.git
Log | Files | Refs

commit cfe2d815bea0dd47d0ebeae933d673f4bf16cd6d
parent 7297370069e8d96cc8a5b77bd53f8e7cd01bd0c2
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 15 Mar 2020 12:53:04 -0700

compiler: logical and/or improvements

- compatible_type() now adjusts items as needed
  (so an iComp can become and iBool for param/assignment/etc)
- correctly flag missing parameters to function calls
- don't allow parse_operand() to find "nothing" and leave x
  uninitialized
- testcase to illustrate short-circuit behaviour working

Diffstat:
Msrc/compiler.c | 45++++++++++++++++++++++++++++++++++++++++-----
Mtest/1031-logical-and-or.log | 37+++++++++++++++++++++++++++++++++++++
Mtest/1031-logical-and-or.src | 27++++++++++++++++++++++++++-
3 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/src/compiler.c b/src/compiler.c @@ -370,6 +370,8 @@ void gen_ref_param(u32 n, Item val); // call func, consumes parameters and func void gen_call(Item func); +void gen_bool_from_comp(Item x); + // generate a forward conditional branch // consumes x which must be Bool or Cond // returns address to fixup @@ -561,9 +563,14 @@ bool same_type(Type a, Type b) { } // for assignments, etc -bool compatible_type(Type dst, Type src) { +bool compatible_type(Type dst, Type src, Item x) { + if (x->kind == iComp) { + // collapse comparisons into bools for storage + gen_bool_from_comp(x); + src = ctx.type_bool; + } if (dst->kind == tInt32) { - if (src->kind == tByte) { + if ((src->kind == tByte) || (src->kind == tBool)) { return true; } } @@ -1028,6 +1035,8 @@ void parse_operand(Item x) { error("unknown identifier '%s'", str->text); } gen_item_from_obj(x, obj); + } else { + error("invalid expression"); } next(); } @@ -1065,12 +1074,15 @@ void parse_primary_expr(Item x) { u32 n = 0; Object param = x->type->first; while (param != nil) { + if (ctx.tok == tCPAREN) { + error("too few parameters for %s()", x->type->obj->name->text); + } if (n != 0) { require(tCOMMA); } ItemRec y; parse_expr(&y); - if (!compatible_type(param->type, y.type)) { + if (!compatible_type(param->type, y.type, &y)) { error("incompatible type for parameter '%s'\n", param->name->text); } if (param->type->kind == tArray) { @@ -1221,7 +1233,7 @@ void parse_expr(Item x) { ItemRec y; // if y goto yup - parse_rel_expr(&y); + parse_and_expr(&y); gen_branch_cond(&y, true); add_scope_fixup(outer); } @@ -1430,7 +1442,7 @@ void parse_return() { x.type = ctx.type_void; } else { parse_expr(&x); - if (!compatible_type(ctx.fn->type->base, x.type)) { + if (!compatible_type(ctx.fn->type->base, x.type, &x)) { error("return types do not match"); } require(tSEMI); @@ -1593,6 +1605,9 @@ void parse_expr_statement() { next(); ItemRec y; parse_expr(&y); + if (!compatible_type(x.type, y.type, &x)) { + error("incompatible type in assignment"); + } gen_store(&y, &x); } else if ((ctx.tok & tcMASK) == tcAEQOP) { u32 op = ctx.tok - tADDEQ; @@ -2169,6 +2184,25 @@ void gen_load_bool2(Item x) { emit_opi(MOV, x->r, 0, !x->a); } +void gen_bool_from_comp(Item x) { + gen_trace("bool_from_cond", x, nil); + emit_op(SUB, x->a, x->a, x->b); + put_reg(x->b); + u32 l0_br_to_true = ctx.pc; + emit_bi(rel_op_to_cc(x->r), 0); + emit_opi(MOV, x->a, 0, 0); + u32 l1_br_to_done = ctx.pc; + emit_bi(AL, 0); + fixup_branch_fwd(l0_br_to_true); + emit_opi(MOV, x->a, 0, 1); + fixup_branch_fwd(l1_br_to_done); + x->kind = iReg; + x->type = ctx.type_bool; + x->r = x->a; + x->a = 0; + x->b = 0; +} + u32 gen_branch_cond(Item x, bool sense) { gen_trace_n("branch_cond", sense, x, nil); u32 cc; @@ -2389,6 +2423,7 @@ void gen_rel_op(u32 op, Item x, Item y) { // fuse x and y items into the new Comparison Item x x->kind = iComp; + x->type = ctx.type_bool; x->a = x->r; x->b = y->r; x->r = op; diff --git a/test/1031-logical-and-or.log b/test/1031-logical-and-or.log @@ -8,6 +8,43 @@ D 00000106 D 00000207 D 00000208 D 00000109 +D 00000333 +D 00000666 +D 00000999 +D 00002200 +D 00000333 +D 00000666 +D 00000999 +D 00002201 +D 00000333 +D 00000666 +D 00000999 +D 00002202 +D 00000333 +D 00001103 +D 00000333 +D 00000666 +D 00000999 +D 00002204 +D 00000333 +D 00000666 +D 00000999 +D 00002205 +D 00000333 +D 00000666 +D 00001106 +D 00000333 +D 00000666 +D 00000999 +D 00002207 +D 00000333 +D 00000666 +D 00000999 +D 00002208 +D 00000333 +D 00000666 +D 00000999 +D 00001109 D 00000400 D 00000401 D 00000402 diff --git a/test/1031-logical-and-or.src b/test/1031-logical-and-or.src @@ -1,4 +1,24 @@ +func is_three(n i32) bool { + _hexout_(0x333); + return n == 3; +} +func is_six(n i32) bool { + _hexout_(0x666); + return n == 6; +} +func is_nine(n i32) bool { + _hexout_(0x999); + return n == 9; +} + +func or_test2(n i32) { + if (is_three(n) || is_six(n) || is_nine(n)) { + _hexout_(n | 0x1100); + } else { + _hexout_(n | 0x2200); + } +} func or_test(n i32) { if (n == 3 || n == 6 || n == 9) { @@ -7,7 +27,6 @@ func or_test(n i32) { _hexout_(n | 0x200); } } - func and_test(n i32) { if ((n & 1 == 1) && (n & 2 == 2) && (n < 8)) { _hexout_(n | 0x300); @@ -23,9 +42,15 @@ func start() i32 { n = n + 1; } n = 0; + while n < 10 { + or_test2(n); + n = n + 1; + } + n = 0; while n < 16 { and_test(n); n = n + 1; } return 0x42; } +