harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 0cc65bddc822f5898b71cdd5a8d644b649ca1979
parent 5c4effb3ba5c1a601d8de6f4b15f9bfc9d120a8d
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date:   Fri, 30 Apr 2021 12:16:38 +0200

implement &&=, ||= and ^^= operators

Signed-off-by: Bor Grošelj Simić <bor.groseljsimic@telemach.net>

Diffstat:
Minclude/lex.h | 7+++++--
Msrc/gen.c | 29+++++++++++++++++++++++++++--
Msrc/lex.c | 121++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/parse.c | 10++++++++--
Mtests/10-binarithms.ha | 43+++++++++++++++++++++++++++++++++++++++++--
5 files changed, 155 insertions(+), 55 deletions(-)

diff --git a/include/lex.h b/include/lex.h @@ -70,7 +70,7 @@ enum lexical_token { T_LAST_KEYWORD = T_VOID, // Operators - T_ANDEQ, + T_BANDEQ, T_BAND, T_BNOT, T_BOR, @@ -86,6 +86,7 @@ enum lexical_token { T_GREATER, T_GREATEREQ, T_LAND, + T_LANDEQ, T_LBRACE, T_LBRACKET, T_LEQUAL, @@ -93,17 +94,19 @@ enum lexical_token { T_LESSEQ, T_LNOT, T_LOR, + T_LOREQ, T_LPAREN, T_LSHIFT, T_LSHIFTEQ, T_LXOR, + T_LXOREQ, T_MINUS, T_MINUSEQ, T_MINUSMINUS, T_MODEQ, T_MODULO, T_NEQUAL, - T_OREQ, + T_BOREQ, T_PLUS, T_PLUSEQ, T_PLUSPLUS, diff --git a/src/gen.c b/src/gen.c @@ -908,6 +908,32 @@ gen_expr_assign(struct gen_context *ctx, qval_deref(&src); } gen_expression(ctx, value, &src); + } else if (expr->assign.op == BIN_LAND || expr->assign.op == BIN_LOR) { + struct qbe_statement rlabel = {0}, slabel = {0}; + struct qbe_value rbranch = {0}, sbranch = {0}, result = {0}; + rbranch.kind = QV_LABEL; + rbranch.name = strdup(genl(&rlabel, &ctx->id, "value.%d")); + sbranch.kind = QV_LABEL; + sbranch.name = strdup(genl(&slabel, &ctx->id, "short_circuit.%d")); + + struct qbe_value load; + gen_loadtemp(ctx, &load, &src, otype, type_is_signed(objtype)); + if (expr->binarithm.op == BIN_LAND) { + pushi(ctx->current, NULL, Q_JNZ, &load, &rbranch, + &sbranch, NULL); + } else { + pushi(ctx->current, NULL, Q_JNZ, &load, &sbranch, + &rbranch, NULL); + } + + push(&ctx->current->body, &rlabel); + gen_temp(ctx, &result, otype, "assign.result.%d"); + gen_expression(ctx, value, &result); + gen_store(ctx, &src, &result); + if (!value->terminates) { + pushi(ctx->current, NULL, Q_JMP, &sbranch, NULL); + } + push(&ctx->current->body, &slabel); } else { struct qbe_value v = {0}; gen_temp(ctx, &v, vtype, "assign.value.%d"); @@ -917,8 +943,7 @@ gen_expr_assign(struct gen_context *ctx, gen_temp(ctx, &result, otype, "assign.result.%d"); struct qbe_value load; - gen_loadtemp(ctx, &load, &src, otype, - type_is_signed(objtype)); + gen_loadtemp(ctx, &load, &src, otype, type_is_signed(objtype)); pushi(ctx->current, &result, binarithm_for_op(expr->assign.op, otype, type_is_signed(objtype)), diff --git a/src/lex.c b/src/lex.c @@ -77,7 +77,7 @@ static const char *tokens[] = { [T_VOID] = "void", // Operators - [T_ANDEQ] = "&=", + [T_BANDEQ] = "&=", [T_BAND] = "&", [T_BNOT] = "~", [T_BOR] = "|", @@ -93,6 +93,7 @@ static const char *tokens[] = { [T_GREATER] = ">", [T_GREATEREQ] = ">=", [T_LAND] = "&&", + [T_LANDEQ] = "&&=", [T_LBRACE] = "{", [T_LBRACKET] = "[", [T_LEQUAL] = "==", @@ -100,17 +101,19 @@ static const char *tokens[] = { [T_LESSEQ] = "<=", [T_LNOT] = "!", [T_LOR] = "||", + [T_LOREQ] = "||=", [T_LPAREN] = "(", [T_LSHIFT] = "<<", [T_LSHIFTEQ] = "<<=", [T_LXOR] = "^^", + [T_LXOREQ] = "^^=", [T_MINUS] = "-", [T_MINUSEQ] = "-=", [T_MINUSMINUS] = "--", [T_MODEQ] = "%=", [T_MODULO] = "%", [T_NEQUAL] = "!=", - [T_OREQ] = "|=", + [T_BOREQ] = "|=", [T_PLUS] = "+", [T_PLUSEQ] = "+=", [T_PLUSPLUS] = "++", @@ -653,6 +656,72 @@ lex3(struct lexer *lexer, struct token *out, uint32_t c) break; } break; + case '&': + switch ((c = next(lexer, NULL, false))) { + case '&': + switch ((c = next(lexer, NULL, false))) { + case '=': + out->token = T_LANDEQ; + break; + default: + push(lexer, c, false); + out->token = T_LAND; + break; + } + break; + case '=': + out->token = T_BANDEQ; + break; + default: + push(lexer, c, false); + out->token = T_BAND; + break; + } + break; + case '|': + switch ((c = next(lexer, NULL, false))) { + case '|': + switch ((c = next(lexer, NULL, false))) { + case '=': + out->token = T_LOREQ; + break; + default: + push(lexer, c, false); + out->token = T_LOR; + break; + } + break; + case '=': + out->token = T_BOREQ; + break; + default: + push(lexer, c, false); + out->token = T_BOR; + break; + } + break; + case '^': + switch ((c = next(lexer, NULL, false))) { + case '^': + switch ((c = next(lexer, NULL, false))) { + case '=': + out->token = T_LXOREQ; + break; + default: + push(lexer, c, false); + out->token = T_LXOR; + break; + } + break; + case '=': + out->token = T_BXOREQ; + break; + default: + push(lexer, c, false); + out->token = T_BXOR; + break; + } + break; default: assert(0); // Invariant } @@ -684,20 +753,6 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c) assert(c != UTF8_INVALID); switch (c) { - case '^': - switch ((c = next(lexer, NULL, false))) { - case '^': - out->token = T_LXOR; - break; - case '=': - out->token = T_BXOREQ; - break; - default: - push(lexer, c, false); - out->token = T_BXOR; - break; - } - break; case '*': switch ((c = next(lexer, NULL, false))) { case '=': @@ -793,34 +848,6 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c) break; } break; - case '&': - switch ((c = next(lexer, NULL, false))) { - case '&': - out->token = T_LAND; - break; - case '=': - out->token = T_ANDEQ; - break; - default: - push(lexer, c, false); - out->token = T_BAND; - break; - } - break; - case '|': - switch ((c = next(lexer, NULL, false))) { - case '|': - out->token = T_LOR; - break; - case '=': - out->token = T_OREQ; - break; - default: - push(lexer, c, false); - out->token = T_BOR; - break; - } - break; case '=': switch ((c = next(lexer, NULL, false))) { case '=': @@ -875,8 +902,10 @@ _lex(struct lexer *lexer, struct token *out) case '.': // . .. ... case '<': // < << <= <<= case '>': // > >> >= >>= + case '&': // & && &= &&= + case '|': // | || |= ||= + case '^': // ^ ^^ ^= ^^= return lex3(lexer, out, c); - case '^': // ^ ^= case '*': // * *= case '%': // % %= case '/': // / /= // @@ -884,8 +913,6 @@ _lex(struct lexer *lexer, struct token *out) case '-': // - -= case ':': // : :: case '!': // ! != - case '&': // & && &= - case '|': // | || |= case '=': // = == => return lex2(lexer, out, c); case '~': diff --git a/src/parse.c b/src/parse.c @@ -2180,8 +2180,10 @@ parse_expression(struct lexer *lexer) switch (lex(lexer, &tok)) { case T_EQUAL: return parse_assignment(lexer, value, indirect, BIN_LEQUAL); - case T_ANDEQ: + case T_BANDEQ: return parse_assignment(lexer, value, indirect, BIN_BAND); + case T_LANDEQ: + return parse_assignment(lexer, value, indirect, BIN_LAND); case T_DIVEQ: return parse_assignment(lexer, value, indirect, BIN_DIV); case T_LSHIFTEQ: @@ -2190,8 +2192,10 @@ parse_expression(struct lexer *lexer) return parse_assignment(lexer, value, indirect, BIN_MINUS); case T_MODEQ: return parse_assignment(lexer, value, indirect, BIN_MODULO); - case T_OREQ: + case T_BOREQ: return parse_assignment(lexer, value, indirect, BIN_BOR); + case T_LOREQ: + return parse_assignment(lexer, value, indirect, BIN_LOR); case T_PLUSEQ: return parse_assignment(lexer, value, indirect, BIN_PLUS); case T_RSHIFTEQ: @@ -2200,6 +2204,8 @@ parse_expression(struct lexer *lexer) return parse_assignment(lexer, value, indirect, BIN_TIMES); case T_BXOREQ: return parse_assignment(lexer, value, indirect, BIN_BXOR); + case T_LXOREQ: + return parse_assignment(lexer, value, indirect, BIN_LXOR); default: unlex(lexer, &tok); if (indirect) { diff --git a/tests/10-binarithms.ha b/tests/10-binarithms.ha @@ -8,7 +8,7 @@ fn set(x: *int) bool = { return true; }; -fn andor() void = { +fn andorxor() void = { assert((false || false) == false); assert((false || true) == true); assert((true || false) == true); @@ -18,6 +18,18 @@ fn andor() void = { assert((false || set(&x)) == true); assert(x == 42); + let x = 0; + let f = false; + f ||= false; + assert(!f); + f ||= set(&x); + assert(x == 42); + assert(f); + f || error(); + assert(f); + f ||= false; + assert(f); + assert((false && false) == false); assert((false && true) == false); assert((true && false) == false); @@ -26,6 +38,33 @@ fn andor() void = { x = 0; assert((true && set(&x)) == true); assert(x == 42); + + let x = 0; + let f = true; + f &&= true; + f &&= set(&x); + assert(x == 42); + assert(f); + f &&= false; + assert(!f); + f &&= error(); + f &&= true; + assert(!f); + + assert((false ^^ false) == false); + assert((false ^^ true) == true); + assert((true ^^ false) == true); + assert((true ^^ true) == false); + + let f = true; + f ^^= true; + assert(!f); + f ^^= false; + assert(!f); + f ^^= true; + assert(f); + f ^^= false; + assert(f); }; fn sar_shr() void = { @@ -52,6 +91,6 @@ fn sar_shr() void = { export fn main() void = { // TODO: other binarithms - andor(); + andorxor(); sar_shr(); };