Make class parsing more c++-like, fix some issues with uninitialised variables not getting detected properly.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6322 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
6700dfd289
commit
ed63b7435e
5 changed files with 557 additions and 349 deletions
|
@ -3253,6 +3253,7 @@ void DecompileProgsDat(char *name, void *buf, size_t bufsize)
|
|||
type_bint = type_integer;
|
||||
type_variant = QCC_PR_NewType("variant", ev_variant, true);
|
||||
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
|
||||
type_invalid = QCC_PR_NewType("invalid", ev_void, false);
|
||||
|
||||
DecompileReadData(name, buf, bufsize);
|
||||
DecompileDecompileFunctions(c);
|
||||
|
|
|
@ -508,7 +508,7 @@ extern int QCC_packid;
|
|||
extern const unsigned int type_size[];
|
||||
//extern QCC_def_t *def_for_type[9];
|
||||
|
||||
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_variant, *type_floatfield;
|
||||
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_invalid, *type_variant, *type_floatfield;
|
||||
extern char *basictypenames[];
|
||||
|
||||
struct QCC_function_s
|
||||
|
@ -819,7 +819,7 @@ enum {
|
|||
WARN_BADPRAGMA,
|
||||
WARN_NOTUTF8,
|
||||
WARN_HANGINGSLASHR,
|
||||
WARN_NOTDEFINED,
|
||||
WARN_MEMBERNOTDEFINED,
|
||||
WARN_NOTCONSTANT,
|
||||
WARN_SWITCHTYPEMISMATCH,
|
||||
WARN_CONFLICTINGUNIONMEMBER,
|
||||
|
@ -1095,7 +1095,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char
|
|||
void QCC_PR_EmitArraySetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char *arrayname);
|
||||
void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype);
|
||||
|
||||
void QCC_PR_ParseDefs (char *classname, pbool fatal);
|
||||
void QCC_PR_ParseDefs (const char *classname, pbool fatal);
|
||||
QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *scope, int arraysize, QCC_def_t *rootsymbol, unsigned int ofs, int referable, unsigned int flags);
|
||||
void QCC_PR_ParseInitializerDef(QCC_def_t *def, unsigned int flags);
|
||||
void QCC_PR_FinaliseFunctions(void);
|
||||
|
|
|
@ -10524,8 +10524,54 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
|
|||
return QCC_DefToRef(retbuf, QCC_MakeIntConst(sz));
|
||||
}
|
||||
}
|
||||
/*if (QCC_PR_CheckKeyword(keyword_new, "new"))
|
||||
{ //note: C++ requires struct-based classes rather than entity ones.
|
||||
const char *cname = QCC_PR_ParseName();
|
||||
QCC_type_t *rettype = QCC_TypeForName(cname);
|
||||
QCC_sref_t result, func;
|
||||
if (!rettype || rettype->type != ev_entity)
|
||||
QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "new %s() unsupported argument type for intrinsic", cname);
|
||||
e = QCC_PR_GetSRef(NULL, "spawn", NULL, 0, 0, 0);
|
||||
if (!e.cast)
|
||||
QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "new %s() spawn builtin not defined", cname);
|
||||
result = QCC_PR_GenerateFunctionCallRef(nullsref, e, NULL,0);
|
||||
result.cast = rettype;
|
||||
if (QCC_PR_CheckToken("("))
|
||||
{ //arglist is optional, apparently
|
||||
char genfunc[256];
|
||||
//do field assignments.
|
||||
while(QCC_PR_CheckToken(","))
|
||||
{
|
||||
QCC_sref_t f, p, v;
|
||||
f = QCC_PR_ParseValue(rettype, false, false, true);
|
||||
if (f.cast->type != ev_field)
|
||||
QCC_PR_ParseError(0, "Named field is not a field.");
|
||||
if (QCC_PR_CheckToken("=")) //allow : or = as a separator, but throw a warning for =
|
||||
QCC_PR_ParseWarning(0, "That = should be a :"); //rejecting = helps avoid qcc bugs. :P
|
||||
else
|
||||
QCC_PR_Expect(":");
|
||||
v = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
|
||||
|
||||
p = QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], result, f, NULL, STFL_PRESERVEA);
|
||||
if (v.cast->size == 3)
|
||||
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_V], v, p, NULL));
|
||||
else
|
||||
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_F], v, p, NULL));
|
||||
}
|
||||
QCC_PR_Expect(")");
|
||||
|
||||
QC_snprintfz(genfunc, sizeof(genfunc), "spawnfunc_%s", rettype->name);
|
||||
func = QCC_PR_GetSRef(type_function, genfunc, NULL, true, 0, GDF_CONST);
|
||||
func.sym->referenced = true;
|
||||
|
||||
QCC_UnFreeTemp(result);
|
||||
QCC_FreeTemp(QCC_PR_GenerateFunctionCallRef(result, func, NULL, 0));
|
||||
result.cast = rettype;
|
||||
}
|
||||
return QCC_DefToRef(retbuf, result);
|
||||
}*/
|
||||
if (QCC_PR_CheckKeyword(true, "_length"))
|
||||
{ //for compat with gmqcc
|
||||
{ //for compat with gmqcc. use array.length in fte instead.
|
||||
pbool bracket = QCC_PR_CheckToken("(");
|
||||
/*QCC_type_t *t;
|
||||
t = QCC_PR_ParseType(false, true);
|
||||
|
@ -15047,8 +15093,27 @@ void QCC_CommonSubExpressionRemoval(int first, int last)
|
|||
//follow branches (by recursing).
|
||||
//stop on first read(error, return statement) or write(no error, return -1)
|
||||
//end-of-block returns 0, done/return/goto returns -2
|
||||
static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_def_t *def, unsigned int min, unsigned int max)
|
||||
static int QCC_CheckOneUninitialised(int firststatement, int laststatement, union QCC_eval_basic_s *min, union QCC_eval_basic_s *max)
|
||||
{
|
||||
#define SPLIT \
|
||||
if (!(ofs > max || ofs+sz <= min)) \
|
||||
{ \
|
||||
if (min < ofs) \
|
||||
{ /*keep checking before*/ \
|
||||
ret = QCC_CheckOneUninitialised(i + 1, laststatement, min, ofs); \
|
||||
if (ret > 0) \
|
||||
return ret; \
|
||||
} \
|
||||
if (ofs+sz < max) \
|
||||
{ /*keep checking after*/ \
|
||||
ret = QCC_CheckOneUninitialised(i + 1, laststatement, ofs+sz, max); \
|
||||
if (ret > 0) \
|
||||
return ret; \
|
||||
} \
|
||||
if (iswrite) \
|
||||
return -1; /*okay, we wrote it all*/ \
|
||||
return i; /*an error when its a read*/ \
|
||||
}
|
||||
int ret;
|
||||
int i;
|
||||
QCC_statement_t *st;
|
||||
|
@ -15059,46 +15124,44 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
|
|||
|
||||
if (st->op == OP_DONE || st->op == OP_RETURN)
|
||||
{
|
||||
if (st->a.sym && st->a.sym->symbolheader == def && st->a.ofs >= min && st->a.ofs < max)
|
||||
return i;
|
||||
if (st->a.cast && st->a.sym)
|
||||
{
|
||||
union QCC_eval_basic_s *ofs = st->a.sym->symboldata+st->a.ofs;
|
||||
int sz = st->a.cast->size;
|
||||
if (!(ofs > max || ofs+sz < min))
|
||||
return i;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (st->op == OP_GLOBALADDRESS && st->a.sym && (st->a.sym->symbolheader == def || (st->a.sym->symbolheader == def)))
|
||||
return -1; //assume taking a pointer to it is an initialisation.
|
||||
|
||||
// this code catches gotos, but can cause issues with while statements.
|
||||
// if (st->op == OP_GOTO && (int)st->a < 1)
|
||||
// return -2;
|
||||
|
||||
if (pr_opcodes[st->op].type_a)
|
||||
if (pr_opcodes[st->op].type_a && st->a.sym)
|
||||
{
|
||||
if (st->a.sym && st->a.sym->symbolheader == def && st->a.ofs >= min && st->a.ofs < max)
|
||||
{
|
||||
if (OpAssignsToA(st->op))
|
||||
return -1;
|
||||
union QCC_eval_basic_s *ofs = st->a.sym->symboldata+st->a.ofs;
|
||||
int sz = st->a.cast->size;
|
||||
pbool iswrite = OpAssignsToA(st->op) || st->op == OP_GLOBALADDRESS; /* address-of counts as a write here, because we're too dumb to track when/if that is assigned to.*/
|
||||
|
||||
return i;
|
||||
}
|
||||
SPLIT
|
||||
}
|
||||
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0 && !st->a.sym)
|
||||
{
|
||||
int jump = i + (int)st->a.ofs;
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
i = jump-1;
|
||||
}
|
||||
|
||||
if (pr_opcodes[st->op].type_b)
|
||||
if (pr_opcodes[st->op].type_b && st->b.sym)
|
||||
{
|
||||
if (st->b.sym && st->b.sym->symbolheader == def && st->b.ofs >= min && st->b.ofs < max)
|
||||
{
|
||||
if (OpAssignsToB(st->op))
|
||||
return -1;
|
||||
union QCC_eval_basic_s *ofs = st->b.sym->symboldata+st->b.ofs;
|
||||
int sz = st->b.cast->size;
|
||||
pbool iswrite = OpAssignsToB(st->op);
|
||||
|
||||
return i;
|
||||
}
|
||||
SPLIT
|
||||
}
|
||||
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !st->b.sym && !(st->flags & STF_LOGICOP))
|
||||
{
|
||||
|
@ -15108,10 +15171,10 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
|
|||
if (st->op == OP_GOTO && (int)st->a.ofs > 0)
|
||||
{
|
||||
int jump2 = jump-1 + st->a.ofs;
|
||||
int rett = QCC_CheckOneUninitialised(i + 1, jump - 1, def, min, max);
|
||||
int rett = QCC_CheckOneUninitialised(i + 1, jump - 1, min, max);
|
||||
if (rett > 0)
|
||||
return rett;
|
||||
ret = QCC_CheckOneUninitialised(jump, jump2, def, min, max);
|
||||
ret = QCC_CheckOneUninitialised(jump, jump2, min, max);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
if (rett < 0 && ret < 0)
|
||||
|
@ -15120,7 +15183,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
|
|||
}
|
||||
else
|
||||
{
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
i = jump-1;
|
||||
|
@ -15128,17 +15191,18 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
|
|||
continue;
|
||||
}
|
||||
|
||||
if (pr_opcodes[st->op].type_c && st->c.sym && st->c.sym->symbolheader == def && st->c.ofs >= min && st->c.ofs < max)
|
||||
if (pr_opcodes[st->op].type_c && st->c.sym)
|
||||
{
|
||||
if (OpAssignsToC(st->op))
|
||||
return -1;
|
||||
union QCC_eval_basic_s *ofs = st->c.sym->symboldata+st->c.ofs;
|
||||
int sz = st->c.cast->size;
|
||||
pbool iswrite = OpAssignsToC(st->op);
|
||||
|
||||
return i;
|
||||
SPLIT
|
||||
}
|
||||
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0 && !st->c.sym)
|
||||
{
|
||||
int jump = i + (int)st->c.ofs;
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
|
||||
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
i = jump-1;
|
||||
|
@ -15148,11 +15212,12 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
|
|||
}
|
||||
|
||||
return 0;
|
||||
#undef SPLIT
|
||||
}
|
||||
|
||||
static pbool QCC_CheckUninitialised(int firststatement, int laststatement)
|
||||
{
|
||||
QCC_def_t *local;
|
||||
QCC_def_t *local, *c, *uninit;
|
||||
unsigned int i;
|
||||
pbool result = false;
|
||||
unsigned int paramend = FIRST_LOCAL;
|
||||
|
@ -15180,11 +15245,33 @@ static pbool QCC_CheckUninitialised(int firststatement, int laststatement)
|
|||
continue;
|
||||
if (local->arraysize)
|
||||
continue; //probably indexed. we won't detect things properly. its the user's resposibility to check. :(
|
||||
err = QCC_CheckOneUninitialised(firststatement, laststatement, local, local->ofs, local->ofs + local->type->size * (local->arraysize?local->arraysize:1));
|
||||
err = QCC_CheckOneUninitialised(firststatement, laststatement, local->symboldata, local->symboldata + local->type->size * (local->arraysize?local->arraysize:1));
|
||||
if (err > 0)
|
||||
{
|
||||
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s%s%s", col_symbol,local->name,col_none);
|
||||
{ //try to refine it to a single component if we can.
|
||||
uninit = NULL;
|
||||
for (c = local; ; c = c->next)
|
||||
{
|
||||
if (c != local)
|
||||
{
|
||||
err = QCC_CheckOneUninitialised(firststatement, laststatement, c->symboldata, c->symboldata + c->type->size * (c->arraysize?c->arraysize:1));
|
||||
if (err > 0)
|
||||
{
|
||||
if (uninit)
|
||||
{
|
||||
uninit = NULL;
|
||||
break;
|
||||
}
|
||||
uninit = c;
|
||||
}
|
||||
}
|
||||
if (c == local->deftail)
|
||||
break; //that was the last of them.
|
||||
}
|
||||
if (!uninit) //otherwise give up and print the whole struct.
|
||||
uninit = local;
|
||||
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s%s%s", col_symbol,uninit->name,col_none);
|
||||
result = true;
|
||||
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
@ -17989,7 +18076,7 @@ PR_ParseDefs
|
|||
Called at the outer layer and when a local statement is hit
|
||||
================
|
||||
*/
|
||||
void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
|
||||
void QCC_PR_ParseDefs (const char *classname, pbool fatal_unused)
|
||||
{
|
||||
char *name;
|
||||
QCC_type_t *basetype, *type, *defclass;
|
||||
|
@ -18416,17 +18503,29 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
|
|||
// QCC_PR_ParseError (WARN_TYPEWITHNONAME, "type (%s) with no name", type->name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (!istypedef && !classname && type->typedefed && QCC_PR_CheckToken("::"))
|
||||
{
|
||||
while (QCC_PR_CheckToken ("*"))
|
||||
type = QCC_PointerTypeTo(type);
|
||||
name = QCC_PR_ParseName ();
|
||||
classname = type->name; //FIXME: doesn't work with commas...
|
||||
type = type_invalid;
|
||||
}
|
||||
else while (QCC_PR_CheckToken ("*"))
|
||||
type = QCC_PointerTypeTo(type);
|
||||
name = QCC_PR_ParseName ();
|
||||
|
||||
if (!istypedef && !classname && QCC_PR_CheckToken("::"))
|
||||
{
|
||||
classname = name; //FIXME: doesn't work with commas...
|
||||
name = QCC_PR_ParseName();
|
||||
}
|
||||
|
||||
if (!istypedef && QCC_PR_CheckToken("::") && !classname)
|
||||
if (type == type_invalid)
|
||||
{
|
||||
classname = name;
|
||||
name = QCC_PR_ParseName();
|
||||
type = type_void;
|
||||
if (!strcmp(classname, name))
|
||||
; //constructor. allowed.
|
||||
else
|
||||
QCC_PR_ParseWarning(ERR_NOTATYPE, "no type specified for %s::%s. this is only allowed for constructors", classname, name);
|
||||
}
|
||||
|
||||
//check for an array
|
||||
|
@ -18527,6 +18626,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
|
|||
name = qccHunkAlloc(strlen(classname) + strlen(name) + 3);
|
||||
sprintf(name, "%s::%s", classname, membername);
|
||||
defclass = QCC_TypeForName(classname);
|
||||
allocatenew = (dynlength.cast || aliasof)?false:2;
|
||||
if (defclass && defclass->type == ev_struct)
|
||||
allocatenew = false;
|
||||
else if (!defclass || !defclass->parentclass)
|
||||
|
@ -18630,6 +18730,15 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
|
|||
def->referenced = true;
|
||||
def = QCC_PR_DummyDef(type, name, pr_scope, arraysize, def, 0, true, gd_flags);
|
||||
}
|
||||
else if (allocatenew != 1)
|
||||
{ //we always allocate here, because it lets us handle syntax errors a little more gracefully, but an error is still an error and will be fatal later.
|
||||
def = QCC_PR_GetDef (type, name, pr_scope, false, arraysize, gd_flags);
|
||||
if (!def)
|
||||
{
|
||||
QCC_PR_ParseWarning(allocatenew?WARN_MEMBERNOTDEFINED:ERR_NOTDEFINED, "%s is not part of class %s", name, classname);
|
||||
def = QCC_PR_GetDef (type, name, pr_scope, true, arraysize, gd_flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
def = QCC_PR_GetDef (type, name, pr_scope, allocatenew, arraysize, gd_flags);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ QCC_type_t *type_uint; //uint32
|
|||
QCC_type_t *type_int64; //int64
|
||||
QCC_type_t *type_uint64; //uint64
|
||||
QCC_type_t *type_variant; //__variant
|
||||
QCC_type_t *type_invalid; //technically void, but shouldn't really ever be used.
|
||||
QCC_type_t *type_floatpointer; //float *
|
||||
QCC_type_t *type_intpointer; //int *
|
||||
QCC_type_t *type_bint; //int (0 or 1)
|
||||
|
@ -3047,6 +3048,7 @@ void QCC_PR_PreProcessor_Define(pbool append)
|
|||
s++; //skip the \ char
|
||||
if (*s == '\r' && s[1] == '\n')
|
||||
s++; //skip the \r. the \n will become part of the macro.
|
||||
s++; //skip the \n
|
||||
QCC_PR_NewLine(true);
|
||||
|
||||
/*
|
||||
|
@ -3524,7 +3526,7 @@ static pbool QCC_PR_ExpandPreProcessorMacro(CompilerConstant_t *c, char **buffer
|
|||
QCC_PR_ExpandStrCat(buffer,bufferlen,buffermax, "#", 1);
|
||||
QCC_PR_ExpandStrCat(buffer,bufferlen,buffermax, qcc_token, strlen(qcc_token));
|
||||
if (!c->evil)
|
||||
QCC_PR_ParseWarning(0, "'#' is not followed by a macro parameter in %s", c->name);
|
||||
QCC_PR_ParseWarning(0, "'#%s' is not a macro parameter in %s", qcc_token, c->name);
|
||||
}
|
||||
continue; //already did this one
|
||||
}
|
||||
|
@ -5643,7 +5645,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
return newt;
|
||||
}
|
||||
|
||||
if (QCC_PR_CheckKeyword (keyword_class, "class"))
|
||||
if (flag_qcfuncs && QCC_PR_CheckKeyword (keyword_class, "class"))
|
||||
{
|
||||
// int parms;
|
||||
QCC_type_t *fieldtype;
|
||||
|
@ -5658,6 +5660,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
int basicindex;
|
||||
QCC_def_t *d;
|
||||
QCC_type_t *pc;
|
||||
QCC_type_t *basetype;
|
||||
pbool found = false;
|
||||
int assumevirtual = 0; //0=erk, 1=yes, -1=no
|
||||
|
||||
|
@ -5718,11 +5721,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
{
|
||||
unsigned int gdf_flags;
|
||||
|
||||
pbool havebody = false;
|
||||
pbool isnull = false;
|
||||
pbool isvirt = false;
|
||||
pbool isnonvirt = false;
|
||||
pbool isstatic = false;
|
||||
pbool wasvirt = false;
|
||||
pbool wasnonvirt = false;
|
||||
pbool wasstatic = false;
|
||||
pbool isconst = false;
|
||||
pbool isvar = false;
|
||||
pbool isignored = false;
|
||||
|
@ -5732,18 +5733,34 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
// pbool ispublic = false;
|
||||
// pbool isprivate = false;
|
||||
// pbool isprotected = false;
|
||||
pbool firstkeyword = true;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (QCC_PR_CheckKeyword(1, "nonvirtual"))
|
||||
isnonvirt = true;
|
||||
{
|
||||
if (firstkeyword && QCC_PR_CheckToken(":"))
|
||||
{ //fteqcc-specific
|
||||
assumevirtual = -1;
|
||||
continue;
|
||||
}
|
||||
wasnonvirt = true;
|
||||
}
|
||||
else if (QCC_PR_CheckKeyword(1, "static"))
|
||||
isstatic = true;
|
||||
wasstatic = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "const"))
|
||||
isconst = isstatic = true;
|
||||
isconst = wasstatic = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "var"))
|
||||
isvar = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "virtual"))
|
||||
isvirt = true;
|
||||
{
|
||||
if (firstkeyword && QCC_PR_CheckToken(":"))
|
||||
{ //fteqcc-specific
|
||||
assumevirtual = 1;
|
||||
continue;
|
||||
}
|
||||
wasvirt = true;
|
||||
}
|
||||
else if (QCC_PR_CheckKeyword(1, "ignore"))
|
||||
isignored = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "strip"))
|
||||
|
@ -5754,339 +5771,384 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
isget = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "set"))
|
||||
isset = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "public"))
|
||||
/*ispublic = true*/;
|
||||
else if (QCC_PR_CheckKeyword(1, "private"))
|
||||
/*isprivate = true*/;
|
||||
else if (QCC_PR_CheckKeyword(1, "protected"))
|
||||
/*isprotected = true*/;
|
||||
else if (firstkeyword && QCC_PR_CheckKeyword(1, "public"))
|
||||
{
|
||||
/*ispublic = true;*/
|
||||
QCC_PR_Expect(":");
|
||||
continue;
|
||||
}
|
||||
else if (firstkeyword && QCC_PR_CheckKeyword(1, "private"))
|
||||
{
|
||||
QCC_PR_Expect(":");
|
||||
/*isprivate = true; */
|
||||
continue;
|
||||
}
|
||||
else if (firstkeyword && QCC_PR_CheckKeyword(1, "protected"))
|
||||
{
|
||||
QCC_PR_Expect(":");
|
||||
/*isprotected = true;*/ QCC_PR_Expect(":");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (QCC_PR_CheckToken(":"))
|
||||
{
|
||||
if (isvirt && !isnonvirt)
|
||||
assumevirtual = 1;
|
||||
else if (isnonvirt && !isvirt)
|
||||
assumevirtual = -1;
|
||||
continue;
|
||||
firstkeyword = false;
|
||||
}
|
||||
if (isget || isset)
|
||||
{
|
||||
if (isvirt)
|
||||
if (wasvirt)
|
||||
QCC_PR_ParseWarning(ERR_INTERNAL, "virtual accessors are not supported at this time");
|
||||
if (isstatic)
|
||||
if (wasstatic)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "static accessors are not supported");
|
||||
QCC_PR_ParseAccessorMember(newt, isinline, isset);
|
||||
QCC_PR_CheckToken(";");
|
||||
continue;
|
||||
}
|
||||
|
||||
newparm = QCC_PR_ParseType(false, false);
|
||||
basetype = QCC_PR_ParseType(false, false);
|
||||
|
||||
if (!newparm)
|
||||
if (!basetype)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "In class %s, expected type, found %s", classname, pr_token);
|
||||
|
||||
if (newparm->type == ev_struct || newparm->type == ev_union) //we wouldn't be able to handle it.
|
||||
if (basetype->type == ev_struct || basetype->type == ev_union) //we wouldn't be able to handle it.
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
|
||||
|
||||
parmname = QCC_PR_ParseName();
|
||||
if (QCC_PR_CheckToken("["))
|
||||
{
|
||||
arraysize = QCC_PR_IntConstExpr();
|
||||
QCC_PR_Expect("]");
|
||||
}
|
||||
else
|
||||
arraysize = 0;
|
||||
|
||||
if (newparm->type == ev_function)
|
||||
for (;basetype;)
|
||||
{
|
||||
if (isstatic)
|
||||
{
|
||||
isstatic = false;
|
||||
isnonvirt = true;
|
||||
// QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static member functions are not supported at this time.", classname, parmname);
|
||||
pbool havebody = false;
|
||||
pbool isnull = false;
|
||||
pbool isstatic = wasstatic;
|
||||
pbool isvirt = wasvirt;
|
||||
pbool isnonvirt = wasnonvirt;
|
||||
|
||||
if (flag_qcfuncs && basetype->type == ev_function && basetype->aux_type == newt && QCC_PR_PeekToken(";"))
|
||||
{ //C++ style constructor (ie: missing return type followed by class name)
|
||||
//swap the class out for the appropriate function type...
|
||||
newparm = QCC_PR_GenFunctionType(type_void, basetype->params, basetype->num_parms);
|
||||
parmname = classname;
|
||||
}
|
||||
|
||||
if (!strcmp(classname, parmname))
|
||||
else if (!flag_qcfuncs && basetype == newt && QCC_PR_CheckToken("("))
|
||||
{
|
||||
if (isstatic)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "Constructor %s::%s may not be static.", classname, pr_token);
|
||||
if (!isvirt)
|
||||
isnonvirt = true;//silently promote constructors to static
|
||||
}
|
||||
else if (!isvirt && !isnonvirt && !isstatic)
|
||||
{
|
||||
if (assumevirtual == 1)
|
||||
isvirt = true;
|
||||
else if (assumevirtual == -1)
|
||||
isnonvirt = true;
|
||||
else
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "%s::%s was not qualified. Assuming non-virtual.", classname, parmname);
|
||||
isnonvirt = true;
|
||||
}
|
||||
}
|
||||
if (isvirt+isnonvirt+isstatic != 1)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "Multiple conflicting qualifiers on %s::%s.", classname, pr_token);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isvirt||isnonvirt)
|
||||
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
|
||||
if (isinline)
|
||||
QCC_Error(ERR_INTERNAL, "inline keyword on member that is not a function");
|
||||
}
|
||||
|
||||
if (QCC_PR_CheckToken("="))
|
||||
havebody = true;
|
||||
else if (newparm->type == ev_function && pr_token[0] == '{')
|
||||
havebody = true;
|
||||
if (isinline && (!havebody || isvirt))
|
||||
QCC_Error(ERR_INTERNAL, "inline keyword on function prototype or virtual function");
|
||||
|
||||
gdf_flags = 0;
|
||||
if ((newparm->type == ev_function && !arraysize && !isvar) || isconst)
|
||||
gdf_flags = GDF_CONST;
|
||||
|
||||
if (havebody)
|
||||
{
|
||||
QCC_def_t *def;
|
||||
if (pr_scope)
|
||||
QCC_Error(ERR_INTERNAL, "Nested function declaration");
|
||||
|
||||
isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i"));
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
|
||||
if (isnull)
|
||||
{
|
||||
if (isignored)
|
||||
def = NULL;
|
||||
else
|
||||
{
|
||||
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
|
||||
def->symboldata[def->ofs].function = 0;
|
||||
def->initialized = 1;
|
||||
}
|
||||
newparm = QCC_PR_ParseFunctionType(false, type_void);
|
||||
parmname = classname;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isignored)
|
||||
def = NULL;
|
||||
else
|
||||
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
|
||||
|
||||
if (newparm->type != ev_function && !isstatic)
|
||||
QCC_Error(ERR_INTERNAL, "Can only initialise member functions");
|
||||
else
|
||||
parmname = QCC_PR_ParseName();
|
||||
if (QCC_PR_CheckToken("["))
|
||||
{
|
||||
if (autoprototype || isignored)
|
||||
{
|
||||
if (QCC_PR_CheckToken("["))
|
||||
{
|
||||
while (!QCC_PR_CheckToken("]"))
|
||||
{
|
||||
if (pr_token_type == tt_eof)
|
||||
break;
|
||||
QCC_PR_Lex();
|
||||
}
|
||||
}
|
||||
QCC_PR_Expect("{");
|
||||
arraysize = QCC_PR_IntConstExpr();
|
||||
QCC_PR_Expect("]");
|
||||
}
|
||||
else
|
||||
arraysize = 0;
|
||||
|
||||
{
|
||||
int blev = 1;
|
||||
//balance out the { and }
|
||||
while(blev)
|
||||
{
|
||||
if (pr_token_type == tt_eof)
|
||||
break;
|
||||
if (QCC_PR_CheckToken("{"))
|
||||
blev++;
|
||||
else if (QCC_PR_CheckToken("}"))
|
||||
blev--;
|
||||
else
|
||||
QCC_PR_Lex(); //ignore it.
|
||||
}
|
||||
}
|
||||
}
|
||||
if (QCC_PR_CheckToken("("))
|
||||
{
|
||||
//int fnc(), fld; is valid.
|
||||
newparm = QCC_PR_ParseFunctionType(false, basetype);
|
||||
}
|
||||
else
|
||||
newparm = basetype;
|
||||
}
|
||||
|
||||
if (newparm->type == ev_function)
|
||||
{
|
||||
if (!strcmp(classname, parmname))
|
||||
{
|
||||
if (isstatic)
|
||||
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor %s::%s should not be static.", classname, pr_token);
|
||||
if (!isvirt)
|
||||
isnonvirt = true;//silently promote constructors to static
|
||||
if (newparm->aux_type->type != ev_void)
|
||||
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor %s::%s does not return void.", classname, pr_token);
|
||||
if (newparm->num_parms != 0 || newparm->vargs)
|
||||
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor arguments are not supported at this time %s::%s. Use named fields instead.", classname, pr_token);
|
||||
}
|
||||
else if (!isvirt && !isnonvirt && !isstatic)
|
||||
{
|
||||
if (assumevirtual == 1)
|
||||
isvirt = true;
|
||||
else if (assumevirtual == -1)
|
||||
isnonvirt = true;
|
||||
else
|
||||
{
|
||||
pr_classtype = newt;
|
||||
QCC_PR_ParseInitializerDef(def, 0);
|
||||
pr_classtype = NULL;
|
||||
/*
|
||||
f = QCC_PR_ParseImmediateStatements (def, newparm);
|
||||
pr_classtype = NULL;
|
||||
pr_scope = NULL;
|
||||
def->symboldata[def->ofs].function = f - functions;
|
||||
f->def = def;
|
||||
def->initialized = 1;*/
|
||||
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "%s::%s was not qualified. Assuming non-virtual.", classname, parmname);
|
||||
isnonvirt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (def)
|
||||
QCC_FreeDef(def);
|
||||
else if (isvirt+isnonvirt+isstatic != 1)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "Multiple conflicting qualifiers on %s::%s.", classname, pr_token);
|
||||
|
||||
if (!isvirt && !isignored)
|
||||
{
|
||||
QCC_def_t *fdef;
|
||||
QCC_type_t *pc;
|
||||
unsigned int i;
|
||||
|
||||
for (pc = newt->parentclass; pc; pc = pc->parentclass)
|
||||
{
|
||||
for (i = 0; i < pc->num_parms; i++)
|
||||
{
|
||||
if (!strcmp(pc->params[i].paramname, parmname))
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class '%s'. Did you forget the 'virtual' keyword?", newt->name, parmname, pc->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < pc->num_parms)
|
||||
break;
|
||||
if (isstatic)
|
||||
{ //static and non-virtual functions differ only in that static should not have a 'this' available. however there's no hiding 'self' for calling in to other functions.
|
||||
isstatic = false;
|
||||
isnonvirt = true;
|
||||
// QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static member functions are not supported at this time.", classname, parmname);
|
||||
}
|
||||
if (!pc)
|
||||
{
|
||||
fdef = QCC_PR_GetDef(NULL, parmname, NULL, false, 0, GDF_CONST);
|
||||
if (fdef && fdef->type->type == ev_field)
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class 'entity'. Did you forget the 'virtual' keyword?", newt->name, parmname);
|
||||
QCC_PR_ParsePrintDef(0, fdef);
|
||||
}
|
||||
else if (fdef)
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s shadows a global", newt->name, parmname);
|
||||
QCC_PR_ParsePrintDef(0, fdef);
|
||||
}
|
||||
if (fdef)
|
||||
QCC_FreeDef(fdef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QCC_PR_Expect(";");
|
||||
|
||||
if (isignored) //member doesn't really exist
|
||||
continue;
|
||||
|
||||
//static members are technically just funny-named globals, and do not generate fields.
|
||||
if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize))
|
||||
{
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
|
||||
QCC_FreeDef(QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags));
|
||||
|
||||
if (isnonvirt || isstatic)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
fieldtype = QCC_PR_NewType(parmname, ev_field, false);
|
||||
fieldtype->aux_type = newparm;
|
||||
fieldtype->size = newparm->size;
|
||||
|
||||
parms = realloc(parms, sizeof(*parms) * (numparms+1));
|
||||
parms[numparms].ofs = 0;
|
||||
parms[numparms].out = false;
|
||||
parms[numparms].optional = false;
|
||||
parms[numparms].isvirtual = isvirt;
|
||||
parms[numparms].paramname = parmname;
|
||||
parms[numparms].arraysize = arraysize;
|
||||
parms[numparms].type = newparm;
|
||||
parms[numparms].defltvalue.cast = NULL;
|
||||
|
||||
basicindex = 0;
|
||||
found = false;
|
||||
for(pc = newt; pc && !found; pc = pc->parentclass)
|
||||
{
|
||||
struct QCC_typeparam_s *pp;
|
||||
int numpc;
|
||||
int i;
|
||||
if (pc == newt)
|
||||
{
|
||||
pp = parms;
|
||||
numpc = numparms;
|
||||
}
|
||||
else
|
||||
{
|
||||
pp = pc->params;
|
||||
numpc = pc->num_parms;
|
||||
if (isvirt||isnonvirt)
|
||||
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
|
||||
if (isinline)
|
||||
QCC_Error(ERR_INTERNAL, "inline keyword on member that is not a function");
|
||||
}
|
||||
for (i = 0; i < numpc; i++)
|
||||
|
||||
if (QCC_PR_CheckToken("="))
|
||||
havebody = true;
|
||||
else if (newparm->type == ev_function && QCC_PR_PeekToken("{"))
|
||||
havebody = true;
|
||||
if (isinline && (!havebody || isvirt))
|
||||
QCC_Error(ERR_INTERNAL, "inline keyword on function prototype or virtual function");
|
||||
|
||||
gdf_flags = 0;
|
||||
if ((newparm->type == ev_function && !arraysize && !isvar) || isconst)
|
||||
gdf_flags = GDF_CONST;
|
||||
|
||||
if (havebody)
|
||||
{
|
||||
if (pp[i].type->type == newparm->type)
|
||||
QCC_def_t *def;
|
||||
if (pr_scope)
|
||||
QCC_Error(ERR_INTERNAL, "Nested function declaration");
|
||||
|
||||
isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i"));
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
|
||||
if (isnull)
|
||||
{
|
||||
if (!strcmp(pp[i].paramname, parmname))
|
||||
if (isignored)
|
||||
def = NULL;
|
||||
else
|
||||
{
|
||||
if (typecmp(pp[i].type, newparm))
|
||||
{
|
||||
char bufc[256];
|
||||
char bufp[256];
|
||||
TypeName(pp[i].type, bufp, sizeof(bufp));
|
||||
TypeName(newparm, bufc, sizeof(bufc));
|
||||
QCC_PR_ParseError(0, "%s defined as %s in %s, but %s in %s\n", parmname, bufc, newt->name, bufp, pc->name);
|
||||
}
|
||||
basicindex = pp[i].ofs;
|
||||
found = true;
|
||||
break;
|
||||
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
|
||||
def->symboldata[def->ofs].function = 0;
|
||||
def->initialized = 1;
|
||||
}
|
||||
if ((unsigned int)basicindex < pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1)) //if we found one with the index
|
||||
basicindex = pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1); //make sure we don't union it.
|
||||
}
|
||||
}
|
||||
}
|
||||
parms[numparms].ofs = basicindex; //ulp, its new
|
||||
numparms++;
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
if (!*basictypes[newparm->type])
|
||||
QCC_PR_ParseError(0, "members of type %s are not supported (%s::%s)\n", basictypenames[newparm->type], classname, parmname);
|
||||
|
||||
//make sure the union is okay
|
||||
d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST);
|
||||
if (d)
|
||||
basicindex = 0;
|
||||
else
|
||||
{ //don't go all weird with unioning generic fields
|
||||
QC_snprintfz(membername, sizeof(membername), "::*%s", basictypenames[newparm->type]);
|
||||
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
|
||||
if (!d)
|
||||
{
|
||||
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT|GDF_USED);
|
||||
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
|
||||
// d->symboldata[i]._int = pr.size_fields+i;
|
||||
// pr.size_fields += i;
|
||||
|
||||
d->used = true;
|
||||
d->referenced = true; //always referenced, so you can inherit safely.
|
||||
}
|
||||
if (d->arraysize < basicindex+(arraysize?arraysize:1))
|
||||
{
|
||||
if (d->symboldata)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
|
||||
else
|
||||
{
|
||||
int newsize = basicindex+(arraysize?arraysize:1);
|
||||
if (d->type->type == ev_union || d->type->type == ev_struct)
|
||||
d->arraysize = newsize;
|
||||
else while(d->arraysize < newsize)
|
||||
if (isignored)
|
||||
def = NULL;
|
||||
else
|
||||
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
|
||||
|
||||
if (newparm->type != ev_function && !isstatic)
|
||||
QCC_Error(ERR_INTERNAL, "Can only initialise member functions");
|
||||
else
|
||||
{
|
||||
QC_snprintfz(membername, sizeof(membername), "::%s[%i]", basictypenames[newparm->type], d->arraysize/d->type->size);
|
||||
QCC_PR_DummyDef(d->type, membername, d->scope, 0, d, d->arraysize, true, GDF_CONST);
|
||||
d->arraysize+=d->type->size;
|
||||
if (autoprototype || isignored)
|
||||
{
|
||||
if (QCC_PR_CheckToken("["))
|
||||
{
|
||||
while (!QCC_PR_CheckToken("]"))
|
||||
{
|
||||
if (pr_token_type == tt_eof)
|
||||
break;
|
||||
QCC_PR_Lex();
|
||||
}
|
||||
}
|
||||
QCC_PR_Expect("{");
|
||||
|
||||
{
|
||||
int blev = 1;
|
||||
//balance out the { and }
|
||||
while(blev)
|
||||
{
|
||||
if (pr_token_type == tt_eof)
|
||||
break;
|
||||
if (QCC_PR_CheckToken("{"))
|
||||
blev++;
|
||||
else if (QCC_PR_CheckToken("}"))
|
||||
blev--;
|
||||
else
|
||||
QCC_PR_Lex(); //ignore it.
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pr_classtype = newt;
|
||||
QCC_PR_ParseInitializerDef(def, 0);
|
||||
pr_classtype = NULL;
|
||||
/*
|
||||
f = QCC_PR_ParseImmediateStatements (def, newparm);
|
||||
pr_classtype = NULL;
|
||||
pr_scope = NULL;
|
||||
def->symboldata[def->ofs].function = f - functions;
|
||||
f->def = def;
|
||||
def->initialized = 1;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if (def)
|
||||
QCC_FreeDef(def);
|
||||
|
||||
if (!isvirt && !isignored)
|
||||
{
|
||||
QCC_def_t *fdef;
|
||||
QCC_type_t *pc;
|
||||
unsigned int i;
|
||||
|
||||
for (pc = newt->parentclass; pc; pc = pc->parentclass)
|
||||
{
|
||||
for (i = 0; i < pc->num_parms; i++)
|
||||
{
|
||||
if (!strcmp(pc->params[i].paramname, parmname))
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class '%s'. Did you forget the 'virtual' keyword?", newt->name, parmname, pc->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < pc->num_parms)
|
||||
break;
|
||||
}
|
||||
if (!pc)
|
||||
{
|
||||
fdef = QCC_PR_GetDef(NULL, parmname, NULL, false, 0, GDF_CONST);
|
||||
if (fdef && fdef->type->type == ev_field)
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class 'entity'. Did you forget the 'virtual' keyword?", newt->name, parmname);
|
||||
QCC_PR_ParsePrintDef(0, fdef);
|
||||
}
|
||||
else if (fdef)
|
||||
{
|
||||
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s shadows a global", newt->name, parmname);
|
||||
QCC_PR_ParsePrintDef(0, fdef);
|
||||
}
|
||||
if (fdef)
|
||||
QCC_FreeDef(fdef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QCC_FreeDef(d);
|
||||
|
||||
//and make sure we can do member::__fname
|
||||
//actually, that seems pointless.
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
|
||||
// externs->Printf("define %s -> %s\n", membername, d->name);
|
||||
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, basicindex, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
|
||||
d->referenced = true; //always referenced, so you can inherit safely.
|
||||
if (!QCC_PR_CheckToken(","))
|
||||
{
|
||||
QCC_PR_Expect(";");
|
||||
basetype = NULL;
|
||||
}
|
||||
|
||||
if (isignored) //member doesn't really exist
|
||||
continue;
|
||||
|
||||
//static members are technically just funny-named globals, and do not generate fields.
|
||||
if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize))
|
||||
{
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
|
||||
QCC_FreeDef(QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags));
|
||||
|
||||
if (isnonvirt || isstatic)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
fieldtype = QCC_PR_NewType(parmname, ev_field, false);
|
||||
fieldtype->aux_type = newparm;
|
||||
fieldtype->size = newparm->size;
|
||||
|
||||
parms = realloc(parms, sizeof(*parms) * (numparms+1));
|
||||
parms[numparms].ofs = 0;
|
||||
parms[numparms].out = false;
|
||||
parms[numparms].optional = false;
|
||||
parms[numparms].isvirtual = isvirt;
|
||||
parms[numparms].paramname = parmname;
|
||||
parms[numparms].arraysize = arraysize;
|
||||
parms[numparms].type = newparm;
|
||||
parms[numparms].defltvalue.cast = NULL;
|
||||
|
||||
basicindex = 0;
|
||||
found = false;
|
||||
for(pc = newt; pc && !found; pc = pc->parentclass)
|
||||
{
|
||||
struct QCC_typeparam_s *pp;
|
||||
int numpc;
|
||||
int i;
|
||||
if (pc == newt)
|
||||
{
|
||||
pp = parms;
|
||||
numpc = numparms;
|
||||
}
|
||||
else
|
||||
{
|
||||
pp = pc->params;
|
||||
numpc = pc->num_parms;
|
||||
}
|
||||
for (i = 0; i < numpc; i++)
|
||||
{
|
||||
if (pp[i].type->type == newparm->type)
|
||||
{
|
||||
if (!strcmp(pp[i].paramname, parmname))
|
||||
{
|
||||
if (typecmp(pp[i].type, newparm))
|
||||
{
|
||||
char bufc[256];
|
||||
char bufp[256];
|
||||
TypeName(pp[i].type, bufp, sizeof(bufp));
|
||||
TypeName(newparm, bufc, sizeof(bufc));
|
||||
QCC_PR_ParseError(0, "%s defined as %s in %s, but %s in %s\n", parmname, bufc, newt->name, bufp, pc->name);
|
||||
}
|
||||
basicindex = pp[i].ofs;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)basicindex < pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1)) //if we found one with the index
|
||||
basicindex = pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1); //make sure we don't union it.
|
||||
}
|
||||
}
|
||||
}
|
||||
parms[numparms].ofs = basicindex; //ulp, its new
|
||||
numparms++;
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
if (!*basictypes[newparm->type])
|
||||
QCC_PR_ParseError(0, "members of type %s are not supported (%s::%s)\n", basictypenames[newparm->type], classname, parmname);
|
||||
|
||||
//make sure the union is okay
|
||||
d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST);
|
||||
if (d)
|
||||
basicindex = 0;
|
||||
else
|
||||
{ //don't go all weird with unioning generic fields
|
||||
QC_snprintfz(membername, sizeof(membername), "::*%s", basictypenames[newparm->type]);
|
||||
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
|
||||
if (!d)
|
||||
{
|
||||
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT|GDF_USED);
|
||||
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
|
||||
// d->symboldata[i]._int = pr.size_fields+i;
|
||||
// pr.size_fields += i;
|
||||
|
||||
d->used = true;
|
||||
d->referenced = true; //always referenced, so you can inherit safely.
|
||||
}
|
||||
if (d->arraysize < basicindex+(arraysize?arraysize:1))
|
||||
{
|
||||
if (d->symboldata)
|
||||
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
|
||||
else
|
||||
{
|
||||
int newsize = basicindex+(arraysize?arraysize:1);
|
||||
if (d->type->type == ev_union || d->type->type == ev_struct)
|
||||
d->arraysize = newsize;
|
||||
else while(d->arraysize < newsize)
|
||||
{
|
||||
QC_snprintfz(membername, sizeof(membername), "::%s[%i]", basictypenames[newparm->type], d->arraysize/d->type->size);
|
||||
QCC_PR_DummyDef(d->type, membername, d->scope, 0, d, d->arraysize, true, GDF_CONST);
|
||||
d->arraysize+=d->type->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QCC_FreeDef(d);
|
||||
|
||||
//and make sure we can do member::__fname
|
||||
//actually, that seems pointless.
|
||||
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
|
||||
// externs->Printf("define %s -> %s\n", membername, d->name);
|
||||
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, basicindex, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
|
||||
d->referenced = true; //always referenced, so you can inherit safely.
|
||||
}
|
||||
}
|
||||
|
||||
if (redeclaration)
|
||||
|
@ -6140,7 +6202,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
if (QCC_PR_CheckKeyword (keyword_union, "union"))
|
||||
structtype = ev_union;
|
||||
else if (QCC_PR_CheckKeyword (keyword_struct, "struct"))
|
||||
structtype = ev_struct;
|
||||
structtype = ev_struct; //defaults to public
|
||||
// else if (QCC_PR_CheckKeyword (keyword_class, "class"))
|
||||
// structtype = ev_struct; //defaults to private. no other difference.
|
||||
if (structtype != ev_void)
|
||||
{
|
||||
struct QCC_typeparam_s *parms = NULL, *oldparm;
|
||||
|
@ -6152,6 +6216,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
pbool isnonvirt = false;
|
||||
pbool isstatic = false;
|
||||
pbool isvirt = false;
|
||||
pbool definedsomething = false;
|
||||
|
||||
if (QCC_PR_CheckToken("{"))
|
||||
{
|
||||
|
@ -6241,15 +6306,28 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
|
||||
//parse field modifiers
|
||||
if (QCC_PR_CheckKeyword(1, "public"))
|
||||
{
|
||||
/*ispublic = true*/;
|
||||
QCC_PR_Expect(":");
|
||||
continue;
|
||||
}
|
||||
else if (QCC_PR_CheckKeyword(1, "private"))
|
||||
{
|
||||
/*isprivate = true*/;
|
||||
QCC_PR_Expect(":");
|
||||
continue;
|
||||
}
|
||||
else if (QCC_PR_CheckKeyword(1, "protected"))
|
||||
{
|
||||
/*isprotected = true*/;
|
||||
QCC_PR_Expect(":");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (QCC_PR_CheckKeyword(1, "nonvirtual"))
|
||||
isnonvirt = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "static"))
|
||||
//if (QCC_PR_CheckKeyword(1, "nonvirtual"))
|
||||
// isnonvirt = true;
|
||||
//else
|
||||
if (QCC_PR_CheckKeyword(1, "static"))
|
||||
isstatic = true;
|
||||
else if (QCC_PR_CheckKeyword(1, "virtual"))
|
||||
isvirt = true;
|
||||
|
@ -6260,6 +6338,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
|
||||
//now parse the actual type.
|
||||
newparm = QCC_PR_ParseType(false, false);
|
||||
definedsomething = false;
|
||||
}
|
||||
type = newparm;
|
||||
|
||||
|
@ -6269,6 +6348,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
arraysize = 0;
|
||||
if (QCC_PR_CheckToken(";"))
|
||||
{ //annonymous structs do weird scope stuff.
|
||||
if (!definedsomething && (type->type != ev_struct && type->type != ev_union))
|
||||
{
|
||||
if (flag_qcfuncs && type->type == ev_function && type->aux_type == newt && QCC_PR_PeekToken(";"))
|
||||
QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "constructors are not supported in structs at this time", newparm->name);
|
||||
else
|
||||
QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "declaration does not declare anything (%s)", newparm->name);
|
||||
}
|
||||
newparm = NULL;
|
||||
parmname = "";
|
||||
}
|
||||
|
@ -6277,6 +6363,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
|
|||
parmname = qccHunkAlloc(strlen(pr_token)+1);
|
||||
strcpy(parmname, pr_token);
|
||||
QCC_PR_Lex();
|
||||
definedsomething = true;
|
||||
if (QCC_PR_CheckToken("["))
|
||||
{
|
||||
arraysize=QCC_PR_IntConstExpr();
|
||||
|
|
|
@ -241,6 +241,8 @@ struct {
|
|||
{" F331", WARN_SELFNOTTHIS},
|
||||
{" F332", WARN_DIVISIONBY0},
|
||||
{" F333", WARN_ARGUMENTCHECK},
|
||||
{" F334", WARN_MISSINGMEMBERQUALIFIER},
|
||||
{" F335", WARN_MEMBERNOTDEFINED}, //defining a new member function inside a class that didn't list it.
|
||||
|
||||
{" F207", WARN_NOTREFERENCEDFIELD},
|
||||
{" F208", WARN_NOTREFERENCEDCONST},
|
||||
|
@ -3605,6 +3607,8 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
|
|||
type_uint64 = QCC_PR_NewType("__uint64", ev_uint64, true);
|
||||
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
|
||||
|
||||
type_invalid = QCC_PR_NewType("invalid", ev_void, false);
|
||||
|
||||
type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false);
|
||||
type_floatfield->aux_type = type_float;
|
||||
type_pointer->aux_type = QCC_PR_NewType("__pointeraux", ev_float, false);
|
||||
|
@ -4628,7 +4632,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
else
|
||||
*compiler_flag[p].enabled = false;
|
||||
}
|
||||
if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17"))
|
||||
if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c++") ||!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17"))
|
||||
{ //set up for greatest C compatibility... variations from C are bugs, not features.
|
||||
keyword_asm = false;
|
||||
keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true;
|
||||
|
@ -4658,7 +4662,13 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default.
|
||||
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals.
|
||||
|
||||
if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90"))
|
||||
if (!stricmp(myargv[i]+5, "c++"))
|
||||
{
|
||||
keyword_class = /*keyword_new =*/ keyword_inline = true;
|
||||
cnst = QCC_PR_DefineName("__cplusplus");
|
||||
val = NULL;
|
||||
}
|
||||
else if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90"))
|
||||
val = "199409L"; //it was ammended, apparently.
|
||||
else if (!stricmp(myargv[i]+5, "c99"))
|
||||
val = "199901L";
|
||||
|
@ -4858,11 +4868,12 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
case WARN_STRICTTYPEMISMATCH:
|
||||
case WARN_PARAMWITHNONAME:
|
||||
case WARN_IFSTRING_USED:
|
||||
case WARN_UNINITIALIZED:
|
||||
// case WARN_UNINITIALIZED:
|
||||
case WARN_GMQCC_SPECIFIC:
|
||||
case WARN_SYSTEMCRC:
|
||||
case WARN_SYSTEMCRC2:
|
||||
qccwarningaction[j] = qccwarningaction[WARN_GMQCC_SPECIFIC];
|
||||
if (qccwarningaction[WARN_GMQCC_SPECIFIC])
|
||||
qccwarningaction[j] = WA_WARN;
|
||||
break;
|
||||
|
||||
//these warnings require -Wextra to enable, as they're too annoying to have to fix
|
||||
|
|
Loading…
Reference in a new issue