diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b7c09ba5d..1d5b630e8 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -4,6 +4,7 @@ typedef enum { ex_expr, // binary expression ex_uexpr, // unary expression ex_def, + ex_temp, // temporary variable ex_string, ex_float, @@ -25,8 +26,16 @@ typedef struct { typedef struct { struct expr_s *head; struct expr_s **tail; + struct expr_s *result; } block_t; +typedef struct { + struct expr_s *expr; + def_t *def; + type_t *type; + int users; +} temp_t; + typedef struct expr_s { struct expr_s *next; expr_type type; @@ -43,6 +52,7 @@ typedef struct expr_s { struct expr_s *e2; } expr; def_t *def; + temp_t temp; char *string_val; float float_val; @@ -67,6 +77,7 @@ expr_t *new_label_expr (void); expr_t *new_block_expr (void); expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *new_unary_expr (int op, expr_t *e1); +expr_t *new_temp_def_expr (type_t *type); expr_t *append_expr (expr_t *block, expr_t *e); @@ -80,6 +91,7 @@ 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); +expr_t *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2); def_t *emit_statement (int line, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c); void emit_expr (expr_t *e); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 1d11f63c3..cfeb1644d 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -169,8 +169,14 @@ emit_sub_expr (expr_t *e, def_t *dest) int priority; switch (e->type) { - case ex_label: case ex_block: + if (e->e.block.result) { + expr_t *res = e->e.block.result; + for (e = e->e.block.head; e; e = e->next) + emit_expr (e); + return emit_sub_expr (res, 0); + } + case ex_label: error (e, "internal error"); abort (); case ex_expr: @@ -293,6 +299,10 @@ emit_sub_expr (expr_t *e, def_t *dest) return emit_statement (e->line, op, def_a, def_b, dest); case ex_def: return e->e.def; + case ex_temp: + if (!e->e.temp.def) + e->e.temp.def = PR_GetTempDef (e->e.temp.type, pr_scope); + return e->e.temp.def; case ex_string: case ex_float: case ex_vector: @@ -383,6 +393,7 @@ emit_expr (expr_t *e) } break; case ex_def: + case ex_temp: case ex_string: case ex_float: case ex_vector: diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 2914c41f7..8d8ab761c 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -17,6 +17,7 @@ etype_t qc_types[] = { ev_void, // ex_expr ev_void, // ex_uexpr ev_void, // ex_def + ev_void, // ex_temp ev_string, // ex_string ev_float, // ex_float @@ -73,13 +74,18 @@ get_type (expr_t *e) { switch (e->type) { case ex_label: - case ex_block: return ev_type_count; // something went very wrong + case ex_block: + if (e->e.block.result) + return get_type (e->e.block.result); + return ev_void; case ex_expr: case ex_uexpr: return e->e.expr.type->type; case ex_def: return e->e.def->type->type; + case ex_temp: + return e->e.temp.type->type; case ex_integer: if (options.version == PROG_ID_VERSION) { e->type = ex_float; @@ -250,6 +256,16 @@ new_unary_expr (int op, expr_t *e1) return e; } +expr_t * +new_temp_def_expr (type_t *type) +{ + expr_t *e = new_expr (); + + e->type = ex_temp; + e->e.temp.type = type; + return e; +} + expr_t * append_expr (expr_t *block, expr_t *e) { @@ -278,6 +294,10 @@ print_expr (expr_t *e) printf ("%s", e->e.label.name); break; case ex_block: + if (e->e.block.result) { + print_expr (e->e.block.result); + printf ("="); + } printf ("{\n"); for (e = e->e.block.head; e; e = e->next) { print_expr (e); @@ -309,6 +329,10 @@ print_expr (expr_t *e) case ex_def: printf ("%s", e->e.def->name); break; + case ex_temp: + print_expr (e->e.temp.expr); + printf ("@"); + break; case ex_string: printf ("\"%s\"", e->e.string_val); break; @@ -820,14 +844,17 @@ unary_expr (int op, expr_t *e) case '-': switch (e->type) { case ex_label: - case ex_block: error (e, "internal error"); abort (); case ex_uexpr: if (e->e.expr.op == '-') return e->e.expr.e1; + case ex_block: + if (!e->e.block.result) + return error (e, "invalid type for unary -"); case ex_expr: case ex_def: + case ex_temp: { expr_t *n = new_unary_expr (op, e); n->e.expr.type = (e->type == ex_def) @@ -863,11 +890,14 @@ unary_expr (int op, expr_t *e) case '!': switch (e->type) { case ex_label: - case ex_block: abort (); + case ex_block: + if (!e->e.block.result) + return error (e, "invalid type for unary -"); case ex_uexpr: case ex_expr: case ex_def: + case ex_temp: { expr_t *n = new_unary_expr (op, e); if (options.version > PROG_ID_VERSION) @@ -911,13 +941,16 @@ unary_expr (int op, expr_t *e) case '~': switch (e->type) { case ex_label: - case ex_block: abort (); case ex_uexpr: if (e->e.expr.op == '~') return e->e.expr.e1; + case ex_block: + if (!e->e.block.result) + return error (e, "invalid type for unary -"); case ex_expr: case ex_def: + case ex_temp: { expr_t *n = new_unary_expr (op, e); type_t *t = e->type == ex_expr ? e->e.expr.type @@ -1058,3 +1091,28 @@ return_expr (function_t *f, expr_t *e) } return new_unary_expr ('r', e); } + +expr_t * +conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2) +{ + expr_t *block = new_block_expr (); + type_t *type1 = types[get_type (e1)]; + type_t *type2 = types[get_type (e2)]; + expr_t *tlabel = new_label_expr (); + expr_t *elabel = new_label_expr (); + + block->e.block.result = (type1 == type2) ? new_temp_def_expr (type1) : 0; + append_expr (block, new_binary_expr ('i', test_expr (cond, 1), tlabel)); + if (block->e.block.result) + append_expr (block, new_binary_expr ('=', block->e.block.result, e2)); + else + append_expr (block, e2); + append_expr (block, new_unary_expr ('g', elabel)); + append_expr (block, tlabel); + if (block->e.block.result) + append_expr (block, new_binary_expr ('=', block->e.block.result, e1)); + else + append_expr (block, e1); + append_expr (block, elabel); + return block; +} diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index a348c021b..6a51f105c 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -95,7 +95,7 @@ m ([\-+]?) s_file = ReuseString (pr_immediate_string); } -[!(){}.*/&|^~+\-=\[\];,#%] return yytext[0]; +[!(){}.*/&|^~+\-=\[\];,#%?:] return yytext[0]; "..." return ELIPSIS; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 432c057cd..bcc7858e0 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -46,6 +46,7 @@ typedef struct { } %right '=' ASADD ASSUB ASMUL ASDIV ASAND ASOR ASXOR ASMOD ASSHL ASSHR +%right '?' ':' %left OR AND %left EQ NE LE GE LT GT %left SHL SHR @@ -440,41 +441,42 @@ 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 AND expr { $$ = binary_expr (AND, $1, $3); } - | expr OR expr { $$ = binary_expr (OR, $1, $3); } - | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } - | expr NE expr { $$ = binary_expr (NE, $1, $3); } - | expr LE expr { $$ = binary_expr (LE, $1, $3); } - | expr GE expr { $$ = binary_expr (GE, $1, $3); } - | expr LT expr { $$ = binary_expr (LT, $1, $3); } - | expr GT expr { $$ = binary_expr (GT, $1, $3); } - | expr SHL expr { $$ = binary_expr (SHL, $1, $3); } - | expr SHR expr { $$ = binary_expr (SHR, $1, $3); } - | 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 '&' 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); } - | '-' expr %prec '!' { $$ = unary_expr ('-', $2); } - | '!' expr { $$ = unary_expr ('!', $2); } - | '~' expr { $$ = unary_expr ('~', $2); } + : 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 '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); } + | expr AND expr { $$ = binary_expr (AND, $1, $3); } + | expr OR expr { $$ = binary_expr (OR, $1, $3); } + | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } + | expr NE expr { $$ = binary_expr (NE, $1, $3); } + | expr LE expr { $$ = binary_expr (LE, $1, $3); } + | expr GE expr { $$ = binary_expr (GE, $1, $3); } + | expr LT expr { $$ = binary_expr (LT, $1, $3); } + | expr GT expr { $$ = binary_expr (GT, $1, $3); } + | expr SHL expr { $$ = binary_expr (SHL, $1, $3); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3); } + | 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 '&' 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); } + | '-' expr %prec '!' { $$ = unary_expr ('-', $2); } + | '!' expr { $$ = unary_expr ('!', $2); } + | '~' expr { $$ = unary_expr ('~', $2); } | NAME { $$ = new_expr (); @@ -485,8 +487,8 @@ expr $$->e.def = &def_float; } } - | const { $$ = $1; } - | '(' expr ')' { $$ = $2; $$->paren = 1; } + | const { $$ = $1; } + | '(' expr ')' { $$ = $2; $$->paren = 1; } ; arg_list diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc index fdf14c630..f36289aa2 100644 --- a/tools/qwaq/main.qc +++ b/tools/qwaq/main.qc @@ -53,6 +53,7 @@ float () main = return foo;*/ traceon (); boing (boing (1, 2), boing (3, 4)); + boing (boing (0, 2), boing (3, -3)); return 0; }; @@ -94,7 +95,7 @@ void () blarg = float (float a, float b) boing = { - return a + b; + return a ? a + b : b; }; float (float baz) test_int =