diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 2700c92e..67737958 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -490,7 +490,7 @@ extern pbool keyword_union; //you surly know what a union is! extern pbool keywords_coexist; extern pbool output_parms; -extern pbool autoprototype; +extern pbool autoprototype, autoprototyped; extern pbool pr_subscopedlocals; extern pbool flag_ifstring; extern pbool flag_iffloat; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 368e2ad5..6624fcee 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -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 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 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 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. @@ -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_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; @@ -2879,6 +2880,46 @@ QCC_def_t *QCC_PR_ParseImmediate (void) 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) { @@ -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); if (newself->ofs != self->ofs) { - oself = QCC_GetTemp(type_entity); + oself = QCC_GetTemp(pr_classtype?pr_classtype:type_entity); //oself = self QCC_PR_SimpleStatement(OP_STORE_ENT, self->ofs, oself->ofs, 0, false); //self = other @@ -4394,8 +4435,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype) QCC_dfunction_t *df; - QCC_def_t *virt; - QCC_def_t *ed, *oself, *self; + QCC_def_t *ed; QCC_def_t *constructor = NULL; pbool constructed = false; 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; pbool allowarray; unsigned int arraysize; + int statatementstart; t = d->type; arraysize = d->arraysize; @@ -4785,6 +4826,8 @@ QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign) break; } + statatementstart = numstatements; + if (idx) { 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); } + //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); return d; } @@ -5212,7 +5259,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, p { if (!pr_classtype) 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); } 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) 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 { 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; e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA); - t = e->type->type; - if (st != 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; - 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; + return QCC_PR_GenerateAddressOf(st, e); } else if (QCC_PR_CheckToken ("*")) { @@ -9964,6 +9982,8 @@ void QCC_PR_ParseDefs (char *classname) } if (type->type == ev_struct && strcmp(type->name, "struct")) 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) // { // return; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index b97ed8db..93f260c1 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -53,6 +53,18 @@ int numCompilerConstants; 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[] = // longer symbols must be before a shorter partial match @@ -168,7 +180,7 @@ void QCC_PR_PrintNextLine (void) extern char qccmsourcedir[]; //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]; int doubledots; @@ -223,6 +235,13 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) strcpy(end, newfile); + if (verbose) + { + if (autoprototype) + printf("prototyping include %s\n", fullname); + else + printf("including %s\n", fullname); + } QCC_Include(fullname); } @@ -726,7 +745,7 @@ pbool QCC_PR_Precompiler(void) if (!strcmp(pr_token, "#endlist")) break; - QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir); + QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir, true); if (*pr_file_p == '\r') pr_file_p++; @@ -769,7 +788,7 @@ pbool QCC_PR_Precompiler(void) } msg[a] = 0; - QCC_FindBestInclude(msg, compilingfile, qccmsourcedir); + QCC_FindBestInclude(msg, compilingfile, qccmsourcedir, false); pr_file_p++; @@ -884,24 +903,34 @@ pbool QCC_PR_Precompiler(void) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); 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; compressoutput = atoi(msg); } - else if (!strncmp(qcc_token, "forcecrc", 8)) + else if (!QC_strcasecmp(qcc_token, "forcecrc")) { 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); @@ -920,7 +949,50 @@ pbool QCC_PR_Precompiler(void) 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 extern char sourcefileslist[MAXSOURCEFILESLIST][1024]; @@ -979,11 +1051,13 @@ pbool QCC_PR_Precompiler(void) 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. extern char destfile[1024]; + char olddest[1024]; #ifndef QCCONLY extern char qccmfilename[1024]; int p; char *s, *s2; #endif + Q_strlcpy(olddest, destfile, sizeof(olddest)); QCC_COM_Parse(msg); #ifndef QCCONLY @@ -1022,7 +1096,8 @@ pbool QCC_PR_Precompiler(void) strcpy(destfile, qcc_token); #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")) { @@ -3813,6 +3888,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) struct QCC_typeparam_s *parms = NULL; char *parmname; int arraysize; + pbool redeclaration; parmname = QCC_PR_ParseName(); classname = qccHunkAlloc(strlen(parmname)+1); @@ -3820,8 +3896,21 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) newt = 0; - /* Don't advance the line number yet */ - forwarddeclaration = pr_token[0] == ';'; + if (QCC_PR_CheckToken(":")) + { + 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 */ for(i=0;inum_parms != 0) - QCC_PR_ParseError(ERR_REDECLARATION, "Redeclaration of class %s", classname); - if (pr_scope && !forwarddeclaration) - QCC_PR_ParseError(ERR_REDECLARATION, "Declaration of class %s within function", classname); + redeclaration = true; + else + redeclaration = false; if (!newt) + { newt = QCC_PR_NewType(classname, ev_entity, true); - - newt->size=type_entity->size; + newt->size=type_entity->size; + } type = NULL; if (forwarddeclaration) - { - QCC_PR_CheckToken(";"); - return NULL; - } + return newt; + 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(",")) QCC_PR_ParseError(ERR_NOTANAME, "member missing name"); while (!QCC_PR_CheckToken("}")) { + pbool havebody = false; pbool isstatic = false, isvirt = false; if (QCC_PR_CheckKeyword(1, "static")) isstatic = true; @@ -3892,16 +3969,28 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) QCC_PR_Lex(); if (QCC_PR_CheckToken("[")) { - arraysize=QCC_PR_IntConstExpr(); + arraysize = QCC_PR_IntConstExpr(); QCC_PR_Expect("]"); } + else + arraysize = 0; if (isvirt && newparm->type != ev_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_function_t *f; @@ -3920,37 +4009,60 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) extern QCC_type_t *pr_classtype; QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type); - 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 ; inumparms ; i++) + if (autoprototype) { - 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 ; inumparms ; 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); } - newt->num_parms = numparms; - newt->params = qccHunkAlloc(sizeof(*type->params) * numparms); - memcpy(newt->params, parms, sizeof(*type->params) * numparms); - free(parms); + if (redeclaration) + { + int i; + 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; @@ -4065,7 +4195,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) { struct QCC_typeparam_s *parms = NULL; int numparms = 0; - int arraysize; + unsigned int arraysize; char *parmname; if (QCC_PR_CheckToken("{")) @@ -4108,7 +4238,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) else newparm = QCC_PR_ParseType(true, false); - arraysize = 1; + arraysize = 0; if (!QCC_PR_CheckToken(";")) { @@ -4118,6 +4248,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) if (QCC_PR_CheckToken("[")) { arraysize=QCC_PR_IntConstExpr(); + if (!arraysize) + QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays"); QCC_PR_Expect("]"); } QCC_PR_CheckToken(";"); @@ -4130,13 +4262,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) if (structtype == ev_union) { parms[numparms].ofs = 0; - if (newparm->size*arraysize > newt->size) - newt->size = newparm->size*arraysize; + if (newparm->size*(arraysize?arraysize:1) > newt->size) + newt->size = newparm->size*(arraysize?arraysize:1); } else { parms[numparms].ofs = newt->size; - newt->size += newparm->size*arraysize; + newt->size += newparm->size*(arraysize?arraysize:1); } parms[numparms].arraysize = arraysize; parms[numparms].optional = false; diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 29a34fb2..6565edb8 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -19,6 +19,7 @@ extern int optres_test2; int writeasm; pbool verbose; +pbool qcc_nopragmaoptimise; pbool QCC_PR_SimpleGetToken (void); @@ -216,7 +217,7 @@ optimisations_t optimisations[] = //level 1 = size optimisations //level 2 = speed 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_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_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_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."}, {NULL} }; @@ -381,7 +382,7 @@ int QCC_CopyString (char *str) if (!*str) return 1; - if (opt_noduplicatestrings) + if (opt_noduplicatestrings || !strcmp(str, "IMMEDIATE")) { #if 1 //more scalable (faster) version. @@ -2604,6 +2605,7 @@ void QCC_PR_CommandLinePrecompilerOptions (void) int i, j, p; char *name, *val; pbool werror = false; + qcc_nopragmaoptimise = false; for (i = 1;i= '0' && myargv[i][2] <= '3') { @@ -2826,6 +2829,7 @@ void QCC_SetDefaultProperties (void) ForcedCRC = 0; defaultstatic = 0; + autoprototyped = false; QCC_PR_DefineName("FTEQCC"); @@ -3311,6 +3315,7 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); void StartNewStyleCompile(void); newstyle: newstylesource = true; + originalqccmsrc = qccmsrc; StartNewStyleCompile(); return; } @@ -3659,13 +3664,30 @@ void new_QCC_ContinueCompile(void) { if (pr_error_count) QCC_Error (ERR_PARSEERRORS, "Errors have occured"); - QCC_FinishCompile(); - PostCompile(); - if (!PreCompile()) + if (autoprototype) + { + 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; - QCC_main(myargc, myargv); - return; + } + else + { + QCC_FinishCompile(); + + PostCompile(); + if (!PreCompile()) + return; + QCC_main(myargc, myargv); + return; + } } pr_scope = NULL; // outside all functions