Make sizeof into an actual operator instead of a mere intrinsic

Char immediates now support a greater range of escapes for parity with string immediates.
Don't misparse triple field parameters as variable args+junk.
Recognise octal immediates, but warn in case it was unintended.
Fix a bug with initialised const locals.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5760 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-09-11 01:18:32 +00:00
parent ebc28bf3ef
commit b095410ce6
6 changed files with 532 additions and 318 deletions

View File

@ -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)
{

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 ; i<numfunctions ; i++)
{
if (functions[i].privatelocals)
// if (functions[i].privatelocals)
{
for (d = functions[i].firstlocal; d; d = d->nextlocal)
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<myargc;i++)
{
if (*myargv[i] == '-')
break;
if (!qccmsrc)
{
qccmsrc = qccHunkAlloc(8192);
(void)QC_strlcpy(qccmsrc, "progs.dat\n", 8192);
}
if (!QC_strlcat(qccmsrc, myargv[i], 8192) || !QC_strlcat(qccmsrc, "\n", 8192))
QCC_PR_ParseWarning (WARN_STRINGTOOLONG, "Too many files to compile");
}
qccmsrc = qccHunkAlloc(8192);
*qccmsrc = 0;
for (i = 0;i<numsourcefiles;i++)
QC_snprintfz(qccmsrc+strlen(qccmsrc), 8192-strlen(qccmsrc), "#include \"%s\"\n", sourcefileslist[i]);
currentsourcefile = i;
}
if (qccmsrc)
@ -5352,8 +5372,8 @@ void QCC_ContinueCompile(void)
if (parseonly)
{
qcc_compileactive = false;
sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL;
sourcefilesnumdefs = currentsourcefile+1;
if (sourcefilesnumdefs < countof(sourcefilesdefs) && qccpersisthunk)
sourcefilesdefs[currentsourcefile++] = pr.def_head.next;
}
else
{
@ -5491,8 +5511,8 @@ void QCC_FinishCompile(void)
// report / copy the data files
QCC_CopyFiles ();
sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL;
sourcefilesnumdefs = currentsourcefile+1;
if (sourcefilesnumdefs < countof(sourcefilesdefs) && qccpersisthunk)
sourcefilesdefs[sourcefilesnumdefs++] = pr.def_head.next;
if (donesomething)
{
@ -5651,8 +5671,8 @@ void new_QCC_ContinueCompile(void)
QCC_FinishCompile();
else
{
sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL;
sourcefilesnumdefs = currentsourcefile+1;
if (sourcefilesnumdefs < countof(sourcefilesdefs) && qccpersisthunk)
sourcefilesdefs[currentsourcefile++] = pr.def_head.next;
}
PostCompile();
if (!QCC_main(myargc, myargv))