diff --git a/src/cfront.c b/src/cfront.c index 8e5b316a..35307ae3 100644 --- a/src/cfront.c +++ b/src/cfront.c @@ -47,6 +47,7 @@ typedef enum { T_close_square, /* ] */ T_asterisk, /* '*' */ T_divide, /* / */ + T_mod, /* % */ T_bit_or, /* | */ T_bit_xor, /* ^ */ T_log_and, /* && */ @@ -338,6 +339,10 @@ token_t get_next_token() skip_whitespace(); return T_lt; } + if (next_char == '%') { + read_char(1); + return T_mod; + } if (next_char == '>') { read_char(0); if (next_char == '=') { @@ -876,6 +881,7 @@ int get_operator_prio(opcode_t op) return 12; case OP_mul: case OP_div: + case OP_mod: return 13; default: return 0; @@ -893,6 +899,8 @@ opcode_t get_operator() op = OP_mul; else if (lex_accept(T_divide)) op = OP_div; + else if (lex_accept(T_mod)) + op = OP_mod; else if (lex_accept(T_lshift)) op = OP_lshift; else if (lex_accept(T_rshift)) @@ -1357,6 +1365,7 @@ int read_numeric_sconstant() int eval_expression_imm(opcode_t op, int op1, int op2) { /* return immediate result */ + int tmp = op2; int res = 0; switch (op) { case OP_add: @@ -1371,6 +1380,16 @@ int eval_expression_imm(opcode_t op, int op1, int op2) case OP_div: res = op1 / op2; break; + case OP_mod: + /* TODO: provide arithmetic & operation instead of '&=' */ + /* TODO: do optimization for local expression */ + tmp &= (tmp - 1); + if ((op2 != 0) && (tmp == 0)) { + res = op1; + res &= (op2 - 1); + } else + res = op1 % op2; + break; case OP_lshift: res = op1 << op2; break; diff --git a/src/codegen.c b/src/codegen.c index 9fe1b7f1..51d83154 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -121,6 +121,7 @@ int get_code_length(ir_instr_t *ii) case OP_func_exit: return 16; case OP_exit: + case OP_mod: return 12; case OP_load_data_address: case OP_jz: @@ -367,6 +368,14 @@ void code_generate() if (dump_ir == 1) printf(" x%d /= x%d", dest_reg, OP_reg); break; + case OP_mod: + emit(__div(__AL, OP_reg + 1, OP_reg, dest_reg)); + emit(__mul(__AL, OP_reg, OP_reg, OP_reg + 1)); + emit(__sub_r(__AL, dest_reg, dest_reg, OP_reg)); + /* TODO: support percent-sign character (%) in format string */ + if (dump_ir == 1) + printf(" x%d = x%d mod x%d", dest_reg, dest_reg, OP_reg); + break; case OP_negate: emit(__rsb_i(__AL, dest_reg, 0, dest_reg)); if (dump_ir == 1) diff --git a/src/defs.h b/src/defs.h index 814937d0..7f4a17df 100644 --- a/src/defs.h +++ b/src/defs.h @@ -68,6 +68,7 @@ typedef enum { OP_sub, OP_mul, OP_div, /* signed division */ + OP_mod, /* modulo */ OP_lshift, OP_rshift, OP_log_and, diff --git a/tests/driver.sh b/tests/driver.sh index 529a4ccc..a85554bc 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -69,8 +69,8 @@ expr 55 "1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + 10))))))))" # expr 21 "+1+20" # expr 10 "-15+(+35-10)" -# expr 2 "5 % 3" -# expr 6 "111 % 7" +expr 2 "5 % 3" +expr 6 "111 % 7" expr 1 "10 > 5" expr 1 "3+3 > 5"