浏览代码

Add %% operator (divisor modulo)

Ginger Bill 8 年之前
父节点
当前提交
c6d531df95
共有 5 个文件被更改,包括 21 次插入1 次删除
  1. 4 0
      src/check_expr.c
  2. 1 0
      src/exact_value.c
  3. 10 0
      src/ir.c
  4. 2 0
      src/parser.c
  5. 4 1
      src/tokenizer.c

+ 4 - 0
src/check_expr.c

@@ -1864,8 +1864,10 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 		break;
 		break;
 
 
 	case Token_Mod:
 	case Token_Mod:
+	case Token_ModMod:
 	case Token_AndNot:
 	case Token_AndNot:
 	case Token_ModEq:
 	case Token_ModEq:
+	case Token_ModModEq:
 	case Token_AndNotEq:
 	case Token_AndNotEq:
 		if (!is_type_integer(type)) {
 		if (!is_type_integer(type)) {
 			error(op, "Operator `%.*s` is only allowed with integers", LIT(op.string));
 			error(op, "Operator `%.*s` is only allowed with integers", LIT(op.string));
@@ -2669,8 +2671,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	switch (op.kind) {
 	switch (op.kind) {
 	case Token_Quo:
 	case Token_Quo:
 	case Token_Mod:
 	case Token_Mod:
+	case Token_ModMod:
 	case Token_QuoEq:
 	case Token_QuoEq:
 	case Token_ModEq:
 	case Token_ModEq:
+	case Token_ModModEq:
 		if ((x->mode == Addressing_Constant || is_type_integer(x->type)) &&
 		if ((x->mode == Addressing_Constant || is_type_integer(x->type)) &&
 		    y->mode == Addressing_Constant) {
 		    y->mode == Addressing_Constant) {
 			bool fail = false;
 			bool fail = false;

+ 1 - 0
src/exact_value.c

@@ -595,6 +595,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
 		case Token_Quo:    return exact_value_float(fmod(cast(f64)a, cast(f64)b));
 		case Token_Quo:    return exact_value_float(fmod(cast(f64)a, cast(f64)b));
 		case Token_QuoEq:  c = a / b;  break; // NOTE(bill): Integer division
 		case Token_QuoEq:  c = a / b;  break; // NOTE(bill): Integer division
 		case Token_Mod:    c = a % b;  break;
 		case Token_Mod:    c = a % b;  break;
+		case Token_ModMod: c = ((a % b) + b)%b; break;
 		case Token_And:    c = a & b;  break;
 		case Token_And:    c = a & b;  break;
 		case Token_Or:     c = a | b;  break;
 		case Token_Or:     c = a | b;  break;
 		case Token_Xor:    c = a ^ b;  break;
 		case Token_Xor:    c = a ^ b;  break;

+ 10 - 0
src/ir.c

@@ -2073,6 +2073,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 	case Token_Mul:
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Quo:
 	case Token_Mod:
 	case Token_Mod:
+	case Token_ModMod:
 	case Token_And:
 	case Token_And:
 	case Token_Or:
 	case Token_Or:
 	case Token_Xor:
 	case Token_Xor:
@@ -2081,6 +2082,14 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 		break;
 		break;
 	}
 	}
 
 
+	if (op == Token_ModMod) {
+		irValue *n = left;
+		irValue *m = right;
+		irValue *a = ir_emit(proc, ir_instr_binary_op(proc, Token_Mod, n, m, type));
+		irValue *b = ir_emit(proc, ir_instr_binary_op(proc, Token_Add, a, m, type));
+		return ir_emit(proc, ir_instr_binary_op(proc, Token_Mod, b, m, type));
+	}
+
 	return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
 	return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
 }
 }
 
 
@@ -3744,6 +3753,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 		case Token_Mul:
 		case Token_Mul:
 		case Token_Quo:
 		case Token_Quo:
 		case Token_Mod:
 		case Token_Mod:
+		case Token_ModMod:
 		case Token_And:
 		case Token_And:
 		case Token_Or:
 		case Token_Or:
 		case Token_Xor:
 		case Token_Xor:

+ 2 - 0
src/parser.c

@@ -2136,6 +2136,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
 	case Token_Mul:
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Quo:
 	case Token_Mod:
 	case Token_Mod:
+	case Token_ModMod:
 	case Token_And:
 	case Token_And:
 	case Token_AndNot:
 	case Token_AndNot:
 	case Token_Shl:
 	case Token_Shl:
@@ -2305,6 +2306,7 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
 	case Token_MulEq:
 	case Token_MulEq:
 	case Token_QuoEq:
 	case Token_QuoEq:
 	case Token_ModEq:
 	case Token_ModEq:
+	case Token_ModModEq:
 	case Token_AndEq:
 	case Token_AndEq:
 	case Token_OrEq:
 	case Token_OrEq:
 	case Token_XorEq:
 	case Token_XorEq:

+ 4 - 1
src/tokenizer.c

@@ -25,6 +25,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
 	TOKEN_KIND(Token_Mul,      "*"), \
 	TOKEN_KIND(Token_Mul,      "*"), \
 	TOKEN_KIND(Token_Quo,      "/"), \
 	TOKEN_KIND(Token_Quo,      "/"), \
 	TOKEN_KIND(Token_Mod,      "%"), \
 	TOKEN_KIND(Token_Mod,      "%"), \
+	TOKEN_KIND(Token_ModMod,   "%%"), \
 	TOKEN_KIND(Token_And,      "&"), \
 	TOKEN_KIND(Token_And,      "&"), \
 	TOKEN_KIND(Token_Or,       "|"), \
 	TOKEN_KIND(Token_Or,       "|"), \
 	TOKEN_KIND(Token_Xor,      "~"), \
 	TOKEN_KIND(Token_Xor,      "~"), \
@@ -41,6 +42,7 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
 	TOKEN_KIND(Token_MulEq,      "*="), \
 	TOKEN_KIND(Token_MulEq,      "*="), \
 	TOKEN_KIND(Token_QuoEq,      "/="), \
 	TOKEN_KIND(Token_QuoEq,      "/="), \
 	TOKEN_KIND(Token_ModEq,      "%="), \
 	TOKEN_KIND(Token_ModEq,      "%="), \
+	TOKEN_KIND(Token_ModModEq,   "%%="), \
 	TOKEN_KIND(Token_AndEq,      "&="), \
 	TOKEN_KIND(Token_AndEq,      "&="), \
 	TOKEN_KIND(Token_OrEq,       "|="), \
 	TOKEN_KIND(Token_OrEq,       "|="), \
 	TOKEN_KIND(Token_XorEq,      "~="), \
 	TOKEN_KIND(Token_XorEq,      "~="), \
@@ -892,8 +894,9 @@ Token tokenizer_get_token(Tokenizer *t) {
 		case '}':  token.kind = Token_CloseBrace;   break;
 		case '}':  token.kind = Token_CloseBrace;   break;
 		case '\\': token.kind = Token_BackSlash;    break;
 		case '\\': token.kind = Token_BackSlash;    break;
 
 
+		case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq);      break;
+
 		case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq);                                        break;
 		case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq);                                        break;
-		case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq);                                        break;
 		case '=': token.kind = token_kind_variant2(t, Token_Eq,  Token_CmpEq);                                        break;
 		case '=': token.kind = token_kind_variant2(t, Token_Eq,  Token_CmpEq);                                        break;
 		case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq);                                        break;
 		case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq);                                        break;
 		case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq);                                        break;
 		case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq);                                        break;