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:
parent
ebc28bf3ef
commit
b095410ce6
6 changed files with 532 additions and 318 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue