diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index f83534c0..a993a774 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -422,6 +422,102 @@ reeval: *(unsigned char *)ptr = (char)OPA->_float; break; + case OP_STOREF_F: + case OP_STOREF_I: + case OP_STOREF_S: + errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + errorif (!ed || ed->readonly) + { //boot it over to the debugger +#if INTSIZE == 16 + ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a); +#else + ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a); +#endif + fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust); + if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??")) + return prinst.pr_xstatement; + break; + } + +//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods. +#ifdef NOLEGACY + errorif (ed->ereftype == ER_FREE) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } +#endif + + i = OPB->_int + progfuncs->funcs.fieldadjust; + errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + + ptr = (eval_t *)(((int *)edvars(ed)) + i); + ptr->_int = OPC->_int; + break; + case OP_STOREF_V: + errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + errorif (!ed || ed->readonly) + { //boot it over to the debugger +#if INTSIZE == 16 + ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a); +#else + ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a); +#endif + fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust); + if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??")) + return prinst.pr_xstatement; + break; + } + +//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods. +#ifdef NOLEGACY + errorif (ed->ereftype == ER_FREE) + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } +#endif + + i = OPB->_int + progfuncs->funcs.fieldadjust; + errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check + { + if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) + return prinst.pr_xstatement; + break; + } + + ptr = (eval_t *)(((int *)edvars(ed)) + i); + ptr->_vector[0] = OPC->_vector[0]; + ptr->_vector[1] = OPC->_vector[1]; + ptr->_vector[2] = OPC->_vector[2]; + break; + + //get a pointer to a field var case OP_ADDRESS: errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) @@ -828,7 +924,7 @@ reeval: case OP_LOADA_S: case OP_LOADA_FNC: i = st->a + OPB->_int; - if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size) + if ((size_t)i >= (size_t)(current_progstate->globals_bytes>>2)) { QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int); } @@ -838,7 +934,7 @@ reeval: case OP_LOADA_V: i = st->a + OPB->_int; - if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size) + if ((size_t)(i) >= (size_t)(current_progstate->globals_bytes>>2)-2u) { QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int); } @@ -1267,19 +1363,19 @@ reeval: case OP_GLOAD_ENT: case OP_GLOAD_S: case OP_GLOAD_FNC: - errorif (OPA->_int < 0 || OPA->_int*4 >= current_progstate->globals_size) + errorif (OPA->_int < 0 || OPA->_int >= (current_progstate->globals_bytes>>2)) { prinst.pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_bytes>>2); } ptr = ((eval_t *)&glob[OPA->_int]); OPC->_int = ptr->_int; break; case OP_GLOAD_V: - errorif (OPA->_int < 0 || (OPA->_int+2)*4 >= current_progstate->globals_size) + errorif (OPA->_int < 0 || OPA->_int >= (current_progstate->globals_bytes>>2)-2u) { prinst.pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_bytes>>2); } ptr = ((eval_t *)&glob[OPA->_int]); OPC->_vector[0] = ptr->_vector[0]; @@ -1292,19 +1388,19 @@ reeval: case OP_GSTOREP_FLD: case OP_GSTOREP_S: case OP_GSTOREP_FNC: - errorif (OPB->_int < 0 || OPB->_int*4 >= current_progstate->globals_size) + errorif (OPB->_int < 0 || OPB->_int >= (current_progstate->globals_bytes>>2)) { prinst.pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, (unsigned)prinst.addressableused); + PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, current_progstate->globals_bytes>>2); } ptr = ((eval_t *)&glob[OPB->_int]); ptr->_int = OPA->_int; break; case OP_GSTOREP_V: - errorif (OPB->_int < 0 || (OPB->_int+2)*4 >= current_progstate->globals_size) + errorif (OPB->_int < 0 || OPB->_int >= (current_progstate->globals_bytes>>2)-2u) { prinst.pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, (unsigned)prinst.addressableused); + PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, current_progstate->globals_bytes>>2); } ptr = ((eval_t *)&glob[OPB->_int]); ptr->_vector[0] = OPA->_vector[0]; diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 12d1f1bd..a20ee806 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -145,37 +145,37 @@ enum qcop_e { OP_SUBSTOREP_F, //78 OP_SUBSTOREP_V, //79 - OP_FETCH_GBL_F, //80 - OP_FETCH_GBL_V, //81 - OP_FETCH_GBL_S, //82 - OP_FETCH_GBL_E, //83 - OP_FETCH_GBL_FNC,//84 + OP_FETCH_GBL_F, //80 has built-in bounds check + OP_FETCH_GBL_V, //81 has built-in bounds check + OP_FETCH_GBL_S, //82 has built-in bounds check + OP_FETCH_GBL_E, //83 has built-in bounds check + OP_FETCH_GBL_FNC,//84 has built-in bounds check OP_CSTATE, //85 OP_CWSTATE, //86 - OP_THINKTIME, //87 + OP_THINKTIME, //87 shortcut for OPA.nextthink=time+OPB OP_BITSETSTORE_F, //88 redundant, for h2 compat OP_BITSETSTOREP_F, //89 OP_BITCLRSTORE_F, //90 OP_BITCLRSTOREP_F, //91 - OP_RAND0, //92 - OP_RAND1, //93 - OP_RAND2, //94 - OP_RANDV0, //95 + OP_RAND0, //92 OPC = random() + OP_RAND1, //93 OPC = random()*OPA + OP_RAND2, //94 OPC = random()*(OPB-OPA)+OPA + OP_RANDV0, //95 //3d/box versions of the above. OP_RANDV1, //96 OP_RANDV2, //97 - OP_SWITCH_F, //98 + OP_SWITCH_F, //98 switchref=OPA; PC += OPB --- the jump allows the jump table (such as it is) to be inserted after the block. OP_SWITCH_V, //99 OP_SWITCH_S, //100 OP_SWITCH_E, //101 OP_SWITCH_FNC, //102 - OP_CASE, //103 - OP_CASERANGE, //104 + OP_CASE, //103 if (OPA===switchref) PC += OPB + OP_CASERANGE, //104 if (OPA<=switchref&&switchref<=OPB) PC += OPC @@ -184,9 +184,10 @@ enum qcop_e { //the rest are added //mostly they are various different ways of adding two vars with conversions. - OP_CALL1H, - OP_CALL2H, - OP_CALL3H, + //hexen2 calling convention (-TH2 requires us to remap OP_CALLX to these on load, -TFTE just uses these directly.) + OP_CALL1H, //OFS_PARM0=OPB + OP_CALL2H, //OFS_PARM0,1=OPB,OPC + OP_CALL3H, //no extra args OP_CALL4H, OP_CALL5H, OP_CALL6H, //110 @@ -195,21 +196,21 @@ enum qcop_e { OP_STORE_I, - OP_STORE_IF, - OP_STORE_FI, + OP_STORE_IF, //OPB.f = (float)OPA.i (makes more sense when written as a->b) + OP_STORE_FI, //OPB.i = (int)OPA.f OP_ADD_I, - OP_ADD_FI, - OP_ADD_IF, + OP_ADD_FI, //OPC.f = OPA.f + OPB.i + OP_ADD_IF, //OPC.f = OPA.i + OPB.f -- redundant... - OP_SUB_I, - OP_SUB_FI, //120 - OP_SUB_IF, + OP_SUB_I, //OPC.i = OPA.i - OPB.i + OP_SUB_FI, //120 //OPC.f = OPA.f - OPB.i + OP_SUB_IF, //OPC.f = OPA.i - OPB.f - OP_CONV_ITOF, - OP_CONV_FTOI, - OP_CP_ITOF, - OP_CP_FTOI, + OP_CONV_ITOF, //OPC.f=(float)OPA.i + OP_CONV_FTOI, //OPC.i=(int)OPA.f + OP_CP_ITOF, //OPC.f=(float)(*OPA).i + OP_CP_FTOI, //OPC.i=(int)(*OPA).f OP_LOAD_I, OP_STOREP_I, OP_STOREP_IF, @@ -223,7 +224,7 @@ enum qcop_e { OP_EQ_I, OP_NE_I, - OP_IFNOT_S, + OP_IFNOT_S, //compares string empty, rather than just null. OP_IF_S, OP_NOT_I, @@ -234,8 +235,8 @@ enum qcop_e { OP_RSHIFT_I, OP_LSHIFT_I, - OP_GLOBALADDRESS, - OP_ADD_PIW, //add B words to A pointer + OP_GLOBALADDRESS, //C.p = &A + B.i*4 + OP_ADD_PIW, //C.p = A.p + B.i*4 OP_LOADA_F, OP_LOADA_V, @@ -302,7 +303,7 @@ enum qcop_e { OP_NE_IF, OP_NE_FI, -//erm... FTEQCC doesn't make use of these... These are for DP. +//erm... FTEQCC doesn't make use of these (doesn't model separate pointer types). These are for DP. OP_GSTOREP_I, OP_GSTOREP_F, OP_GSTOREP_ENT, @@ -326,10 +327,16 @@ enum qcop_e { OP_SWITCH_I,//hmm. OP_GLOAD_V, - - OP_IF_F, +//r3349+ + OP_IF_F, //compares as an actual float, instead of treating -0 as positive. OP_IFNOT_F, +//r5697+ + OP_STOREF_V, //3 elements... + OP_STOREF_F, //1 fpu element... + OP_STOREF_S, //1 string reference + OP_STOREF_I, //1 non-string reference/int + OP_NUMREALOPS, /* diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index e0b1498d..4119af56 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -2097,8 +2097,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD if (num == 0 && oldglobals) { - if (pr_progstate[0].globals_size == oldglobalssize) - memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_size); + if (pr_progstate[0].globals_bytes == oldglobalssize) + memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_bytes); free(oldglobals); oldglobals = NULL; } @@ -2217,16 +2217,16 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD if (oldglobals) free(oldglobals); oldglobals = NULL; - if (pr_progstate[0].globals_size) + if (pr_progstate[0].globals_bytes) { - oldglobals = malloc(pr_progstate[0].globals_size); + oldglobals = malloc(pr_progstate[0].globals_bytes); if (oldglobals) { - oldglobalssize = pr_progstate[0].globals_size; + oldglobalssize = pr_progstate[0].globals_bytes; memcpy(oldglobals, pr_progstate[0].globals, oldglobalssize); } else - externs->Printf("Unable to alloc %i bytes\n", pr_progstate[0].globals_size); + externs->Printf("Unable to alloc %i bytes\n", pr_progstate[0].globals_bytes); } PRAddressableFlush(progfuncs, 0); @@ -2784,7 +2784,7 @@ retry: current_progstate->statements = (void *)((qbyte *)pr_progs + pr_progs->ofs_statements); glob = pr_globals = (void *)((qbyte *)pr_progs + pr_progs->ofs_globals); - current_progstate->globals_size = pr_progs->numglobals*sizeof(*pr_globals); + current_progstate->globals_bytes = pr_progs->numglobals*sizeof(*pr_globals); pr_linenums=NULL; pr_types=NULL; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index c217642e..1431ed6a 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -351,7 +351,7 @@ typedef struct progstate_s // }; // void *global_struct; float *globals; // same as pr_global_struct - int globals_size; // in bytes + unsigned int globals_bytes; // in bytes typeinfo_t *types; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index a00ed913..c87abcd7 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -655,12 +655,12 @@ QCC_opcode_t pr_opcodes[] = {7, "", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, {7, "","IFNOT_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, -/* -{7, "<=>", "STOREF_F", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -{7, "<=>", "STOREF_V", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, -{7, "<=>", "STOREF_IF", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -{7, "<=>", "STOREF_FI", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -*/ + +{7, "<=>", "STOREF_V", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, +{7, "<=>", "STOREF_F", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, +{7, "<=>", "STOREF_S", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_string}, +{7, "<=>", "STOREF_I", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_integer}, + /* emulated ops begin here */ {7, "<>", "OP_EMULATED", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, @@ -775,8 +775,8 @@ static pbool OpAssignsToC(unsigned int op) return false; if(op >= OP_SWITCH_F && op <= OP_CALL8H) return false; - if(op >= OP_RAND0 && op <= OP_RANDV2) - return false; +// if(op >= OP_RAND0 && op <= OP_RANDV2) +// return false; // they use a and b, but have 3 types // safety if(op >= OP_BITSETSTORE_F && op <= OP_BITCLRSTOREP_F) @@ -791,6 +791,8 @@ static pbool OpAssignsToC(unsigned int op) return false; //actually they do. if (op >= OP_STORE_I && op <= OP_STORE_FI) return false; + if (op >= OP_STOREF_V && op <= OP_STOREF_I) + return false; //reads it, doesn't write. if (op == OP_BOUNDCHECK || op == OP_UNUSED || op == OP_POP) return false; return true; @@ -847,6 +849,7 @@ static int OpAssignsCount(unsigned int op) case OP_RANDV0: case OP_RANDV1: case OP_RANDV2: + return 1; //writes C, even when there's no A or B arg specified. case OP_UNUSED: case OP_POP: return 0; //FIXME @@ -867,6 +870,11 @@ static int OpAssignsCount(unsigned int op) case OP_CASE: case OP_CASERANGE: return 0; + case OP_STOREF_V: + case OP_STOREF_F: + case OP_STOREF_S: + case OP_STOREF_I: + return 0; //stores to a.b rather than any direct value... case OP_BOUNDCHECK: return 0; default: //the majority will write c @@ -1182,6 +1190,8 @@ static pbool QCC_OPCodeValid(QCC_opcode_t *op) case QCF_FTEH2: case QCF_FTE: case QCF_FTEDEBUG: + if (num >= OP_STOREF_V) //to be enabled at a later date - opcodes added in r5698. + return false; return true; case QCF_DARKPLACES: //all id opcodes. @@ -4957,7 +4967,9 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis {"VF_RT_DESTCOLOUR7", 219, ev_string, ev_float, ev_vector}, {"VF_ENVMAP", 220, ev_string}, {"VF_USERDATA", 221, ev_pointer, ev_integer}, - {"VF_SKYROOM_CAMERA", 222, ev_vector} + {"VF_SKYROOM_CAMERA", 222, ev_vector}, +// {"VF_PIXELPSCALE", 223, ev_vector}, + {"VF_PROJECTIONOFFSET", 224, ev_vector}, }; char temp[256]; @@ -5495,6 +5507,8 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (!strcmp(funcname, "strlen") && QCC_Intrinsic_strlen(&d, a)) return d; + if (!strcmp(funcname, "stof")) + return QCC_MakeFloatConst(atof(&strings[a->string])); } } else if (opt_constantarithmatic && argcount == 2 && arglist[0]->type == REF_GLOBAL && arglist[1]->type == REF_GLOBAL) @@ -5503,16 +5517,23 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, const QCC_eval_t *b = QCC_SRef_EvalConst(arglist[1]->base); if (a && b) { - if (!strcmp(funcname, "pow")) - return QCC_MakeFloatConst(pow(a->_float, b->_float)); - if (!strcmp(funcname, "mod")) - return QCC_MakeFloatConst(fmodf((int)a->_float, (int)b->_float)); - if (!strcmp(funcname, "bitshift")) + if (arglist[0]->cast == type_float && arglist[1]->cast == type_float) { - if (b->_float < 0) - return QCC_MakeFloatConst((int)a->_float >> (int)-b->_float); - else - return QCC_MakeFloatConst((int)a->_float << (int)b->_float); + if (!strcmp(funcname, "pow")) + return QCC_MakeFloatConst(pow(a->_float, b->_float)); + if (!strcmp(funcname, "mod")) + return QCC_MakeFloatConst(fmodf((int)a->_float, (int)b->_float)); + if (!strcmp(funcname, "min")) + return QCC_MakeFloatConst(min(a->_float, b->_float)); + if (!strcmp(funcname, "max")) + return QCC_MakeFloatConst(max(a->_float, b->_float)); + if (!strcmp(funcname, "bitshift")) + { + if (b->_float < 0) + return QCC_MakeFloatConst((int)a->_float >> (int)-b->_float); + else + return QCC_MakeFloatConst((int)a->_float << (int)b->_float); + } } } } @@ -5624,6 +5645,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, copyop_i = OP_LOADA_F; copyop_idx = -1; copyop_index = arglist[i]->index; + copyop_index = QCC_SupplyConversion(copyop_index, ev_integer, true); sref = arglist[i]->base; } else if (arglist[i]->base.sym->arraylengthprefix && QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F])) @@ -9690,15 +9712,53 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable QCC_PR_ParseErrorPrintSRef(ERR_NOFUNC, dest->base, "Accessor has no set function"); break; case REF_FIELD: -// { + { + int storef_opcode; //fixme: we should do this earlier, to preserve original instruction ordering. //such that self.enemy = (self = world); still has the same result (more common with function calls) - - dest = QCC_PR_BuildRef(&ptrref, REF_POINTER, - QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, preservedest?STFL_PRESERVEA:0), //pointer address - nullsref, (dest->index.cast->type == ev_field)?dest->index.cast->aux_type:type_variant, dest->readonly); - preservedest = false; - continue; + + if (dest->cast->type == ev_float) + storef_opcode = OP_STOREF_F; + else if (dest->cast->type == ev_vector) + storef_opcode = OP_STOREF_V; + else if (dest->cast->type == ev_string) + storef_opcode = OP_STOREF_S; + else if ( dest->cast->type == ev_entity || + dest->cast->type == ev_field || + dest->cast->type == ev_function || + dest->cast->type == ev_pointer || + dest->cast->type == ev_integer) + storef_opcode = OP_STOREF_I; + else + storef_opcode = OP_DONE; + //don't use it for arrays. address+storep_with_offset is less opcodes. + if (storef_opcode!=OP_DONE && dest->cast->size == 1 && QCC_OPCodeValid(&pr_opcodes[storef_opcode])) + { + dest->base.sym->referenced = true; + dest->index.sym->referenced = true; + source.sym->referenced = true; + //doesn't generate any temps. + QCC_PR_SimpleStatement(&pr_opcodes[storef_opcode], dest->base, dest->index, source, true); + + if (!preservedest) + { + QCC_FreeTemp(dest->base); + QCC_FreeTemp(dest->index); + } + if (!readable) + { + QCC_FreeTemp(source); + source = nullsref; + } + } + else + { + dest = QCC_PR_BuildRef(&ptrref, REF_POINTER, + QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, preservedest?STFL_PRESERVEA:0), //pointer address + nullsref, (dest->index.cast->type == ev_field)?dest->index.cast->aux_type:type_variant, dest->readonly); + preservedest = false; + continue; + } // source = QCC_StoreToRef( // QCC_PR_BuildRef(&tmp, REF_POINTER, @@ -9706,8 +9766,8 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable // NULL, (dest->index->type->type == ev_field)?dest->index->type->aux_type:type_variant, dest->readonly), // source, readable, false); // QCC_PR_ParseWarning(ERR_INTERNAL, "FIXME: trying to do references: assignments to ent.field not supported.\n"); -// } -// break; + } + break; } break; } @@ -12485,7 +12545,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ return i; } } - else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0) + else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0 && !st->a.sym) { int jump = i + (int)st->a.ofs; ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); @@ -12504,7 +12564,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ return i; } } - else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !(st->flags & STF_LOGICOP)) + else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !st->b.sym && !(st->flags & STF_LOGICOP)) { int jump = i + (int)st->b.ofs; //check if there's an else. @@ -12539,7 +12599,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ return i; } - else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0) + else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0 && !st->c.sym) { int jump = i + (int)st->c.ofs; ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index f1bb507f..eaca50cc 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1330,14 +1330,17 @@ static pbool QCC_PR_Precompiler(void) else if (!QC_strcasecmp(qcc_token, "KK7")) newtype = QCF_KK7; else if (!QC_strcasecmp(qcc_token, "DP") || !QC_strcasecmp(qcc_token, "DARKPLACES")) + { + QCC_PR_ParseWarning(WARN_BADTARGET, "#pragma target \"%s\". Requires an unofficial patch to DP. Without that patch there is no support for any opcodes beyond vanilla.", qcc_token); newtype = QCF_DARKPLACES; + } else if (!QC_strcasecmp(qcc_token, "FTEDEBUG")) newtype = QCF_FTEDEBUG; else if (!QC_strcasecmp(qcc_token, "FTE")) newtype = QCF_FTE; else if (!QC_strcasecmp(qcc_token, "FTEH2")) newtype = QCF_FTEH2; - else if (!QC_strcasecmp(qcc_token, "STANDARD") || !QC_strcasecmp(qcc_token, "ID")) + else if (!QC_strcasecmp(qcc_token, "STANDARD") || !QC_strcasecmp(qcc_token, "ID") || !QC_strcasecmp(qcc_token, "VANILLA")) newtype = QCF_STANDARD; else if (!QC_strcasecmp(qcc_token, "DEBUG")) newtype = QCF_FTEDEBUG; diff --git a/engine/qclib/qccguiqt.cpp b/engine/qclib/qccguiqt.cpp index d1cf8116..b376673c 100644 --- a/engine/qclib/qccguiqt.cpp +++ b/engine/qclib/qccguiqt.cpp @@ -1200,6 +1200,18 @@ public: return NULL;//"Type info not available. Compile first."; } + void clearannotates(void) + { + for (int i = 0; i < numdocuments; i++) + { + document_s *d = docs[i]; + s->setDocument(d->doc); + s->clearAnnotations(); + } + if (curdoc) + s->setDocument(curdoc->doc); + } + bool annotate(const char *line) { auto filename = line+6; @@ -2292,6 +2304,8 @@ int GUIprintf(const char *msg, ...) sizes.append(1); mainwnd->logsplit.setSizes(sizes); } + + mainwnd->docs.clearannotates(); return 0; } diff --git a/engine/qclib/qcctui.c b/engine/qclib/qcctui.c index a2772ca3..f6bc7bcb 100644 --- a/engine/qclib/qcctui.c +++ b/engine/qclib/qcctui.c @@ -119,7 +119,7 @@ int main (int argc, const char **argv) { unsigned int i; pbool sucess; -#ifdef _WIN32 +#if 0//def _WIN32 pbool writelog = true; //spew log files on windows. windows often closes the window as soon as the program ends making its output otherwise unreadable. #else pbool writelog = false; //other systems are sane.