fixes for classes and autoproto. also added #pragma autoproto

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4392 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-06-13 22:45:15 +00:00
parent 58e4ff0817
commit 8aae46a71b
4 changed files with 304 additions and 130 deletions

View file

@ -490,7 +490,7 @@ extern pbool keyword_union; //you surly know what a union is!
extern pbool keywords_coexist; extern pbool keywords_coexist;
extern pbool output_parms; extern pbool output_parms;
extern pbool autoprototype; extern pbool autoprototype, autoprototyped;
extern pbool pr_subscopedlocals; extern pbool pr_subscopedlocals;
extern pbool flag_ifstring; extern pbool flag_ifstring;
extern pbool flag_iffloat; extern pbool flag_iffloat;

View file

@ -67,6 +67,7 @@ pbool keyword_union; //you surly know what a union is!
pbool keywords_coexist; //don't disable a keyword simply because a var was made with the same name. pbool keywords_coexist; //don't disable a keyword simply because a var was made with the same name.
pbool output_parms; //emit some PARMX fields. confuses decompilers. pbool output_parms; //emit some PARMX fields. confuses decompilers.
pbool autoprototype; //take two passes over the source code. First time round doesn't enter and functions or initialise variables. pbool autoprototype; //take two passes over the source code. First time round doesn't enter and functions or initialise variables.
pbool autoprototyped; //previously autoprototyped. no longer allowed to enable autoproto, but don't warn about it.
pbool pr_subscopedlocals; //causes locals to be valid ONLY within their statement block. (they simply can't be referenced by name outside of it) pbool pr_subscopedlocals; //causes locals to be valid ONLY within their statement block. (they simply can't be referenced by name outside of it)
pbool flag_ifstring; //makes if (blah) equivelent to if (blah != "") which resolves some issues in multiprogs situations. pbool flag_ifstring; //makes if (blah) equivelent to if (blah != "") which resolves some issues in multiprogs situations.
pbool flag_iffloat; //use an op_if_f instruction instead of op_if so if(-0) evaluates to false. pbool flag_iffloat; //use an op_if_f instruction instead of op_if so if(-0) evaluates to false.
@ -1948,7 +1949,7 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_
{ {
TypeName(var_a->type, typea, sizeof(typea)); TypeName(var_a->type, typea, sizeof(typea));
TypeName(var_b->type, typeb, sizeof(typeb)); TypeName(var_b->type, typeb, sizeof(typeb));
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Implicit assignment from %s to %s", typea, typeb); QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Implicit assignment from %s to %s %s", typea, typeb, var_b->name);
} }
} }
break; break;
@ -2879,6 +2880,46 @@ QCC_def_t *QCC_PR_ParseImmediate (void)
return cn; return cn;
} }
QCC_def_t *QCC_PR_GenerateAddressOf(int expressionstart, QCC_def_t *operand)
{
QCC_def_t *e2;
if (expressionstart != numstatements)
//woo, something like ent.field?
{
if ((OP_LOAD_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOAD_FNC) || statements[numstatements-1].op == OP_LOAD_I || statements[numstatements-1].op == OP_LOAD_P)
{
statements[numstatements-1].op = OP_ADDRESS;
operand->type = QCC_PR_PointerType(operand->type);
return operand;
}
else if (OP_LOADA_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOADA_I || statements[numstatements-1].op == OP_LOADA_STRUCT)
{
statements[numstatements-1].op = OP_GLOBALADDRESS;
operand->type = QCC_PR_PointerType(operand->type);
return operand;
}
else if (OP_LOADP_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOADP_I)
{
statements[numstatements-1].op = OP_POINTER_ADD;
operand->type = QCC_PR_PointerType(operand->type);
return operand;
}
else //this is a restriction that could be lifted, I just want to make sure that I got all the bits first.
{
QCC_PR_ParseError (ERR_BADNOTTYPE, "type mismatch for '&' Must be singular expression or field reference");
return operand;
}
}
// QCC_PR_ParseWarning(0, "debug: &global");
if (!QCC_OPCodeValid(&pr_opcodes[OP_GLOBALADDRESS]))
QCC_PR_ParseError (ERR_BADEXTENSION, "Cannot use addressof operator ('&') on a global. Please use the FTE target.");
e2 = QCC_PR_Statement (&pr_opcodes[OP_GLOBALADDRESS], operand, 0, NULL);
e2->type = QCC_PR_PointerType(operand->type);
return e2;
}
void QCC_PrecacheSound (QCC_def_t *e, int ch) void QCC_PrecacheSound (QCC_def_t *e, int ch)
{ {
@ -3083,7 +3124,7 @@ QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC
self = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false); self = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false);
if (newself->ofs != self->ofs) if (newself->ofs != self->ofs)
{ {
oself = QCC_GetTemp(type_entity); oself = QCC_GetTemp(pr_classtype?pr_classtype:type_entity);
//oself = self //oself = self
QCC_PR_SimpleStatement(OP_STORE_ENT, self->ofs, oself->ofs, 0, false); QCC_PR_SimpleStatement(OP_STORE_ENT, self->ofs, oself->ofs, 0, false);
//self = other //self = other
@ -4394,8 +4435,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype)
QCC_dfunction_t *df; QCC_dfunction_t *df;
QCC_def_t *virt; QCC_def_t *ed;
QCC_def_t *ed, *oself, *self;
QCC_def_t *constructor = NULL; QCC_def_t *constructor = NULL;
pbool constructed = false; pbool constructed = false;
int basictypefield[ev_union+1]; int basictypefield[ev_union+1];
@ -4616,6 +4656,7 @@ QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign)
QCC_dstatement_t *st; QCC_dstatement_t *st;
pbool allowarray; pbool allowarray;
unsigned int arraysize; unsigned int arraysize;
int statatementstart;
t = d->type; t = d->type;
arraysize = d->arraysize; arraysize = d->arraysize;
@ -4785,6 +4826,8 @@ QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign)
break; break;
} }
statatementstart = numstatements;
if (idx) if (idx)
{ {
if (d->type->type == ev_pointer) if (d->type->type == ev_pointer)
@ -5023,6 +5066,10 @@ QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign)
d = QCC_PR_ParseArrayPointer(d, allowarrayassign); d = QCC_PR_ParseArrayPointer(d, allowarrayassign);
} }
//float b[64]; return b; should return a pointer, and NOT the value b[0].
if (arraysize)
d = QCC_PR_GenerateAddressOf(statatementstart, d);
d = QCC_PR_ParseField(d); d = QCC_PR_ParseField(d);
return d; return d;
} }
@ -5212,7 +5259,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, p
{ {
if (!pr_classtype) if (!pr_classtype)
QCC_PR_ParseError(ERR_NOTANAME, "Cannot use 'this' outside of an OO function\n"); QCC_PR_ParseError(ERR_NOTANAME, "Cannot use 'this' outside of an OO function\n");
od = QCC_PR_GetDef(NULL, "self", NULL, true, 0, false); od = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false);
d = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, od->ofs, true, GDF_CONST); d = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, od->ofs, true, GDF_CONST);
} }
else if (keyword_class && !strcmp(name, "super")) else if (keyword_class && !strcmp(name, "super"))
@ -5231,6 +5278,12 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, p
{ {
if (!d) if (!d)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\" in class \"%s\"", name, assumeclass->name); QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\" in class \"%s\"", name, assumeclass->name);
else if (!assumeclass->parentclass && assumeclass != type_entity)
{
QCC_PR_ParseWarning (ERR_UNKNOWNVALUE, "Class \"%s\" is not defined, cannot access memeber \"%s\"", assumeclass->name, name);
if (!autoprototype && !autoprototyped)
QCC_PR_Note(ERR_UNKNOWNVALUE, strings+s_file, pr_source_line, "Consider using #pragma autoproto");
}
else else
{ {
QCC_PR_ParseWarning (ERR_UNKNOWNVALUE, "Unknown value \"%s\" in class \"%s\"", name, assumeclass->name); QCC_PR_ParseWarning (ERR_UNKNOWNVALUE, "Unknown value \"%s\" in class \"%s\"", name, assumeclass->name);
@ -5379,43 +5432,8 @@ QCC_def_t *QCC_PR_Term (int exprflags)
{ {
int st = numstatements; int st = numstatements;
e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA); e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
t = e->type->type;
if (st != numstatements) return QCC_PR_GenerateAddressOf(st, e);
//woo, something like ent.field?
{
if ((OP_LOAD_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOAD_FNC) || statements[numstatements-1].op == OP_LOAD_I || statements[numstatements-1].op == OP_LOAD_P)
{
statements[numstatements-1].op = OP_ADDRESS;
e->type = QCC_PR_PointerType(e->type);
return e;
}
else if (OP_LOADA_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOADA_I || statements[numstatements-1].op == OP_LOADA_STRUCT)
{
statements[numstatements-1].op = OP_GLOBALADDRESS;
e->type = QCC_PR_PointerType(e->type);
return e;
}
else if (OP_LOADP_F <= statements[numstatements-1].op && statements[numstatements-1].op <= OP_LOADP_I)
{
statements[numstatements-1].op = OP_POINTER_ADD;
e->type = QCC_PR_PointerType(e->type);
return e;
}
else //this is a restriction that could be lifted, I just want to make sure that I got all the bits first.
{
QCC_PR_ParseError (ERR_BADNOTTYPE, "type mismatch for '&' Must be singular expression or field reference");
return e;
}
}
// QCC_PR_ParseWarning(0, "debug: &global");
if (!QCC_OPCodeValid(&pr_opcodes[OP_GLOBALADDRESS]))
QCC_PR_ParseError (ERR_BADEXTENSION, "Cannot use addressof operator ('&') on a global. Please use the FTE target.");
e2 = QCC_PR_Statement (&pr_opcodes[OP_GLOBALADDRESS], e, 0, NULL);
e2->type = QCC_PR_PointerType(e->type);
return e2;
} }
else if (QCC_PR_CheckToken ("*")) else if (QCC_PR_CheckToken ("*"))
{ {
@ -9964,6 +9982,8 @@ void QCC_PR_ParseDefs (char *classname)
} }
if (type->type == ev_struct && strcmp(type->name, "struct")) if (type->type == ev_struct && strcmp(type->name, "struct"))
return; //allow named structs return; //allow named structs
if (type->type == ev_entity && type != type_entity)
return; //allow forward class definititions with or without a variable.
// if (type->type == ev_union) // if (type->type == ev_union)
// { // {
// return; // return;

View file

@ -53,6 +53,18 @@ int numCompilerConstants;
extern pbool expandedemptymacro; extern pbool expandedemptymacro;
static void Q_strlcpy(char *dest, const char *src, int sizeofdest)
{
if (sizeofdest)
{
int slen = strlen(src);
slen = min((sizeofdest-1), slen);
memcpy(dest, src, slen);
dest[slen] = 0;
}
}
char *pr_punctuation[] = char *pr_punctuation[] =
// longer symbols must be before a shorter partial match // longer symbols must be before a shorter partial match
@ -168,7 +180,7 @@ void QCC_PR_PrintNextLine (void)
extern char qccmsourcedir[]; extern char qccmsourcedir[];
//also meant to include it. //also meant to include it.
void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath, pbool verbose)
{ {
char fullname[1024]; char fullname[1024];
int doubledots; int doubledots;
@ -223,6 +235,13 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath)
strcpy(end, newfile); strcpy(end, newfile);
if (verbose)
{
if (autoprototype)
printf("prototyping include %s\n", fullname);
else
printf("including %s\n", fullname);
}
QCC_Include(fullname); QCC_Include(fullname);
} }
@ -726,7 +745,7 @@ pbool QCC_PR_Precompiler(void)
if (!strcmp(pr_token, "#endlist")) if (!strcmp(pr_token, "#endlist"))
break; break;
QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir); QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir, true);
if (*pr_file_p == '\r') if (*pr_file_p == '\r')
pr_file_p++; pr_file_p++;
@ -769,7 +788,7 @@ pbool QCC_PR_Precompiler(void)
} }
msg[a] = 0; msg[a] = 0;
QCC_FindBestInclude(msg, compilingfile, qccmsourcedir); QCC_FindBestInclude(msg, compilingfile, qccmsourcedir, false);
pr_file_p++; pr_file_p++;
@ -884,24 +903,34 @@ pbool QCC_PR_Precompiler(void)
QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
} }
else if (!strncmp(qcc_token, "compress", 8)) else if (!QC_strcasecmp(qcc_token, "compress"))
{ {
extern pbool compressoutput; extern pbool compressoutput;
compressoutput = atoi(msg); compressoutput = atoi(msg);
} }
else if (!strncmp(qcc_token, "forcecrc", 8)) else if (!QC_strcasecmp(qcc_token, "forcecrc"))
{ {
ForcedCRC = atoi(msg); ForcedCRC = atoi(msg);
} }
else if (!strncmp(qcc_token, "noref", 8)) else if (!QC_strcasecmp(qcc_token, "noref"))
{ {
defaultnoref = atoi(msg); defaultnoref = !!atoi(msg);
} }
else if (!strncmp(qcc_token, "defaultstatic", 13)) else if (!QC_strcasecmp(qcc_token, "defaultstatic"))
{ {
defaultstatic = atoi(msg); defaultstatic = !!atoi(msg);
} }
else if (!strncmp(qcc_token, "wrasm", 5)) else if (!QC_strcasecmp(qcc_token, "autoproto"))
{
if (!autoprototyped)
{
if (numpr_globals != RESERVED_OFS)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "#pragma autoproto must appear before any definitions");
else
autoprototype = *msg?!!atoi(msg):true;
}
}
else if (!QC_strcasecmp(qcc_token, "wrasm"))
{ {
pbool on = atoi(msg); pbool on = atoi(msg);
@ -920,7 +949,50 @@ pbool QCC_PR_Precompiler(void)
asmfilebegun = true; asmfilebegun = true;
} }
} }
else if (!strncmp(qcc_token, "sourcefile", 10)) else if (!QC_strcasecmp(qcc_token, "optimise") || !QC_strcasecmp(qcc_token, "optimize")) //bloomin' americans.
{
int o;
extern pbool qcc_nopragmaoptimise;
if (pr_scope)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "pragma %s: unable to change optimisations mid-function", qcc_token, msg);
else if (qcc_nopragmaoptimise)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "pragma %s %s: overriden by commandline", qcc_token, msg);
else if (*msg >= '0' && *msg <= '3')
{
int lev = atoi(msg);
for (o = 0; optimisations[o].enabled; o++)
{
if (optimisations[o].optimisationlevel <= lev)
*optimisations[o].enabled = true;
}
}
else
{
if (!strnicmp(msg, "no-", 3))
{
for (o = 0; optimisations[o].enabled; o++)
{
if ((*optimisations[o].abbrev && !stricmp(msg+3, optimisations[o].abbrev)) || !stricmp(msg+3, optimisations[o].fullname))
{
*optimisations[o].enabled = false;
break;
}
}
}
else
{
for (o = 0; optimisations[o].enabled; o++)
if ((*optimisations[o].abbrev && !stricmp(msg, optimisations[o].abbrev)) || !stricmp(msg, optimisations[o].fullname))
{
*optimisations[o].enabled = true;
break;
}
}
if (!optimisations[o].enabled)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "pragma %s: %s unsupported", qcc_token, msg);
}
}
else if (!QC_strcasecmp(qcc_token, "sourcefile"))
{ {
#define MAXSOURCEFILESLIST 8 #define MAXSOURCEFILESLIST 8
extern char sourcefileslist[MAXSOURCEFILESLIST][1024]; extern char sourcefileslist[MAXSOURCEFILESLIST][1024];
@ -979,11 +1051,13 @@ pbool QCC_PR_Precompiler(void)
else if (!QC_strcasecmp(qcc_token, "PROGS_DAT")) 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. { //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
extern char destfile[1024]; extern char destfile[1024];
char olddest[1024];
#ifndef QCCONLY #ifndef QCCONLY
extern char qccmfilename[1024]; extern char qccmfilename[1024];
int p; int p;
char *s, *s2; char *s, *s2;
#endif #endif
Q_strlcpy(olddest, destfile, sizeof(olddest));
QCC_COM_Parse(msg); QCC_COM_Parse(msg);
#ifndef QCCONLY #ifndef QCCONLY
@ -1022,7 +1096,8 @@ pbool QCC_PR_Precompiler(void)
strcpy(destfile, qcc_token); strcpy(destfile, qcc_token);
#endif #endif
printf("Outputfile: %s\n", destfile); if (strcmp(destfile, olddest))
printf("Outputfile: %s\n", destfile);
} }
else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag")) else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag"))
{ {
@ -3813,6 +3888,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
struct QCC_typeparam_s *parms = NULL; struct QCC_typeparam_s *parms = NULL;
char *parmname; char *parmname;
int arraysize; int arraysize;
pbool redeclaration;
parmname = QCC_PR_ParseName(); parmname = QCC_PR_ParseName();
classname = qccHunkAlloc(strlen(parmname)+1); classname = qccHunkAlloc(strlen(parmname)+1);
@ -3820,8 +3896,21 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
newt = 0; newt = 0;
/* Don't advance the line number yet */ if (QCC_PR_CheckToken(":"))
forwarddeclaration = pr_token[0] == ';'; {
char *parentname = QCC_PR_ParseName();
fieldtype = QCC_TypeForName(parentname);
if (!fieldtype)
QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not yet defined", parentname);
forwarddeclaration = false;
QCC_PR_Expect("{");
}
else
{
fieldtype = type_entity;
forwarddeclaration = !QCC_PR_CheckToken("{");
}
/* Look to see if this type is already defined */ /* Look to see if this type is already defined */
for(i=0;i<numtypeinfos;i++) for(i=0;i<numtypeinfos;i++)
@ -3835,45 +3924,33 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
} }
} }
if (newt && forwarddeclaration)
QCC_PR_ParseError(ERR_REDECLARATION, "Forward declaration of already defined class %s", classname);
if (newt && newt->num_parms != 0) if (newt && newt->num_parms != 0)
QCC_PR_ParseError(ERR_REDECLARATION, "Redeclaration of class %s", classname); redeclaration = true;
if (pr_scope && !forwarddeclaration) else
QCC_PR_ParseError(ERR_REDECLARATION, "Declaration of class %s within function", classname); redeclaration = false;
if (!newt) if (!newt)
{
newt = QCC_PR_NewType(classname, ev_entity, true); newt = QCC_PR_NewType(classname, ev_entity, true);
newt->size=type_entity->size;
newt->size=type_entity->size; }
type = NULL; type = NULL;
if (forwarddeclaration) if (forwarddeclaration)
{ return newt;
QCC_PR_CheckToken(";");
return NULL;
}
if (pr_scope)
QCC_PR_ParseError(ERR_REDECLARATION, "Declaration of class %s within function", classname);
if (redeclaration && fieldtype != newt->parentclass)
QCC_PR_ParseError(ERR_REDECLARATION, "Parent class changed on redeclaration of %s", classname);
newt->parentclass = fieldtype;
if (QCC_PR_CheckToken(":"))
{
char *parentname = QCC_PR_ParseName();
newt->parentclass = QCC_TypeForName(parentname);
if (!newt->parentclass)
QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not defined", parentname);
}
else
newt->parentclass = type_entity;
QCC_PR_Expect("{");
if (QCC_PR_CheckToken(",")) if (QCC_PR_CheckToken(","))
QCC_PR_ParseError(ERR_NOTANAME, "member missing name"); QCC_PR_ParseError(ERR_NOTANAME, "member missing name");
while (!QCC_PR_CheckToken("}")) while (!QCC_PR_CheckToken("}"))
{ {
pbool havebody = false;
pbool isstatic = false, isvirt = false; pbool isstatic = false, isvirt = false;
if (QCC_PR_CheckKeyword(1, "static")) if (QCC_PR_CheckKeyword(1, "static"))
isstatic = true; isstatic = true;
@ -3892,16 +3969,28 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_PR_Lex(); QCC_PR_Lex();
if (QCC_PR_CheckToken("[")) if (QCC_PR_CheckToken("["))
{ {
arraysize=QCC_PR_IntConstExpr(); arraysize = QCC_PR_IntConstExpr();
QCC_PR_Expect("]"); QCC_PR_Expect("]");
} }
else
arraysize = 0;
if (isvirt && newparm->type != ev_function) if (isvirt && newparm->type != ev_function)
{ {
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function"); QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
} }
if (QCC_PR_CheckToken("=")) if (newparm->type == ev_function)
{
if (QCC_PR_CheckToken("="))
{
havebody = true;
}
else if (pr_token[0] == '{')
havebody = true;
}
if (havebody)
{ {
QCC_def_t *def; QCC_def_t *def;
QCC_function_t *f; QCC_function_t *f;
@ -3920,37 +4009,60 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
extern QCC_type_t *pr_classtype; extern QCC_type_t *pr_classtype;
QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type); QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type);
pr_scope = def; if (autoprototype)
pr_classtype = newt;
f = QCC_PR_ParseImmediateStatements (newparm);
pr_classtype = NULL;
pr_scope = NULL;
G_FUNCTION(def->ofs) = numfunctions;
f->def = def;
def->initialized = 1;
if (numfunctions >= MAX_FUNCTIONS)
QCC_Error(ERR_INTERNAL, "Too many function defs");
// fill in the dfunction
df = &functions[numfunctions];
numfunctions++;
if (f->builtin)
df->first_statement = -f->builtin;
else
df->first_statement = f->code;
if (f->builtin && opt_function_names)
optres_function_names += strlen(f->def->name);
else
df->s_name = QCC_CopyString (f->def->name);
df->s_file = s_file;
df->numparms = f->def->type->num_parms;
df->locals = locals_end - locals_start;
df->parm_start = locals_start;
for (i=0 ; i<df->numparms ; i++)
{ {
df->parm_size[i] = newparm->params[i].type->size; 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_scope = def;
pr_classtype = newt;
f = QCC_PR_ParseImmediateStatements (newparm);
pr_classtype = NULL;
pr_scope = NULL;
G_FUNCTION(def->ofs) = numfunctions;
f->def = def;
def->initialized = 1;
if (numfunctions >= MAX_FUNCTIONS)
QCC_Error(ERR_INTERNAL, "Too many function defs");
// fill in the dfunction
df = &functions[numfunctions];
numfunctions++;
if (f->builtin)
df->first_statement = -f->builtin;
else
df->first_statement = f->code;
if (f->builtin && opt_function_names)
optres_function_names += strlen(f->def->name);
else
df->s_name = QCC_CopyString (f->def->name);
df->s_file = s_file;
df->numparms = f->def->type->num_parms;
df->locals = locals_end - locals_start;
df->parm_start = locals_start;
for (i=0 ; i<df->numparms ; i++)
{
df->parm_size[i] = newparm->params[i].type->size;
}
} }
} }
@ -4037,11 +4149,29 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 0, 0); QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 0, 0);
} }
newt->num_parms = numparms; if (redeclaration)
newt->params = qccHunkAlloc(sizeof(*type->params) * numparms); {
memcpy(newt->params, parms, sizeof(*type->params) * numparms); int i;
free(parms); redeclaration = newt->num_parms != numparms;
for (i = 0; i < numparms && i < newt->num_parms; i++)
{
if (newt->params[i].arraysize != parms[i].arraysize || typecmp(newt->params[i].type, parms[i].type) || strcmp(newt->params[i].paramname, parms[i].paramname))
{
QCC_PR_ParseError(ERR_REDECLARATION, "Incompatible redeclaration of class %s. %s differs.", classname, parms[i].paramname);
break;
}
}
if (newt->num_parms != numparms)
QCC_PR_ParseError(ERR_REDECLARATION, "Incompatible redeclaration of class %s.", classname);
}
else
{
newt->num_parms = numparms;
newt->params = qccHunkAlloc(sizeof(*type->params) * numparms);
memcpy(newt->params, parms, sizeof(*type->params) * numparms);
}
free(parms);
{ {
QCC_def_t *d; QCC_def_t *d;
@ -4065,7 +4195,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
{ {
struct QCC_typeparam_s *parms = NULL; struct QCC_typeparam_s *parms = NULL;
int numparms = 0; int numparms = 0;
int arraysize; unsigned int arraysize;
char *parmname; char *parmname;
if (QCC_PR_CheckToken("{")) if (QCC_PR_CheckToken("{"))
@ -4108,7 +4238,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
else else
newparm = QCC_PR_ParseType(true, false); newparm = QCC_PR_ParseType(true, false);
arraysize = 1; arraysize = 0;
if (!QCC_PR_CheckToken(";")) if (!QCC_PR_CheckToken(";"))
{ {
@ -4118,6 +4248,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckToken("[")) if (QCC_PR_CheckToken("["))
{ {
arraysize=QCC_PR_IntConstExpr(); arraysize=QCC_PR_IntConstExpr();
if (!arraysize)
QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays");
QCC_PR_Expect("]"); QCC_PR_Expect("]");
} }
QCC_PR_CheckToken(";"); QCC_PR_CheckToken(";");
@ -4130,13 +4262,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (structtype == ev_union) if (structtype == ev_union)
{ {
parms[numparms].ofs = 0; parms[numparms].ofs = 0;
if (newparm->size*arraysize > newt->size) if (newparm->size*(arraysize?arraysize:1) > newt->size)
newt->size = newparm->size*arraysize; newt->size = newparm->size*(arraysize?arraysize:1);
} }
else else
{ {
parms[numparms].ofs = newt->size; parms[numparms].ofs = newt->size;
newt->size += newparm->size*arraysize; newt->size += newparm->size*(arraysize?arraysize:1);
} }
parms[numparms].arraysize = arraysize; parms[numparms].arraysize = arraysize;
parms[numparms].optional = false; parms[numparms].optional = false;

View file

@ -19,6 +19,7 @@ extern int optres_test2;
int writeasm; int writeasm;
pbool verbose; pbool verbose;
pbool qcc_nopragmaoptimise;
pbool QCC_PR_SimpleGetToken (void); pbool QCC_PR_SimpleGetToken (void);
@ -216,7 +217,7 @@ optimisations_t optimisations[] =
//level 1 = size optimisations //level 1 = size optimisations
//level 2 = speed optimisations //level 2 = speed optimisations
//level 3 = dodgy optimisations. //level 3 = dodgy optimisations.
//level 4 = experimental... //level 4 = experimental... must be used explicitly
{&opt_assignments, "t", 1, FLAG_ASDEFAULT, "assignments", "c = a*b is performed in one operation rather than two, and can cause older decompilers to fail."}, {&opt_assignments, "t", 1, FLAG_ASDEFAULT, "assignments", "c = a*b is performed in one operation rather than two, and can cause older decompilers to fail."},
{&opt_shortenifnots, "i", 1, FLAG_ASDEFAULT, "shortenifs", "if (!a) was traditionally compiled in two statements. This optimisation does it in one, but can cause some decompilers to get confused."}, {&opt_shortenifnots, "i", 1, FLAG_ASDEFAULT, "shortenifs", "if (!a) was traditionally compiled in two statements. This optimisation does it in one, but can cause some decompilers to get confused."},
@ -236,7 +237,7 @@ optimisations_t optimisations[] =
{&opt_compound_jumps, "cj", 3, FLAG_KILLSDEBUGGERS, "compound_jumps", "This optimisation plays an effect mostly with nested if/else statements, instead of jumping to an unconditional jump statement, it'll jump to the final destination instead. This will bewilder decompilers."}, {&opt_compound_jumps, "cj", 3, FLAG_KILLSDEBUGGERS, "compound_jumps", "This optimisation plays an effect mostly with nested if/else statements, instead of jumping to an unconditional jump statement, it'll jump to the final destination instead. This will bewilder decompilers."},
// {&opt_comexprremoval, "cer", 4, 0, "expression_removal", "Eliminate common sub-expressions"}, //this would be too hard... // {&opt_comexprremoval, "cer", 4, 0, "expression_removal", "Eliminate common sub-expressions"}, //this would be too hard...
{&opt_stripfunctions, "sf", 4, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games. This can affect FTE_MULTIPROGS."}, {&opt_stripfunctions, "sf", 4, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games. This can affect FTE_MULTIPROGS."},
{&opt_locals_overlapping, "lo", 4, FLAG_KILLSDEBUGGERS, "locals_overlapping", "Store all locals in a single section of the pr_globals. Vastly reducing it. This effectivly does the job of overlaptemps.\nHowever, locals are no longer automatically initialised to 0 (and never were in the case of recursion, but at least then its the same type).\nIf locals appear uninitialised, fteqcc will disable this optimisation for the affected functions, you can optionally get a warning about these locals using: #pragma warning enable F302"}, {&opt_locals_overlapping, "lo", 3, FLAG_KILLSDEBUGGERS, "locals_overlapping", "Store all locals in a single section of the pr_globals. Vastly reducing it. This effectivly does the job of overlaptemps.\nHowever, locals are no longer automatically initialised to 0 (and never were in the case of recursion, but at least then its the same type).\nIf locals appear uninitialised, fteqcc will disable this optimisation for the affected functions, you can optionally get a warning about these locals using: #pragma warning enable F302"},
{&opt_vectorcalls, "vc", 4, FLAG_KILLSDEBUGGERS, "vectorcalls", "Where a function is called with just a vector, this causes the function call to store three floats instead of one vector. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not match entirly."}, {&opt_vectorcalls, "vc", 4, FLAG_KILLSDEBUGGERS, "vectorcalls", "Where a function is called with just a vector, this causes the function call to store three floats instead of one vector. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not match entirly."},
{NULL} {NULL}
}; };
@ -381,7 +382,7 @@ int QCC_CopyString (char *str)
if (!*str) if (!*str)
return 1; return 1;
if (opt_noduplicatestrings) if (opt_noduplicatestrings || !strcmp(str, "IMMEDIATE"))
{ {
#if 1 #if 1
//more scalable (faster) version. //more scalable (faster) version.
@ -2604,6 +2605,7 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
int i, j, p; int i, j, p;
char *name, *val; char *name, *val;
pbool werror = false; pbool werror = false;
qcc_nopragmaoptimise = false;
for (i = 1;i<myargc;i++) for (i = 1;i<myargc;i++)
{ {
@ -2628,6 +2630,7 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
//optimisations. //optimisations.
else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) ) else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) )
{ {
qcc_nopragmaoptimise = true;
p = 0; p = 0;
if (myargv[i][2] >= '0' && myargv[i][2] <= '3') if (myargv[i][2] >= '0' && myargv[i][2] <= '3')
{ {
@ -2826,6 +2829,7 @@ void QCC_SetDefaultProperties (void)
ForcedCRC = 0; ForcedCRC = 0;
defaultstatic = 0; defaultstatic = 0;
autoprototyped = false;
QCC_PR_DefineName("FTEQCC"); QCC_PR_DefineName("FTEQCC");
@ -3311,6 +3315,7 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string));
void StartNewStyleCompile(void); void StartNewStyleCompile(void);
newstyle: newstyle:
newstylesource = true; newstylesource = true;
originalqccmsrc = qccmsrc;
StartNewStyleCompile(); StartNewStyleCompile();
return; return;
} }
@ -3659,13 +3664,30 @@ void new_QCC_ContinueCompile(void)
{ {
if (pr_error_count) if (pr_error_count)
QCC_Error (ERR_PARSEERRORS, "Errors have occured"); QCC_Error (ERR_PARSEERRORS, "Errors have occured");
QCC_FinishCompile();
PostCompile(); if (autoprototype)
if (!PreCompile()) {
qccmsrc = originalqccmsrc;
pr_file_p = qccmsrc;
s_file = s_file2 = QCC_CopyString (compilingfile);
QCC_SetDefaultProperties();
autoprototyped = autoprototype;
autoprototype = false;
QCC_PR_NewLine(false);
QCC_PR_Lex();
return; return;
QCC_main(myargc, myargv); }
return; else
{
QCC_FinishCompile();
PostCompile();
if (!PreCompile())
return;
QCC_main(myargc, myargv);
return;
}
} }
pr_scope = NULL; // outside all functions pr_scope = NULL; // outside all functions