diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 62892b5b5..b173f0be1 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -164,6 +164,14 @@ typedef enum { OP_BITXOR_I, OP_BITNOT_F, OP_BITNOT_I, + + OP_SHL_F, + OP_SHR_F, + OP_SHL_I, + OP_SHR_I, + + OP_MOD_F, + OP_MOD_I, } pr_opcode_e; typedef struct diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 371554ca6..f6e04386e 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -1239,6 +1239,8 @@ PR_LoadProgs (progs_t * pr, const char *progsname) case OP_SUB_I: case OP_MUL_I: case OP_DIV_I: + case OP_MOD_I: + case OP_MOD_F: case OP_BITAND_I: case OP_BITOR_I: case OP_GE_I: @@ -1257,6 +1259,10 @@ PR_LoadProgs (progs_t * pr, const char *progsname) case OP_BITXOR_I: case OP_BITNOT_F: case OP_BITNOT_I: + case OP_SHL_F: + case OP_SHR_F: + case OP_SHL_I: + case OP_SHR_I: if ((unsigned short) st->a >= pr->progs->numglobals || (unsigned short) st->b >= pr->progs->numglobals || (unsigned short) st->c >= pr->progs->numglobals) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 6c8b49158..a1285780f 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -369,6 +369,18 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) case OP_BITNOT_F: OPC.float_var = ~ (int) OPA.float_var; break; + case OP_SHL_F: + OPC.float_var = (int) OPA.float_var << (int) OPB.float_var; + break; + case OP_SHR_F: + OPC.float_var = (int) OPA.float_var >> (int) OPB.float_var; + break; + case OP_SHL_I: + OPC.integer_var = OPA.integer_var << OPB.integer_var; + break; + case OP_SHR_I: + OPC.integer_var = OPA.integer_var >> OPB.integer_var; + break; case OP_GE: OPC.float_var = OPA.float_var >= OPB.float_var; break; @@ -657,6 +669,12 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) case OP_DIV_I: OPC.integer_var = OPA.integer_var / OPB.integer_var; break; + case OP_MOD_I: + OPC.integer_var = OPA.integer_var % OPB.integer_var; + break; + case OP_MOD_F: + OPC.float_var = (int) OPA.float_var % (int) OPB.float_var; + break; case OP_CONV_IF: OPC.float_var = OPA.integer_var; break; diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 77c4b58e9..194b6dfe5 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -123,6 +123,11 @@ opcode_t pr_opcodes[] = { {"&&", "and", OP_AND, 6, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION}, {"||", "or", OP_OR, 6, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION}, + {"<<", "shl.f", OP_SHL_F, 2, false, ev_float, ev_float, ev_float, PROG_VERSION}, + {">>", "shr.f", OP_SHR_F, 2, false, ev_float, ev_float, ev_float, PROG_VERSION}, + {"<<", "shl.i", OP_SHL_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, + {">>", "shr.i", OP_SHR_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, + {"&", "bitand", OP_BITAND, 2, false, ev_float, ev_float, ev_float, PROG_ID_VERSION}, {"|", "bitor", OP_BITOR, 2, false, ev_float, ev_float, ev_float, PROG_ID_VERSION}, @@ -130,6 +135,8 @@ opcode_t pr_opcodes[] = { {"-", "sub.i", OP_SUB_I, 3, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, {"*", "mul.i", OP_MUL_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, {"/", "div.i", OP_DIV_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, + {"%", "mod_i", OP_MOD_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, + {"%", "mod.f", OP_MOD_F, 2, false, ev_float, ev_float, ev_float, PROG_VERSION}, {"&", "bitand.i", OP_BITAND_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, {"|", "bitor.i", OP_BITOR_I, 2, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, {">=", "ge.i", OP_GE_I, 4, false, ev_integer, ev_integer, ev_integer, PROG_VERSION}, diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b5a4e1f14..b7c09ba5d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -76,6 +76,7 @@ void convert_int (expr_t *e); expr_t *test_expr (expr_t *e, int test); expr_t *binary_expr (int op, expr_t *e1, expr_t *e2); +expr_t *asx_expr (int op, expr_t *e1, expr_t *e2); expr_t *unary_expr (int op, expr_t *e); expr_t *function_expr (expr_t *e1, expr_t *e2); expr_t *return_expr (function_t *f, expr_t *e); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index ff2c9d5c4..28d84068b 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -232,6 +232,18 @@ emit_sub_expr (expr_t *e, def_t *dest) operator = "|"; priority = 2; break; + case '%': + operator = "%"; + priority = 2; + break; + case SHL: + operator = "<<"; + priority = 2; + break; + case SHR: + operator = ">>"; + priority = 2; + break; case '.': operator = "."; priority = 1; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 74d6f005f..2914c41f7 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -169,6 +169,8 @@ get_op_string (int op) case '^': return "^"; case '~': return "~"; case '!': return "!"; + case SHL: return "<<"; + case SHR: return ">>"; case '(': return "("; case '.': return "."; case 'i': return ""; @@ -412,6 +414,15 @@ do_op_float (int op, expr_t *e1, expr_t *e2) case '^': e1->e.float_val = (int)f1 ^ (int)f2; break; + case '%': + e1->e.float_val = (int)f1 % (int)f2; + break; + case SHL: + e1->e.float_val = (int)f1 << (int)f2; + break; + case SHR: + e1->e.float_val = (int)f1 >> (int)f2; + break; case AND: e1->type = ex_integer; e1->e.integer_val = f1 && f2; @@ -518,6 +529,15 @@ do_op_integer (int op, expr_t *e1, expr_t *e2) case '^': e1->e.integer_val = i1 ^ i2; break; + case '%': + e1->e.integer_val = i1 % i2; + break; + case SHL: + e1->e.integer_val = i1 << i2; + break; + case SHR: + e1->e.integer_val = i1 >> i2; + break; case AND: e1->e.integer_val = i1 && i2; break; @@ -763,6 +783,36 @@ type_mismatch: return e; } +expr_t * +asx_expr (int op, expr_t *e1, expr_t *e2) +{ + switch (op) { + case ASADD: + return binary_expr ('=', e1, binary_expr ('+', e1, e2)); + case ASSUB: + return binary_expr ('=', e1, binary_expr ('-', e1, e2)); + case ASMUL: + return binary_expr ('=', e1, binary_expr ('*', e1, e2)); + case ASDIV: + return binary_expr ('=', e1, binary_expr ('/', e1, e2)); + case ASAND: + return binary_expr ('=', e1, binary_expr ('&', e1, e2)); + case ASOR: + return binary_expr ('=', e1, binary_expr ('|', e1, e2)); + case ASXOR: + return binary_expr ('=', e1, binary_expr ('^', e1, e2)); + case ASMOD: + return binary_expr ('=', e1, binary_expr ('%', e1, e2)); + case ASSHL: + return binary_expr ('=', e1, binary_expr (SHL, e1, e2)); + case ASSHR: + return binary_expr ('=', e1, binary_expr (SHR, e1, e2)); + default: + error (e1, "invalid operand for asx"); + } + return 0; +} + expr_t * unary_expr (int op, expr_t *e) { diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index eea86275e..8120b6d1b 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -95,10 +95,24 @@ m ([\-+]?) s_file = ReuseString (pr_immediate_string); } -[!(){}.*/&|^~+\-=\[\];,#] return yytext[0]; +[!(){}.*/&|^~+\-=\[\];,#%] return yytext[0]; "..." return ELIPSIS; +"+=" return ASADD; +"-=" return ASSUB; +"*=" return ASMUL; +"/=" return ASDIV; +"&=" return ASAND; +"|=" return ASOR; +"^=" return ASXOR; +"%=" return ASMOD; +"<<=" return ASSHL; +">>=" return ASSHR; + +"<<" return SHL; +">>" return SHR; + "&&" return AND; "||" return OR; "==" return EQ; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 5267852d9..94d3fd5b9 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -45,11 +45,12 @@ typedef struct { function_t *function; } -%right '=' +%right '=' ASADD ASSUB ASMUL ASDIV ASAND ASOR ASXOR ASMOD ASSHL ASSHR %left OR AND %left EQ NE LE GE LT GT +%left SHL SHR %left '+' '-' -%left '*' '/' '&' '|' '^' +%left '*' '/' '&' '|' '^' '%' %left '!' '~' %right '(' %left '.' @@ -440,6 +441,18 @@ opt_expr expr : expr '=' expr { $$ = binary_expr ('=', $1, $3); } + | expr ASADD expr { $$ = asx_expr (ASADD, $1, $3); } + | expr ASSUB expr { $$ = asx_expr (ASSUB, $1, $3); } + | expr ASMUL expr { $$ = asx_expr (ASMUL, $1, $3); } + | expr ASDIV expr { $$ = asx_expr (ASDIV, $1, $3); } + | expr ASAND expr { $$ = asx_expr (ASAND, $1, $3); } + | expr ASOR expr { $$ = asx_expr (ASOR, $1, $3); } + | expr ASXOR expr { $$ = asx_expr (ASXOR, $1, $3); } + | expr ASMOD expr { $$ = asx_expr (ASMOD, $1, $3); } + | expr ASSHL expr { $$ = asx_expr (ASSHL, $1, $3); } + | expr ASSHR expr { $$ = asx_expr (ASSHR, $1, $3); } + | expr SHL expr { $$ = binary_expr (SHL, $1, $3); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3); } | expr AND expr { $$ = binary_expr (AND, $1, $3); } | expr OR expr { $$ = binary_expr (OR, $1, $3); } | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } @@ -455,6 +468,7 @@ expr | expr '&' expr { $$ = binary_expr ('&', $1, $3); } | expr '|' expr { $$ = binary_expr ('|', $1, $3); } | expr '^' expr { $$ = binary_expr ('^', $1, $3); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3); } | expr '(' arg_list ')' { $$ = function_expr ($1, $3); } | expr '(' ')' { $$ = function_expr ($1, 0); } | expr '.' expr { $$ = binary_expr ('.', $1, $3); } diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc index 626d775c4..6a57039bd 100644 --- a/tools/qwaq/main.qc +++ b/tools/qwaq/main.qc @@ -12,7 +12,7 @@ float negative = -------2; void () eek; float () main = -{ +{/* local float messed_or; local integer handle; local string buffer; @@ -33,8 +33,23 @@ float () main = print (buffer); } while (read_result == 1024); close (handle); - eek (); - return 0; + eek ();*/ + traceon(); + local float foo = 0; + foo += 1; + foo *= 3; + foo -= 5; + foo &= 11; + foo /= 3; + foo ^= 1; + foo |= 7; + foo <<= 3; + foo >>= 1; + local integer bar; + bar = 12 % 5; + bar %= 3; + foo %= 5; + return foo; }; float () baz =