diff --git a/engine/qclib/comprout.c b/engine/qclib/comprout.c index 8481c0977..d9ba9b0d3 100644 --- a/engine/qclib/comprout.c +++ b/engine/qclib/comprout.c @@ -111,7 +111,7 @@ pbool CompileParams(progfuncs_t *progfuncs, void(*cb)(void), int nump, const cha PostCompile(); - return true; + return !pr_error_count; } int PDECL Comp_Begin(pubprogfuncs_t *progfuncs, int nump, const char **parms) { diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 311b92aea..5965a69a5 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -399,6 +399,7 @@ enum qcop_e { OP_ANDSTORE_F, OP_BITCLR_F, OP_BITCLR_I, + OP_BITCLR_V, OP_ADD_SI, OP_ADD_IS, @@ -449,6 +450,9 @@ enum qcop_e { OP_EQ_FLD, OP_NE_FLD, + OP_SPACESHIP_F, //lame + OP_SPACESHIP_S, //basically strcmp. + //special/fake opcodes used by the decompiler. OPD_GOTO_FORSTART, OPD_GOTO_WHILE1, diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 6b61f786d..89ae661ec 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -706,6 +706,7 @@ extern int optres_logicops; extern int optres_inlines; pbool CompileParams(progfuncs_t *progfuncs, void(*cb)(void), int nump, const char **parms); +pbool QCC_RegisterSourceFile(const char *filename); void QCC_PR_PrintStatement (QCC_statement_t *s); @@ -826,6 +827,7 @@ enum { WARN_UNDESIRABLECONVENTION, WARN_SAMENAMEASGLOBAL, WARN_CONSTANTCOMPARISON, + WARN_DIVISIONBY0, WARN_UNSAFEFUNCTIONRETURNTYPE, WARN_MISSINGOPTIONAL, WARN_SYSTEMCRC, //unknown system crc diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 30a822be5..ad1b38098 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -728,6 +728,7 @@ QCC_opcode_t pr_opcodes[] = {7, "&=", "ANDSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float, OPF_STORE}, {7, "&~=", "BITCLR_F", PC_STORE, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STORE}, {7, "&~=", "BITCLR_I", PC_STORE, ASSOC_LEFT, &type_integer, &type_integer, &type_integer, OPF_STORE}, + {7, "&~=", "BITCLR_V", PC_STORE, ASSOC_LEFT, &type_vector, &type_vector, &type_vector, OPF_STORE}, {7, "+", "ADD_SI", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_integer, &type_string, OPF_STD}, {7, "+", "ADD_IS", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_string, &type_string, OPF_STD}, @@ -776,6 +777,9 @@ QCC_opcode_t pr_opcodes[] = {7, "==", "EQ_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float, OPF_STD}, {7, "!=", "NE_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float, OPF_STD}, + {7, "<=>", "SPACESHIP_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float, OPF_STD}, + {7, "<=>", "SPACESHIP_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float, OPF_STD}, + {0, NULL, "OPD_GOTO_FORSTART"}, {0, NULL, "OPD_GOTO_WHILE1"}, @@ -1069,6 +1073,7 @@ QCC_opcode_t *opcodes_clearstore[] = { &pr_opcodes[OP_BITCLR_F], &pr_opcodes[OP_BITCLR_I], + &pr_opcodes[OP_BITCLR_V], NULL }; QCC_opcode_t *opcodes_clearstorep[] = @@ -1093,6 +1098,13 @@ QCC_opcode_t *opcodes_shrstore[] = NULL }; +QCC_opcode_t *opcodes_spaceship[] = +{ + &pr_opcodes[OP_SPACESHIP_F], + &pr_opcodes[OP_SPACESHIP_S], + NULL +}; + QCC_opcode_t *opcodes_none[] = { NULL @@ -2563,6 +2575,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); optres_constantarithmatic++; return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(eval_a) ^ QCC_PR_RoundFloatConst(eval_b)); + case OP_BITXOR_V: + QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + optres_constantarithmatic++; + return QCC_MakeVectorConst( + (int)eval_a->vector[0] ^ (int)eval_b->vector[0], + (int)eval_a->vector[1] ^ (int)eval_b->vector[1], + (int)eval_a->vector[2] ^ (int)eval_b->vector[2]); case OP_RSHIFT_F: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); optres_constantarithmatic++; @@ -2616,6 +2635,8 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ case OP_DIV_F: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); optres_constantarithmatic++; + if (!eval_b->_float) + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division of %g by 0\n", eval_a->_float); return QCC_MakeFloatConst(eval_a->_float / eval_b->_float); case OP_ADD_F: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); @@ -2651,7 +2672,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ optres_constantarithmatic++; if (eval_b->_int == 0) { - QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Division by constant 0"); + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division by constant 0"); return QCC_MakeIntConst(0); } else @@ -2817,9 +2838,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ eval_a->_int * eval_b->vector[2]); case OP_DIV_IF: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + if (!eval_b->_float) + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division of %d by 0\n", eval_a->_int); return QCC_MakeFloatConst(eval_a->_int / eval_b->_float); case OP_DIV_FI: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); + if (!eval_b->_int) + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division of %g by 0\n", eval_a->_float); return QCC_MakeFloatConst(eval_a->_float / eval_b->_int); case OP_BITAND_IF: QCC_FreeTemp(var_a); QCC_FreeTemp(var_b); @@ -3102,7 +3127,12 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } break; case OP_DIV_F: + case OP_DIV_IF: + if (!eval_b->_float) + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division by 0\n"); + //fallthrough case OP_MUL_F: + case OP_MUL_IF: if (eval_b->_float == 1) { optres_constantarithmatic++; @@ -3122,7 +3152,11 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } break; case OP_DIV_I: + case OP_DIV_FI: + if (!eval_b->_int) + QCC_PR_ParseWarning(WARN_DIVISIONBY0, "Division by 0\n"); case OP_MUL_I: + case OP_MUL_FI: if (eval_b->_int == 1) { optres_constantarithmatic++; @@ -3779,6 +3813,42 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ } break; + case OP_SPACESHIP_F: + { //basically just a subtraction-with-fsign. + const QCC_eval_t *eval; + QCC_statement_t *patch1; + var_a = QCC_PR_Statement(&pr_opcodes[OP_SUB_F], var_a, var_b, NULL); + eval = QCC_SRef_EvalConst(var_c); + if (eval) + { + if (eval->_float < 0) + return QCC_MakeFloatConst(-1); + else + return QCC_MakeFloatConst(eval->_float > 0); + } + + //hack: make local, not temp. this disables assignment/temp folding... + var_c = QCC_MakeSRefForce(QCC_PR_DummyDef(type_float, "ternary", pr_scope, 0, NULL, 0, false, GDF_STRIP), 0, type_float); + + //var_c = a>0; + QCC_PR_SimpleStatement(&pr_opcodes[OP_GT_F], var_a, QCC_MakeFloatConst(0), var_c, true); + patch1 = QCC_Generate_OP_IFNOT(QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], var_a, QCC_MakeFloatConst(0), NULL, 0), false); + QCC_PR_SimpleStatement(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(-1), var_c, nullsref, true); + patch1->b.ofs = &statements[numstatements] - patch1; + return var_c; + } + break; + case OP_SPACESHIP_S: + { + QCC_sref_t fnc = QCC_PR_EmulationFunc(strcmp); + if (!fnc.cast) + QCC_PR_ParseError(0, "strcmp function not defined: cannot emulate string<=>string"); + var_c = QCC_PR_GenerateFunctionCall2(nullsref, fnc, var_a, type_string, var_b, type_string); + var_c.cast = type_float; + return var_c; + } + break; + case OP_CONV_ITOF: case OP_STORE_IF: { @@ -3866,8 +3936,8 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ // r = (a & ~b) | (b & ~a); var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_V], var_b, nullsref, NULL, STFL_PRESERVEA); var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_a, var_c, NULL, STFL_PRESERVEA); - var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_V], var_a, nullsref, NULL, 0); - var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_b, var_a, NULL, 0); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_V], var_a, nullsref, NULL, STFL_PRESERVEA); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_b, var_a, NULL, STFL_PRESERVEB); return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_V], var_c, var_a, NULL, 0); case OP_IF_S: @@ -4113,6 +4183,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ var_b = var_c; var_c = ((op - pr_opcodes)==OP_BITCLRSTORE_I)?var_a:nullsref; break; + case OP_BITCLR_V: + var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_V], var_a, var_b, NULL, STFL_PRESERVEA); + op = &pr_opcodes[OP_SUB_V]; + var_c = nullsref; + break; + + case OP_BITCLR_F: var_c = var_b; var_b = var_a; @@ -6177,6 +6254,15 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, int copyop_v = 0, copyop_i = 0, copyop_idx=0; copyop_v = 0; copyop_i = 0; + if (arglist[i]->postinc) + { + arglist[i]->base = QCC_RefToDef(arglist[i], true); + arglist[i]->index = nullsref; + arglist[i]->type = REF_GLOBAL; + arglist[i]->postinc = false; + arglist[i]->readonly = true; + } + switch(arglist[i]->type) { case REF_GLOBAL: @@ -6635,82 +6721,6 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f funcname = QCC_GetSRefName(func); if (!newself.cast && !t->num_parms&&t->type != ev_variant) //intrinsics. These base functions have variable arguments. I would check for (...) args too, but that might be used for extended builtin functionality. (this code wouldn't compile otherwise) { - if (!strcmp(funcname, "sizeof")) - { - QCC_type_t *t; - func.sym->unused = true; - func.sym->referenced = true; - QCC_FreeTemp(func); - t = QCC_PR_ParseType(false, true); - if (t) - { - QCC_PR_Expect(")"); - return QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL); - } - else - { - int sz; - int oldstcount = numstatements; - QCC_ref_t refbuf, *r; - r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0); - if (r->type == REF_GLOBAL && r->base.sym->type == type_string && !strcmp(r->base.sym->name, "IMMEDIATE")) - sz = strlen(&strings[QCC_SRef_EvalConst(r->base)->string]) + 1; //sizeof("hello") includes the null, and is bytes not codepoints - else - { - sz = 4; //4 bytes per word. we don't support char/short (our string type is logically char*) - if (r->type == REF_ARRAYHEAD && !r->index.cast) - sz *= r->base.sym->arraysize; - sz *= r->cast->size; - } - QCC_FreeTemp(r->base); - if (r->index.cast) - QCC_FreeTemp(r->index); - //the term should not have side effects, or generate any actual statements. - numstatements = oldstcount; - QCC_PR_Expect(")"); - return QCC_MakeIntConst(sz); - } - } - if (!strcmp(funcname, "_length")) - { //for compat with gmqcc - QCC_type_t *t; - func.sym->unused = true; - func.sym->referenced = true; - QCC_FreeTemp(func); - t = QCC_PR_ParseType(false, true); - if (t) - { - QCC_PR_Expect(")"); - return QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL); - } - else - { - int sz = 0; - int oldstcount = numstatements; - QCC_ref_t refbuf, *r; - r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0); - if (r->type == REF_ARRAYHEAD) - sz = r->base.sym->arraysize; - else if (r->cast == type_string) - { - QCC_sref_t d = QCC_RefToDef(r, false); - const QCC_eval_t *c = QCC_SRef_EvalConst(d); - if (c) - sz = strlen(&strings[c->string]); //_length("hello") does NOT include the null (like strlen), but is bytes not codepoints - } - else if (r->cast == type_vector) - sz = 3; //might as well. considering that vectors can be indexed as an array. - else - QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "_length() unsupported argument type for intrinsic"); - QCC_FreeTemp(r->base); - if (r->index.cast) - QCC_FreeTemp(r->index); - //the term should not have side effects, or generate any actual statements. - numstatements = oldstcount; - QCC_PR_Expect(")"); - return QCC_MakeIntConst(sz); - } - } if (!strcmp(funcname, "alloca")) { //FIXME: half of these functions with known arguments should be handled later or something QCC_sref_t sz, ret; @@ -8739,8 +8749,6 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo if (!strcmp(name, "nil")) d = QCC_MakeIntConst(0); else if ( (!strcmp(name, "randomv")) || - (!strcmp(name, "sizeof")) || //FIXME: sizeof should be an operator, not a function (ie: 'sizeof foo' should work just like 'sizeof(foo)' does) - (!strcmp(name, "_length")) || (!strcmp(name, "alloca")) || (!strcmp(name, "entnum")) || (!strcmp(name, "autocvar")) || @@ -9335,6 +9343,85 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) return r; } } + if (pr_token_type == tt_name) //a little extra speed... + { + if (QCC_PR_CheckKeyword(true, "sizeof")) + { + QCC_type_t *t; + pbool bracket = QCC_PR_CheckToken("("); + t = QCC_PR_ParseType(false, true); + if (t) + { + if (bracket) + QCC_PR_Expect(")"); + return QCC_DefToRef(retbuf, QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL)); + } + else + { + int sz; + int oldstcount = numstatements; + QCC_ref_t refbuf, *r; + r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0); + if (r->type == REF_GLOBAL && r->base.sym->type == type_string && !strcmp(r->base.sym->name, "IMMEDIATE")) + sz = strlen(&strings[QCC_SRef_EvalConst(r->base)->string]) + 1; //sizeof("hello") includes the null, and is bytes not codepoints + else + { + sz = 4; //4 bytes per word. we don't support char/short (our string type is logically char*) + if (r->type == REF_ARRAYHEAD && !r->index.cast) + sz *= r->base.sym->arraysize; + sz *= r->cast->size; + } + QCC_FreeTemp(r->base); + if (r->index.cast) + QCC_FreeTemp(r->index); + //the term should not have side effects, or generate any actual statements. + numstatements = oldstcount; + if (bracket) + QCC_PR_Expect(")"); + return QCC_DefToRef(retbuf, QCC_MakeIntConst(sz)); + } + } + if (QCC_PR_CheckKeyword(true, "_length")) + { //for compat with gmqcc + pbool bracket = QCC_PR_CheckToken("("); + /*QCC_type_t *t; + t = QCC_PR_ParseType(false, true); + if (t) + { + if (bracket) + QCC_PR_Expect(")"); + return QCC_DefToRef(retbuf, QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL)); + } + else*/ + { + int sz = 0; + int oldstcount = numstatements; + QCC_ref_t refbuf, *r; + r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0); + if (r->type == REF_ARRAYHEAD) + sz = r->base.sym->arraysize; + else if (r->cast == type_string) + { + QCC_sref_t d = QCC_RefToDef(r, false); + const QCC_eval_t *c = QCC_SRef_EvalConst(d); + if (c) + sz = strlen(&strings[c->string]); //_length("hello") does NOT include the null (like strlen), but is bytes not codepoints + } + else if (r->cast == type_vector) + sz = 3; //might as well. considering that vectors can be indexed as an array. + else + QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "_length() unsupported argument type for intrinsic"); + QCC_FreeTemp(r->base); + if (r->index.cast) + QCC_FreeTemp(r->index); + //the term should not have side effects, or generate any actual statements. + numstatements = oldstcount; + if (bracket) + QCC_PR_Expect(")"); + return QCC_DefToRef(retbuf, QCC_MakeIntConst(sz)); + } + } + } return QCC_PR_ParseRefValue (retbuf, pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN), true, true); } @@ -9350,6 +9437,9 @@ static int QCC_canConv(QCC_sref_t from, etype_t to) //triggers a warning. conversion works by using _x if (from.cast->type == ev_vector && to == ev_float) return 8; + //triggers a warning. + if (from.cast->type == ev_float && to == ev_vector) + return 7; if (pr_classtype) { @@ -10835,7 +10925,7 @@ static QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opc else { op = bestop; - if (numconversions>3) + /*if (numconversions>3) { c=QCC_canConv(lhs, (*op->type_a)->type); if (c>3) @@ -10843,7 +10933,7 @@ static QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opc c=QCC_canConv(rhs, (*op->type_b)->type); if (c>3) QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhs.cast->name, (*op->type_a)->name); - } + }*/ } return op; } @@ -10946,7 +11036,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) lvalisnull = QCC_SRef_IsNull(val); #if 1 //hack: make local, not temp. this disables assignment/temp folding... - r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, true, GDF_STRIP), 0, val.cast); + r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, false, GDF_STRIP), 0, val.cast); #else r = QCC_GetTemp(val.cast); #endif @@ -10981,7 +11071,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) lvalisnull = QCC_SRef_IsNull(val); #if 1 //hack: make local, not temp. this disables assignment/temp folding... - r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, true, GDF_STRIP), 0, val.cast); + r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, false, GDF_STRIP), 0, val.cast); #else r = QCC_GetTemp(val.cast); #endif @@ -11127,6 +11217,12 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) ops_ptr = opcodes_divstorep; opname = "/="; } + else if (QCC_PR_CheckToken ("<=>")) + { + ops = opcodes_spaceship; + ops_ptr = opcodes_none; + opname = "<=>"; + } else { ops = NULL; @@ -11309,6 +11405,19 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) rhsd = QCC_RefToDef(rhsr, true); op = QCC_PR_ChooseOpcode(lhsd, rhsd, &opcodeprioritized[priority][opnum]); + if ((*op->type_a)->type != lhsd.cast->type && (*op->type_a)->type != ev_variant) + { + if (QCC_canConv(lhsd, (*op->type_a)->type) > 3) + QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", lhsd.cast->name, (*op->type_a)->name); + lhsd = QCC_EvaluateCast(lhsd, (*op->type_a), true); + } + if ((*op->type_b)->type != rhsd.cast->type && (*op->type_b)->type != ev_variant) + { + if (QCC_canConv(rhsd, (*op->type_b)->type) > 3) + QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhsd.cast->name, (*op->type_b)->name); + rhsd = QCC_EvaluateCast(rhsd, (*op->type_b), true); + } + if (logicjump) //logic shortcut jumps to just before the if. the rhs is uninitialised if the jump was taken, but the lhs makes it deterministic. { logicjump->flags |= STF_LOGICOP; @@ -17228,6 +17337,7 @@ pbool QCC_PR_CompileFile (char *string, char *filename) memcpy(&oldjb, &pr_parse_abort, sizeof(oldjb)); if( setjmp( pr_parse_abort ) ) { + pr_error_count++; // dont count it as error } else { //clock up the first line diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 4bda87291..f196c4210 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -55,7 +55,7 @@ extern pbool expandedemptymacro; extern unsigned int locals_end, locals_start; extern QCC_type_t *pr_classtype; QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *type, pbool dowrap); - +QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto); static void Q_strlcpy(char *dest, const char *src, int sizeofdest) { @@ -72,13 +72,13 @@ static void Q_strlcpy(char *dest, const char *src, int sizeofdest) char *pr_punctuation[] = // longer symbols must be before a shorter partial match -{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "&=", "++", "--", "->", "^=", "::", ";", ",", "!", "*^", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "><", "<<=", "<<", "<", ">>=", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^^", "^", "~", ":", NULL}; +{"&&", "||", "<=>", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "&=", "++", "--", "->", "^=", "::", ";", ",", "!", "*^", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "><", "<<=", "<<", "<", ">>=", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^^", "^", "~", ":", NULL}; char *pr_punctuationremap[] = //a nice bit of evilness. //(+) -> |= //-> -> . //(-) -> &~= -{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "&=", "++", "--", ".", "^=", "::", ";", ",", "!", "*^", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "><", "<<=", "<<", "<", ">>=", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^^", "^", "~", ":", NULL}; +{"&&", "||", "<=>", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "&=", "++", "--", ".", "^=", "::", ";", ",", "!", "*^", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "><", "<<=", "<<", "<", ">>=", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^^", "^", "~", ":", NULL}; // simple types. function types are dynamically allocated QCC_type_t *type_void; //void @@ -1306,21 +1306,8 @@ static pbool QCC_PR_Precompiler(void) } else if (!QC_strcasecmp(qcc_token, "sourcefile")) { - #define MAXSOURCEFILESLIST 8 - extern char sourcefileslist[MAXSOURCEFILESLIST][1024]; - extern int numsourcefiles; - - int i; - - QCC_COM_Parse(msg); - - for (i = 0; i < numsourcefiles; i++) - { - if (!strcmp(sourcefileslist[i], qcc_token)) - break; - } - if (i == numsourcefiles && numsourcefiles < MAXSOURCEFILESLIST) - strcpy(sourcefileslist[numsourcefiles++], qcc_token); + QCC_COM_Parse(msg); + QCC_RegisterSourceFile(qcc_token); } else if (!QC_strcasecmp(qcc_token, "TARGET")) { @@ -1329,7 +1316,7 @@ static pbool QCC_PR_Precompiler(void) QCC_PR_ParseWarning(WARN_BADTARGET, "Unknown target \'%s\'. Ignored.\nValid targets are: ID, HEXEN2, FTE, FTEH2, KK7, DP(patched)", qcc_token); } else if (!QC_strcasecmp(qcc_token, "PROGS_SRC")) - { //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF. + { //doesn't make sense, but silenced if you are switching between using a certain precompiler app used with CuTF. } else if (!QC_strcasecmp(qcc_token, "PROGS_DAT")) { //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF. @@ -1550,6 +1537,154 @@ void QCC_PR_LexString (void) // print("Found \"%s\"\n", pr_immediate_string); } #else +int QCC_PR_LexEscapedCodepoint(void) +{ //for "\foo" or '\foo' handling. + //caller will have read the \ already. + int t; + int c = *pr_file_p++; + if (!c) + QCC_PR_ParseError (ERR_EOF, "EOF inside quote"); + if (c == 'n') + c = '\n'; + else if (c == 'r') + c = '\r'; + else if (c == '#') //avoid preqcc expansion in strings. + c = '#'; + else if (c == '"') + c = '"'; + else if (c == 't') + c = '\t'; //tab + else if (c == 'a') + c = '\a'; //bell + else if (c == 'v') + c = '\v'; //vertical tab + else if (c == 'f') + c = '\f'; //form feed +// else if (c == 's' || c == 'b') +// c = 0; //invalid... + //else if (c == 'b') + // c = '\b'; + else if (c == '[') + c = 0xe010; //quake specific + else if (c == ']') + c = 0xe011; //quake specific + else if (c == '{') + { + int d; + c = 0; + if (*pr_file_p == 'x') + { + pr_file_p++; + while ((d = *pr_file_p++) != '}') + { + if (d >= '0' && d <= '9') + c = c * 16 + d - '0'; + else if (d >= 'a' && d <= 'f') + c = c * 16 + 10+d - 'a'; + else if (d >= 'A' && d <= 'F') + c = c * 16 + 10+d - 'A'; + else + QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); + } + } + else + { + while ((d = *pr_file_p++) != '}') + { + if (d >= '0' && d <= '9') + c = c * 10 + d - '0'; + else + QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); + } + } + } + else if (c == '.') + c = 0xe01c; + else if (c == '<') + c = 0xe01d; //separator start + else if (c == '-') + c = 0xe01e; //separator middle + else if (c == '>') + c = 0xe01f; //separator end + else if (c == '(') + c = 0xe080; //slider start + else if (c == '=') + c = 0xe081; //slider middle + else if (c == ')') + c = 0xe082; //slider end + else if (c == '+') + c = 0xe083; //slider box + else if (c == 'u' || c == 'U') + { + //lower case u specifies exactly 4 nibbles. + //upper case U specifies exactly 8 nibbles. + unsigned int nibbles = (c=='u')?4:8; + c = 0; + while (nibbles --> 0) + { + t = (unsigned char)*pr_file_p; + if (t >= '0' && t <= '9') + c = (c*16) + (t - '0'); + else if (t >= 'A' && t <= 'F') + c = (c*16) + (t - 'A') + 10; + else if (t >= 'a' && t <= 'f') + c = (c*16) + (t - 'a') + 10; + else + break; + pr_file_p++; + } + if (nibbles) + QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Unicode character terminated unexpectedly"); + } + else if (c == 'x' || c == 'X') + { + int d; + c = 0; + + d = (unsigned char)*pr_file_p++; + if (d >= '0' && d <= '9') + c += d - '0'; + else if (d >= 'A' && d <= 'F') + c += d - 'A' + 10; + else if (d >= 'a' && d <= 'f') + c += d - 'a' + 10; + else + QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); + + c *= 16; + + d = (unsigned char)*pr_file_p++; + if (d >= '0' && d <= '9') + c += d - '0'; + else if (d >= 'A' && d <= 'F') + c += d - 'A' + 10; + else if (d >= 'a' && d <= 'f') + c += d - 'a' + 10; + else + QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); + } + else if (c == '\\') + c = '\\'; + else if (c == '\'') + c = '\''; + else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud). + c = 0xe012 + c - '0'; + else if (c == '\r') + { //sigh + c = *pr_file_p++; + if (c != '\n') + QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r"); + pr_source_line++; + } + else if (c == '\n') + { //sigh + pr_source_line++; + } + else + QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c); + + return c; +} void QCC_PR_LexString (void) { unsigned int c, t; @@ -1675,134 +1810,36 @@ void QCC_PR_LexString (void) QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote"); if (c=='\\') { // escape char - c = *pr_file_p++; - if (!c) - QCC_PR_ParseError (ERR_EOF, "EOF inside quote"); - if (c == 'n') - c = '\n'; - else if (c == 'r') - c = '\r'; - else if (c == '#') //avoid preqcc expansion in strings. - c = '#'; - else if (c == '"') - c = '"'; - else if (c == 't') - c = '\t'; //tab - else if (c == 'a') - c = '\a'; //bell - else if (c == 'v') - c = '\v'; //vertical tab - else if (c == 'f') - c = '\f'; //form feed - else if (c == 's' || c == 'b') + c = *pr_file_p; //peek at it, for our hacks. + if (c == 's' || c == 'b') { + pr_file_p++; texttype ^= 0xe080; continue; } - //else if (c == 'b') - // c = '\b'; - else if (c == '[') - c = 0xe010; //quake specific - else if (c == ']') - c = 0xe011; //quake specific - else if (c == '{') - { - int d; - c = 0; - while ((d = *pr_file_p++) != '}') - { - c = c * 10 + d - '0'; - if (d < '0' || d > '9' || c > 255) - QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); - } - } else if (c == '.') + { + pr_file_p++; c = 0xe01c | texttype; - else if (c == '<') - c = 0xe01d; //separator start - else if (c == '-') - c = 0xe01e; //separator middle - else if (c == '>') - c = 0xe01f; //separator end - else if (c == '(') - c = 0xe080; //slider start - else if (c == '=') - c = 0xe081; //slider middle - else if (c == ')') - c = 0xe082; //slider end - else if (c == '+') - c = 0xe083; //slider box + } else if (c == 'u' || c == 'U') { - //lower case u specifies exactly 4 nibbles. - //upper case U specifies exactly 8 nibbles. - unsigned int nibbles = (c=='u')?4:8; - c = 0; - while (nibbles --> 0) - { - t = (unsigned char)*pr_file_p; - if (t >= '0' && t <= '9') - c = (c*16) + (t - '0'); - else if (t >= 'A' && t <= 'F') - c = (c*16) + (t - 'A') + 10; - else if (t >= 'a' && t <= 'f') - c = (c*16) + (t - 'a') + 10; - else - break; - pr_file_p++; - } - if (nibbles) - QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Unicode character terminated unexpectedly"); - + c = QCC_PR_LexEscapedCodepoint(); goto forceutf8; } else if (c == 'x' || c == 'X') { - int d; - c = 0; - - d = (unsigned char)*pr_file_p++; - if (d >= '0' && d <= '9') - c += d - '0'; - else if (d >= 'A' && d <= 'F') - c += d - 'A' + 10; - else if (d >= 'a' && d <= 'f') - c += d - 'a' + 10; - else - QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); - - c *= 16; - - d = (unsigned char)*pr_file_p++; - if (d >= '0' && d <= '9') - c += d - '0'; - else if (d >= 'A' && d <= 'F') - c += d - 'A' + 10; - else if (d >= 'a' && d <= 'f') - c += d - 'a' + 10; - else - QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code"); + c = QCC_PR_LexEscapedCodepoint(); + if (c > 0xff) + QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code - codepoint %u is above 0xFF", c); goto forcebyte; } - else if (c == '\\') - c = '\\'; - else if (c == '\'') - c = '\''; - else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud). - c = 0xe012 + c - '0'; - else if (c == '\r') - { //sigh - c = *pr_file_p++; - if (c != '\n') - QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r"); - pr_source_line++; - } - else if (c == '\n') - { //sigh - pr_source_line++; - } else - QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c); + { + c = QCC_PR_LexEscapedCodepoint(); + if (stringtype != 2 && c > 0xff) + QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad legacy character code - codepoint %u is above 0xFF", c); + } } else if (c=='\"') { @@ -2044,6 +2081,15 @@ static void QCC_PR_LexNumber (void) pr_token[tokenlen++] = '0'; pr_token[tokenlen++] = 'x'; } + else if (pr_file_p[0] == '0') + { + pr_file_p++; + if (*pr_file_p >= '0' && *pr_file_p <= '9') + QCC_PR_ParseWarning(WARN_GMQCC_SPECIFIC, "A leading 0 is interpreted as base-8."); + base = 8; + + pr_token[tokenlen++] = '0'; + } pr_immediate_type = NULL; //assume base 10 if not stated @@ -2052,7 +2098,7 @@ static void QCC_PR_LexNumber (void) while((c = *pr_file_p)) { - if (c >= '0' && c <= '9') + if (c >= '0' && c <= '9' && c < '0'+base) { pr_token[tokenlen++] = c; num*=base; @@ -2205,43 +2251,32 @@ static void QCC_PR_LexVector (void) { int i; - pr_file_p++; + pr_file_p++; //skip the leading ' char if (*pr_file_p == '\\') {//extended character constant + pr_file_p++; pr_token_type = tt_immediate; pr_immediate_type = type_float; - pr_file_p++; - switch(*pr_file_p) - { - case 'n': - pr_immediate._float = '\n'; - break; - case 'r': - pr_immediate._float = '\r'; - break; - case 't': - pr_immediate._float = '\t'; - break; - case '\'': - pr_immediate._float = '\''; - break; - case '\"': - pr_immediate._float = '\"'; - break; - case '\\': - pr_immediate._float = '\\'; - break; - default: - QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant"); - } - pr_file_p++; + pr_immediate._float = QCC_PR_LexEscapedCodepoint(); if (*pr_file_p != '\'') QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant"); pr_file_p++; return; } - if (pr_file_p[1] == '\'') + if ((unsigned char)*pr_file_p >= 0x80) + { + int b = utf8_check(pr_file_p, &pr_immediate._int); //utf-8 codepoint. + pr_token_type = tt_immediate; + pr_immediate_type = type_float; + if (flag_qccx) + QCC_PR_ParseWarning(WARN_DENORMAL, "char constant: denormal"); + else + pr_immediate._float = pr_immediate._int; + pr_file_p+=b+1; + return; + } + else if (pr_file_p[1] == '\'') {//character constant pr_token_type = tt_immediate; pr_immediate_type = type_float; @@ -4808,7 +4843,7 @@ QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype) //expects a ( to have already been parsed. QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) { - QCC_type_t *ftype; + QCC_type_t *ftype, *t; char *name; int definenames = !recursivefunctiontype; int numparms = 0; @@ -4834,42 +4869,56 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) if (QCC_PR_CheckToken ("...")) { - ftype->vargs = true; - break; - } - - foundinout = false; - paramlist[numparms].optional = false; - paramlist[numparms].isvirtual = false; - paramlist[numparms].out = false; - - while(1) - { - if (!paramlist[numparms].optional && QCC_PR_CheckKeyword(keyword_optional, "optional")) - paramlist[numparms].optional = true; - else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "inout")) + t = QCC_PR_ParseType(false, true); //the evil things I do... + if (!t) { - paramlist[numparms].out = true; - foundinout = true; - } - else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "out")) - { - paramlist[numparms].out = 2; //not really supported, but parsed for readability. - foundinout = true; - } - else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "in")) - { - paramlist[numparms].out = false; - foundinout = true; + ftype->vargs = true; + break; } else - break; + { //its a ... followed by a type... don't bug out... + t = QCC_PR_FieldType(t); + t = QCC_PR_FieldType(t); + t = QCC_PR_FieldType(t); + paramlist[numparms].type = t; + } } + else + { + foundinout = false; + paramlist[numparms].optional = false; + paramlist[numparms].isvirtual = false; + paramlist[numparms].out = false; + while(1) + { + if (!paramlist[numparms].optional && QCC_PR_CheckKeyword(keyword_optional, "optional")) + paramlist[numparms].optional = true; + else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "inout")) + { + paramlist[numparms].out = true; + foundinout = true; + } + else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "out")) + { + paramlist[numparms].out = 2; //not really supported, but parsed for readability. + foundinout = true; + } + else if (!foundinout && QCC_PR_CheckKeyword(keyword_inout, "in")) + { + paramlist[numparms].out = false; + foundinout = true; + } + else + break; + } + + t = QCC_PR_ParseType(false, false); + } paramlist[numparms].defltvalue.cast = NULL; paramlist[numparms].ofs = 0; paramlist[numparms].arraysize = 0; - paramlist[numparms].type = QCC_PR_ParseType(false, false); + paramlist[numparms].type = t; if (!paramlist[numparms].type) QCC_PR_ParseError(0, "Expected type\n"); @@ -5104,6 +5153,35 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) // int ofs; + if (QCC_PR_PeekToken ("...") ) //this is getting stupid + { + QCC_PR_LexWhitespace (false); + if (*pr_file_p == '(') + { //work around gmqcc's "(...(" being misinterpreted as a cast syntax error, instead abort here so it can be treated as an intrinsic (with args) instead. + if (silentfail) + return NULL; + QCC_PR_ParseError (ERR_NOTATYPE, "\"%s\" is not a type", pr_token); + } + QCC_PR_Lex (); + + type = QCC_PR_NewType("FIELD_TYPE", ev_field, false); + type->aux_type = QCC_PR_ParseType (false, false); + type->size = type->aux_type->size; + + newt = QCC_PR_FindType (type); + type = QCC_PR_NewType("FIELD_TYPE", ev_field, false); + type->aux_type = newt; + type->size = type->aux_type->size; + + newt = QCC_PR_FindType (type); + type = QCC_PR_NewType("FIELD_TYPE", ev_field, false); + type->aux_type = newt; + type->size = type->aux_type->size; + + if (newtype) + return type; + return QCC_PR_FindType (type); + } if (QCC_PR_CheckToken ("..")) //so we don't end up with the user specifying '. .vector blah' (hexen2 added the .. token for array ranges) { newt = QCC_PR_NewType("FIELD_TYPE", ev_field, false); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 39072d846..7be568aba 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -10,6 +10,8 @@ #include "errno.h" +#define countof(array) (sizeof(array)/sizeof(array[0])) + //#define TODO_READWRITETRACK //#define DEBUG_DUMP @@ -57,10 +59,10 @@ int tempsstart; #define MAXSOURCEFILESLIST 8 char sourcefileslist[MAXSOURCEFILESLIST][1024]; -QCC_def_t *sourcefilesdefs[MAXSOURCEFILESLIST]; -int sourcefilesnumdefs; -int currentsourcefile; -int numsourcefiles; +QCC_def_t *sourcefilesdefs[MAXSOURCEFILESLIST]; //for the gui to peek at. +int sourcefilesnumdefs; //maximum used... +int currentsourcefile; //currently compiling file. +int numsourcefiles; //count pending. extern char *compilingfile; //file currently being compiled char compilingrootfile[1024]; //the .src file we started from (the current one, not original) @@ -232,6 +234,7 @@ struct { {" F329", WARN_REDECLARATIONMISMATCH}, {" F330", WARN_MUTEDEPRECATEDVARIABLE}, {" F331", WARN_SELFNOTTHIS}, + {" F332", WARN_DIVISIONBY0}, {" F207", WARN_NOTREFERENCEDFIELD}, {" F208", WARN_NOTREFERENCEDCONST}, @@ -989,7 +992,7 @@ static int WriteBodylessFuncs (int handle) int ret=0; for (d=pr.def_head.next ; d ; d=d->next) { - if (!d->used || !d->constant) + if (!d->used || !d->constant || d->symbolheader != d) continue; if (d->type->type == ev_function && !d->scope)// function parms are ok @@ -1066,7 +1069,12 @@ static void QCC_FinaliseDef(QCC_def_t *def) #endif if (def->symboldata == qcc_pr_globals + def->ofs) + { +#ifdef DEBUG_DUMP_GLOBALMAP + externs->Printf("Prefinalised %s @ %i+%i\n", def->name, def->ofs, ssize); +#endif return; //was already finalised. + } if (def->symbolheader != def) { @@ -1257,7 +1265,7 @@ static void QCC_UnmarshalLocals(void) //first, finalize all static locals that shouldn't form part of the local defs. for (i=0 ; inextlocal) if (d->isstatic || (d->constant && d->initialized)) @@ -2660,7 +2668,7 @@ strofs = (strofs+3)&~3; { char *ext; ext = strrchr(destfile, '.'); - if (strchr(ext, '/') || strchr(ext, '\\')) + if (!ext || strchr(ext, '/') || strchr(ext, '\\')) break; if (!stricmp(ext, ".gz")) { @@ -3374,7 +3382,7 @@ static int QCC_PR_FinishCompilation (void) { if (d->type->type == ev_field && !d->symboldata) QCC_PR_FinishFieldDef(d); - if (d->type->type == ev_function && d->constant)// function parms are ok + if (d->type->type == ev_function && d->constant && d->symbolheader == d)// function parms are ok { if (d->isextern) { @@ -4120,6 +4128,22 @@ static void QCC_CopyFiles (void) #define WINDOWSARG(x) false #endif +pbool QCC_RegisterSourceFile(const char *filename) +{ + int i; + for (i = 0; i < numsourcefiles; i++) + { + if (!strcmp(sourcefileslist[i], filename)) + return true; + } + if (numsourcefiles < MAXSOURCEFILESLIST) + { + strcpy(sourcefileslist[numsourcefiles++], filename); + return true; + } + return false; +} + static void QCC_PR_CommandLinePrecompilerOptions (void) { CompilerConstant_t *cnst; @@ -4136,18 +4160,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) { if (++i == myargc) break; - for (j = 0; j < numsourcefiles; j++) - { - if (!strcmp(sourcefileslist[j], myargv[i])) - break; - } - if (j == numsourcefiles) - { - if (numsourcefiles < MAXSOURCEFILESLIST) - strcpy(sourcefileslist[numsourcefiles++], myargv[i]); - else - QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "too many -srcfile arguments"); - } + if (!QCC_RegisterSourceFile(myargv[i])) + QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "too many -srcfile arguments"); } else if ( !strcmp(myargv[i], "-src") ) { @@ -4339,6 +4353,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) keyword_int = keyword_integer = keyword_typedef = keyword_struct = keyword_union = keyword_enum = keyword_enumflags = false; keyword_thinktime = keyword_until = keyword_loop = false; keyword_wrap = keyword_weak = false; + + qccwarningaction[WARN_PARAMWITHNONAME] = WA_ERROR; } else if (!strcmp(myargv[i]+5, "hcc") || !strcmp(myargv[i]+5, "hexenc")) { @@ -4372,6 +4388,10 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE; //and many people would argue that this was a feature rather than a bug qccwarningaction[WARN_UNINITIALIZED] = WA_IGNORE; //all locals get 0-initialised anyway, and our checks are not quite up to scratch. qccwarningaction[WARN_GMQCC_SPECIFIC] = WA_IGNORE; //we shouldn't warn about gmqcc syntax when we're trying to be compatible with it. there's always -Wextra. + qccwarningaction[WARN_SYSTEMCRC] = WA_IGNORE; //lameness + qccwarningaction[WARN_SYSTEMCRC2] = WA_IGNORE; //extra lameness + + qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //some sanity. keyword_asm = false; keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_unused = keyword_used = keyword_nonstatic = keyword_ignore = keyword_strip = false; @@ -4426,6 +4446,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) flag_ifstring = state; else if (!stricmp(arg, "true-empty-strings")) flag_brokenifstring = state; + else if (!stricmp(arg, "arithmetic-exceptions")) + qccwarningaction[WARN_DIVISIONBY0] = state?WA_ERROR:WA_IGNORE; else if (!stricmp(arg, "lno")) { //currently we always try to write lno files, when filename info isn't stripped @@ -4478,6 +4500,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) case WARN_IFSTRING_USED: case WARN_UNINITIALIZED: case WARN_GMQCC_SPECIFIC: + case WARN_SYSTEMCRC: + case WARN_SYSTEMCRC2: qccwarningaction[j] = qccwarningaction[WARN_GMQCC_SPECIFIC]; break; @@ -4486,6 +4510,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) case WARN_EXTRAPRECACHE: //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives. case WARN_FTE_SPECIFIC: //kinda annoying when its actually valid code. case WARN_MUTEDEPRECATEDVARIABLE: //these were explicitly muted by the user using checkbuiltin/etc to mute specific symbols. + case WARN_DIVISIONBY0: //breaks xonotic, which seems to want nans. break; default: @@ -4559,6 +4584,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) || !strcmp(myargv[i], "-max_fields") || !strcmp(myargv[i], "-max_statements") || !strcmp(myargv[i], "-max_functions") || !strcmp(myargv[i], "-max_types") || !strcmp(myargv[i], "-max_temps") || !strcmp(myargv[i], "-max_macros") ) { + if (++i == myargc) + QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "Missing value for %s arg", myargv[--i]); } else if ( !strcmp(myargv[i], "--version") ) { @@ -4569,8 +4596,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "Unrecognised parameter (%s)", myargv[i]); else { - if (numsourcefiles < MAXSOURCEFILESLIST) - strcpy(sourcefileslist[numsourcefiles++], myargv[i]); + if (!QCC_RegisterSourceFile(myargv[i])) + QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "too many source filename arguments"); } } @@ -4682,6 +4709,7 @@ static void QCC_SetDefaultProperties (void) qccwarningaction[WARN_EXTRAPRECACHE] = WA_IGNORE; qccwarningaction[WARN_DEADCODE] = WA_IGNORE; qccwarningaction[WARN_FTE_SPECIFIC] = WA_IGNORE; + qccwarningaction[WARN_DIVISIONBY0] = WA_IGNORE; qccwarningaction[WARN_MUTEDEPRECATEDVARIABLE] = WA_IGNORE; qccwarningaction[WARN_EXTENSION_USED] = WA_IGNORE; qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE; @@ -5137,23 +5165,15 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); QCC_PR_ClearGrabMacros (false); - qccmsrc = NULL; - if (!numsourcefiles) + qccmsrc = NULL; + if (destfile_explicit && numsourcefiles && !currentsourcefile) { //generate an internal .src file from the argument list int i; - for (i = 1;i