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:
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();
};