1
0
Fork 0
forked from fte/fteqw

Added IF_F instructions.

Added -fassumeint so constants are by default ints instead of floats (like in C). Use a decimal point and it'll be a float.
Fixed a couple of omissions/bugs reported by Blub.
Added lame x86 jit which is still buggy, incomplete, and disabled. And bigfoot will hate it.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3349 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2009-08-29 14:56:42 +00:00
parent 1718aae24b
commit 2158389bef
14 changed files with 1341 additions and 96 deletions

View file

@ -132,7 +132,7 @@ int Comp_Continue(progfuncs_t *progfuncs)
if (setjmp(qcccompileerror))
{
PostCompile();
if (*errorfile)
if (*errorfile && externs->useeditor)
externs->useeditor(progfuncs, errorfile, errorline, comp_nump, comp_parms);
return false;
}
@ -143,7 +143,7 @@ int Comp_Continue(progfuncs_t *progfuncs)
{
PostCompile();
if (*errorfile)
if (*errorfile && externs->useeditor)
externs->useeditor(progfuncs, errorfile, errorline, comp_nump, comp_parms);
return false;

View file

@ -271,14 +271,14 @@ reeval:
case OP_STORE_FI:
OPB->_int = (int)OPA->_float;
break;
case OP_STORE_I:
OPB->_int = OPA->_int;
break;
case OP_STORE_F:
case OP_STORE_ENT:
case OP_STORE_FLD: // integers
case OP_STORE_S:
case OP_STORE_I:
case OP_STORE_FNC: // pointers
case OP_STORE_P:
OPB->_int = OPA->_int;
break;
case OP_STORE_V:
@ -493,24 +493,36 @@ reeval:
//==================
case OP_IFNOTS:
case OP_IFNOT_S:
RUNAWAYCHECK();
if (!OPA->string || !PR_StringToNative(progfuncs, OPA->string))
st += (sofs)st->b - 1; // offset the s++
break;
case OP_IFNOT_F:
RUNAWAYCHECK();
if (!OPA->_float)
st += (sofs)st->b - 1; // offset the s++
break;
case OP_IFNOT:
RUNAWAYCHECK();
if (!OPA->_int)
st += (sofs)st->b - 1; // offset the s++
break;
case OP_IFS:
case OP_IF_S:
RUNAWAYCHECK();
if (OPA->string && PR_StringToNative(progfuncs, OPA->string))
st += (sofs)st->b - 1; // offset the s++
break;
case OP_IF_F:
RUNAWAYCHECK();
if (OPA->_int)
st += (sofs)st->b - 1; // offset the s++
break;
case OP_IF:
RUNAWAYCHECK();
if (OPA->_int)

View file

@ -109,6 +109,10 @@ void PR_Configure (progfuncs_t *progfuncs, int addressable_size, int max_progs)
edictrun_t *e;
// int a;
#ifdef QCJIT
prinst->usejit = true;
#endif
max_fields_size=0;
fields_size = 0;
progfuncs->stringtable = 0;

View file

@ -207,8 +207,8 @@ enum {
OP_EQ_I,
OP_NE_I,
OP_IFNOTS,
OP_IFS,
OP_IFNOT_S,
OP_IF_S,
OP_NOT_I, //130
@ -229,7 +229,7 @@ enum {
OP_LOADA_FNC,
OP_LOADA_I,
OP_STORE_P,
OP_STORE_P, //152... erm.. wait...
OP_LOAD_P,
OP_LOADP_F,
@ -311,6 +311,9 @@ enum {
OP_SWITCH_I,//hmm.
OP_GLOAD_V,
OP_IF_F,
OP_IFNOT_F,
OP_NUMREALOPS,
/*

View file

@ -408,28 +408,6 @@ char *COM_TrimString(char *str)
return buffer;
}
#ifdef _WIN32
#if (_MSC_VER >= 1400)
//with MSVC 8, use MS extensions
#define snprintf linuxlike_snprintf_vc8
int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...);
#define vsnprintf(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d)
#else
//msvc crap
#define snprintf linuxlike_snprintf
int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...);
#define vsnprintf linuxlike_vsnprintf
int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr);
#endif
#ifdef _MSC_VER
//these are provided so we don't use them
//but mingw has some defines elsewhere and makes gcc moan
#define _vsnprintf unsafe_vsnprintf
#define _snprintf unsafe_snprintf
#endif
#endif
char *EvaluateDebugString(progfuncs_t *progfuncs, char *key)
{
static char buf[256];
@ -526,7 +504,14 @@ char *EvaluateDebugString(progfuncs_t *progfuncs, char *key)
fdef = ED_FindField (progfuncs, assignment);
if (!fdef)
{
snprintf(buf, sizeof(buf), "Can't find field %s\n", assignment);
int l,nl = strlen(assignment);
strcpy(buf, "Can't find field ");
l = strlen(buf);
if (nl > sizeof(buf)-l-2)
nl = sizeof(buf)-l-2;
memcpy(buf+l, assignment, nl);
assignment[l+nl+0] = '\n';
assignment[l+nl+1] = 0;
return buf;
}
*(int *)val = G_INT(fdef->ofs);
@ -552,8 +537,17 @@ char *EvaluateDebugString(progfuncs_t *progfuncs, char *key)
func = ED_FindFunction (progfuncs, s, &i, progsnum);
if (!func)
{
int l,nl = strlen(s);
assignment[-1] = '=';
snprintf(buf, sizeof(buf), "Can't find function %s\n", s);
strcpy(buf, "Can't find field ");
l = strlen(buf);
if (nl > sizeof(buf)-l-2)
nl = sizeof(buf)-l-2;
memcpy(buf+l, assignment, nl);
assignment[l+nl+0] = '\n';
assignment[l+nl+1] = 0;
return buf;
}
*(func_t *)val = (func - pr_progstate[i].functions) | (i<<24);
@ -839,11 +833,19 @@ void PR_ExecuteCode (progfuncs_t *progfuncs, int s)
float *glob;
int fnum = pr_xfunction - pr_functions;
runaway = 100000000;
int fnum;
prinst->continuestatement = -1;
#ifdef QCJIT
if (prinst->usejit)
{
PR_EnterJIT(progfuncs, s);
return;
}
#endif
fnum = pr_xfunction - pr_functions;
runaway = 100000000;
#define PRBOUNDSCHECK
#define RUNAWAYCHECK() \

View file

@ -90,6 +90,11 @@ progsnum_t PR_LoadProgs(progfuncs_t *progfuncs, char *s, int headercrc, builtin_
{
current_progstate->builtins = builtins;
current_progstate->numbuiltins = numbuiltins;
#ifdef QCJIT
if (prinst->usejit)
prinst->usejit = PR_GenerateJit(progfuncs);
#endif
if (oldtype>=0)
PR_SwitchProgs(progfuncs, oldtype);
return a; //we could load it. Yay!

1039
engine/qclib/pr_x86.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,10 @@
typedef unsigned char qbyte;
#include <stdio.h>
#if defined(_M_IX86) || defined(__i386__)
#define QCJIT
#endif
#define DLL_PROG
#ifndef PROGSUSED
#define PROGSUSED
@ -327,7 +331,9 @@ void PR_SetBuiltins(int type);
#define vars(type, name, size) type name[size]
typedef struct prinst_s {
#ifdef QCJIT
pbool usejit;
#endif
char **tempstrings;
int maxtempstrings;
int numtempstrings;

View file

@ -470,11 +470,13 @@ extern pbool keywords_coexist;
extern pbool output_parms;
extern pbool autoprototype;
extern pbool flag_ifstring;
extern pbool flag_iffloat;
extern pbool flag_acc;
extern pbool flag_caseinsensative;
extern pbool flag_laxcasts;
extern pbool flag_hashonly;
extern pbool flag_fasttrackarrays;
extern pbool flag_assume_integer;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;

View file

@ -24,7 +24,7 @@ const unsigned int type_size[12] = {1, //void
1, //entity
1, //field
sizeof(func_t)/4,//function
sizeof(void *)/4,//pointer
1, //pointer (its an int index)
1, //integer
1, //fixme: how big should a variant be?
0, //ev_struct. variable sized.

View file

@ -68,11 +68,13 @@ 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 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.
pbool flag_acc; //reacc like behaviour of src files (finds *.qc in start dir and compiles all in alphabetical order)
pbool flag_caseinsensative; //symbols will be matched to an insensative case if the specified case doesn't exist. This should b usable for any mod
pbool flag_laxcasts; //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
pbool flag_hashonly; //Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile
pbool flag_fasttrackarrays; //Faster arrays, dynamically detected, activated only in supporting engines.
pbool flag_assume_integer; //5 - is that an integer or a float? qcc says float. but we support int too, so maybe we want that instead?
pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation)
pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp.
@ -456,12 +458,12 @@ QCC_opcode_t pr_opcodes[] =
{7, "&", "BITAND_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_float},
{7, "|", "BITOR_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_float},
{7, "&&", "AND_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "||", "OR_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "&&", "AND_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
{7, "||", "OR_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
{7, "&&", "AND_FI", 5, ASSOC_LEFT, &type_float, &type_float, &type_float},
{7, "||", "OR_FI", 5, ASSOC_LEFT, &type_float, &type_float, &type_integer},
{7, "&&", "AND_I", 7, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "||", "OR_I", 7, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "&&", "AND_IF", 7, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
{7, "||", "OR_IF", 7, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
{7, "&&", "AND_FI", 7, ASSOC_LEFT, &type_float, &type_float, &type_float},
{7, "||", "OR_FI", 7, ASSOC_LEFT, &type_float, &type_float, &type_integer},
{7, "!=", "NE_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
{7, "!=", "NE_FI", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer},
@ -496,6 +498,9 @@ QCC_opcode_t pr_opcodes[] =
{7, "<SWITCH_I>", "SWITCH_I", -1, ASSOC_LEFT, &type_void, NULL, &type_void},
{7, "<>", "GLOAD_S", -1, ASSOC_LEFT, &type_float, &type_float, &type_float},
{6, "<IF_F>", "IF_F", -1, ASSOC_RIGHT, &type_float, NULL, &type_void},
{6, "<IFNOT_F>","IFNOT_F", -1, ASSOC_RIGHT, &type_float, NULL, &type_void},
/* emulated ops begin here */
{7, "<>", "OP_EMULATED", -1, ASSOC_LEFT, &type_float, &type_float, &type_float},
@ -571,16 +576,17 @@ pbool OpAssignsToB(unsigned int op)
return true;
return false;
}
pbool OpAssignedTo(QCC_def_t *v, unsigned int op)
/*pbool OpAssignedTo(QCC_def_t *v, unsigned int op)
{
if(OpAssignsToC(op))
{
} else if(OpAssignsToB(op))
}
else if(OpAssignsToB(op))
{
}
return false;
}
*/
#undef ASSOC_RIGHT_RESULT
#define TOP_PRIORITY 7
@ -798,7 +804,13 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] =
NULL
}, { //7
&pr_opcodes[OP_AND],
&pr_opcodes[OP_AND_I],
&pr_opcodes[OP_AND_IF],
&pr_opcodes[OP_AND_FI],
&pr_opcodes[OP_OR],
&pr_opcodes[OP_OR_I],
&pr_opcodes[OP_OR_IF],
&pr_opcodes[OP_OR_FI],
NULL
}
};
@ -895,8 +907,10 @@ pbool QCC_OPCodeValid(QCC_opcode_t *op)
//stores into a pointer (generated from 'ent.field=XXX')
case OP_STOREP_I: //no worse than the other OP_STOREP_X functions
case OP_STOREP_P:
//reads from an entity field
case OP_LOAD_I: //no worse than the other OP_LOAD_X functions.
case OP_LOAD_P:
return true;
//stores into the globals array.
@ -998,17 +1012,22 @@ pbool QCC_OPCodeValid(QCC_opcode_t *op)
case OP_DIVSTOREP_F:
case OP_STORE_IF:
case OP_STORE_FI:
case OP_STORE_P:
case OP_STOREP_IF: // store a value to a pointer
case OP_STOREP_FI:
case OP_IFNOTS:
case OP_IFS:
case OP_IFNOT_S:
case OP_IF_S:
return true;
case OP_IFNOT_F: //added, but not in dp yet
case OP_IF_F:
return false;
case OP_CP_ITOF:
case OP_CP_FTOI:
return false; //DPFIXME: These are not bounds checked at all.
case OP_GLOBALADDRESS:
return false; //DPFIXME: DP will reject these pointers if they are ever used.
return true; //DPFIXME: DP will reject these pointers if they are ever used.
case OP_POINTER_ADD:
return true; //just maths.
@ -1886,8 +1905,10 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
if ((var_a->constant && var_b->constant && !var_a->temp && !var_b->temp) || var_a->ofs == var_b->ofs)
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Result of comparison is constant");
break;
case OP_IFS:
case OP_IFNOTS:
case OP_IF_S:
case OP_IFNOT_S:
case OP_IF_F:
case OP_IFNOT_F:
case OP_IF:
case OP_IFNOT:
// if (var_a->type->type == ev_function && !var_a->temp)
@ -1908,6 +1929,9 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
if (statements[numstatements-1].c == var_a->ofs)
{
static QCC_def_t nvara;
if (statements[numstatements-1].op == OP_NOT_F)
op = &pr_opcodes[OP_IF_F];
else
op = &pr_opcodes[OP_IF];
numstatements--;
QCC_FreeTemp(var_a);
@ -1919,14 +1943,14 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
}
}
}
else if (op - pr_opcodes == OP_IFNOTS)
else if (op - pr_opcodes == OP_IFNOT_F)
{
if (opt_shortenifnots && var_a && statements[numstatements-1].op == OP_NOT_S)
if (opt_shortenifnots && var_a && statements[numstatements-1].op == OP_NOT_F)
{
if (statements[numstatements-1].c == var_a->ofs)
{
static QCC_def_t nvara;
op = &pr_opcodes[OP_IFS];
op = &pr_opcodes[OP_IF_F];
numstatements--;
QCC_FreeTemp(var_a);
memcpy(&nvara, var_a, sizeof(nvara));
@ -1937,7 +1961,25 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
}
}
}
else if (((unsigned) ((op - pr_opcodes) - OP_STORE_F) < 6))
else if (op - pr_opcodes == OP_IFNOT_S)
{
if (opt_shortenifnots && var_a && statements[numstatements-1].op == OP_NOT_S)
{
if (statements[numstatements-1].c == var_a->ofs)
{
static QCC_def_t nvara;
op = &pr_opcodes[OP_IF_S];
numstatements--;
QCC_FreeTemp(var_a);
memcpy(&nvara, var_a, sizeof(nvara));
nvara.ofs = statements[numstatements].a;
var_a = &nvara;
optres_shortenifnots++;
}
}
}
else if (((unsigned) ((op - pr_opcodes) - OP_STORE_F) < 6) || (op-pr_opcodes) == OP_STORE_P)
{
// remove assignments if what should be assigned is the 3rd operand of the previous statement?
// don't if it's a call, callH, switch or case
@ -1977,7 +2019,7 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
{
switch(op - pr_opcodes)
{
case OP_IFS:
case OP_IF_S:
var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 1, false);
numstatements--;
var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_S], var_a, var_c, NULL);
@ -1988,7 +2030,7 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
op = &pr_opcodes[OP_IF];
break;
case OP_IFNOTS:
case OP_IFNOT_S:
var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 1, false);
numstatements--;
var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_S], var_a, var_c, NULL);
@ -1999,6 +2041,28 @@ QCC_def_t *QCC_PR_Statement ( QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var
op = &pr_opcodes[OP_IFNOT];
break;
case OP_IF_F:
var_c = QCC_MakeFloatDef(0);
numstatements--;
var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_F], var_a, var_c, NULL);
statement = &statements[numstatements];
numstatements++;
QCC_FreeTemp(var_a);
op = &pr_opcodes[OP_IF];
break;
case OP_IFNOT_F:
var_c = QCC_MakeFloatDef(0);
numstatements--;
var_a = QCC_PR_Statement(&pr_opcodes[OP_NE_F], var_a, var_c, NULL);
statement = &statements[numstatements];
numstatements++;
QCC_FreeTemp(var_a);
op = &pr_opcodes[OP_IFNOT];
break;
case OP_ADDSTORE_F:
op = &pr_opcodes[OP_ADD_F];
var_c = var_b;
@ -4174,10 +4238,44 @@ reloop:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADA_FNC], d, ao, NULL); //get pointer to precise def.
nd->type = d->type;
break;
case ev_pointer:
if (ao->constant && !G_INT(ao->ofs))
ao->ofs = 0;
if (d->arraysize>1) //use the array
{
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADA_I], d, ao, NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
}
else
{ //dereference the pointer.
switch(newtype->aux_type->type)
{
case ev_pointer:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_I], d, ao, NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
case ev_float:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_F], d, ao, NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
case ev_vector:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_V], d, ao, NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
case ev_integer:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_I], d, ao, NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
default:
QCC_PR_ParseError(ERR_NOVALIDOPCODES, "No op available. Try assembler");
nd = NULL;
break;
}
}
break;
case ev_integer:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADA_I], d, ao, NULL); //get pointer to precise def.
break;
case ev_struct:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADA_I], d, ao, NULL); //get pointer to precise def.
nd->type = d->type;
@ -4302,6 +4400,10 @@ reloop:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_F], d, QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], ao, 0, NULL), NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
case ev_vector:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_V], d, QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], ao, 0, NULL), NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
break;
case ev_integer:
nd = QCC_PR_Statement(&pr_opcodes[OP_LOADP_I], d, QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], ao, 0, NULL), NULL); //get pointer to precise def.
nd->type = d->type->aux_type;
@ -4695,7 +4797,6 @@ QCC_def_t *QCC_PR_Term (void)
if ((unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 || statements[numstatements-1].op == OP_LOAD_I || statements[numstatements-1].op == OP_LOAD_P)
{
statements[numstatements-1].op = OP_ADDRESS;
QCC_PR_ParseWarning(0, "debug: &ent.field");
e->type = QCC_PR_PointerType(e->type);
return e;
}
@ -5011,9 +5112,30 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags)
type_pointer->aux_type->type = e->type->type;
e->type = type_pointer;
}
if ( !simplestore && (unsigned)(statements[numstatements-1].op - OP_LOADP_F) < 7)
if ( !simplestore && (unsigned)(statements[numstatements-1].op - OP_LOADP_F) < 7 && statements[numstatements-1].c == e->ofs)
{
if (!statements[numstatements-1].b)
{
//if the loadp has no offset, remove the instruction and convert the dest of this instruction directly to the pointer's load address
//this kills the add 0.
e->ofs = statements[numstatements-1].a;
numstatements--;
if (e->type->type != ev_pointer)
{
type_pointer->aux_type->type = e->type->type;
e->type = type_pointer;
}
}
else
{
statements[numstatements-1].op = OP_ADD_I;
if (e->type->type != ev_pointer)
{
type_pointer->aux_type->type = e->type->type;
e->type = type_pointer;
}
}
}
if ( !simplestore && statements[numstatements-1].op == OP_LOADP_C && e->ofs == statements[numstatements-1].c)
{
@ -5478,9 +5600,11 @@ void QCC_PR_ParseStatement (void)
}
else if (!typecmp( e->type, type_string) && flag_ifstring) //special case, as strings are now pointers, not offsets from string table
{
QCC_PR_ParseWarning(0, "while (string) can result in bizzare behaviour");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOTS], e, 0, &patch1));
QCC_PR_ParseWarning(WARN_IFSTRING_USED, "while(string) can result in bizzare behaviour");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_S], e, 0, &patch1));
}
else if (!typecmp( e->type, type_float) && flag_iffloat) //special case, as negative 0 is also zero
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_F], e, 0, &patch1));
else
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT], e, 0, &patch1));
}
@ -5628,8 +5752,10 @@ void QCC_PR_ParseStatement (void)
if (!typecmp( e->type, type_string) && flag_ifstring)
{
QCC_PR_ParseWarning(WARN_IFSTRING_USED, "do {} while(string) can result in bizzare behaviour");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFS], e, NULL, &patch2));
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF_S], e, NULL, &patch2));
}
else if (!typecmp( e->type, type_float) && flag_iffloat)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF_F], e, NULL, &patch2));
else
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF], e, NULL, &patch2));
@ -5724,8 +5850,10 @@ void QCC_PR_ParseStatement (void)
if (!typecmp( e->type, type_string) && flag_ifstring)
{
QCC_PR_ParseWarning(WARN_IFSTRING_USED, "if not(string) can result in bizzare behaviour");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFS], e, 0, &patch1));
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF_S], e, 0, &patch1));
}
else if (!typecmp( e->type, type_float) && flag_iffloat)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF_F], e, 0, &patch1));
else
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IF], e, 0, &patch1));
}
@ -5734,8 +5862,10 @@ void QCC_PR_ParseStatement (void)
if (!typecmp( e->type, type_string) && flag_ifstring)
{
QCC_PR_ParseWarning(WARN_IFSTRING_USED, "if (string) can result in bizzare behaviour");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOTS], e, 0, &patch1));
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_S], e, 0, &patch1));
}
else if (!typecmp( e->type, type_float) && flag_iffloat)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_F], e, 0, &patch1));
else
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT], e, 0, &patch1));
}
@ -5999,7 +6129,9 @@ void QCC_PR_ParseStatement (void)
else
{
if (e->type->type == ev_string)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOTS], e, 0, &patch3));
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_S], e, 0, &patch3));
else if (e->type->type == ev_float)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT_F], e, 0, &patch3));
else
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_IFNOT], e, 0, &patch3));
}
@ -7081,11 +7213,16 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type)
// hexenC has void name() : 2;
if (QCC_PR_CheckToken ("#") || QCC_PR_CheckToken (":"))
{
if (pr_token_type != tt_immediate
|| pr_immediate_type != type_float
|| pr_immediate._float != (int)pr_immediate._float)
int binum = 0;
if (pr_token_type == tt_immediate
&& pr_immediate_type == type_float
&& pr_immediate._float == (int)pr_immediate._float)
binum = (int)pr_immediate._float;
else if (pr_token_type == tt_immediate && pr_immediate_type == type_integer)
binum = pr_immediate._int;
else
QCC_PR_ParseError (ERR_BADBUILTINIMMEDIATE, "Bad builtin immediate");
f->builtin = (int)pr_immediate._float;
f->builtin = binum;
QCC_PR_Lex ();
locals_start = locals_end = OFS_PARM0; //hmm...
@ -8912,7 +9049,7 @@ void QCC_PR_ParseDefs (char *classname)
if (d->constant)
{
for (i = 0; i < d->type->size; i++)
G_INT(def->ofs) = G_INT(d->ofs);
G_INT(def->ofs+i) = G_INT(d->ofs+i);
def->constant = !isvar;
def->initialized = 1;
continue;
@ -9399,14 +9536,14 @@ void QCC_PR_ParseDefs (char *classname)
else
def->constant = true;
def->initialized = 1;
if (pr_immediate_type->type != ev_vector)
QCC_PR_ParseError (ERR_BADIMMEDIATETYPE, "wrong immediate type for %s", name);
(((float *)qcc_pr_globals)[def->ofs+0]) = pr_immediate.vector[0];
(((float *)qcc_pr_globals)[def->ofs+1]) = pr_immediate.vector[1];
(((float *)qcc_pr_globals)[def->ofs+2]) = pr_immediate.vector[2];
QCC_PR_Lex ();
if (pr_immediate_type->type != ev_vector)
QCC_PR_ParseError (ERR_BADIMMEDIATETYPE, "wrong immediate type for %s", name);
continue;
}
else

View file

@ -1397,9 +1397,17 @@ void QCC_PR_LexNumber (void)
pr_file_p++;
}
if (flag_assume_integer)
{
pr_immediate_type = type_integer;
pr_immediate._int = num*sign;
}
else
{
pr_immediate_type = type_float;
pr_immediate._float = (float)(num*sign);
}
}
float QCC_PR_LexFloat (void)
@ -2502,11 +2510,11 @@ void QCC_PR_Lex (void)
if ( (c == '.'&&pr_file_p[1] >='0' && pr_file_p[1] <= '9') || (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
{
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
pr_immediate._float = QCC_PR_LexFloat ();
// pr_immediate_type = type_float;
// pr_immediate._float = QCC_PR_LexFloat ();
// pr_token_type = tt_immediate;
// QCC_PR_LexNumber ();
pr_token_type = tt_immediate;
QCC_PR_LexNumber ();
return;
}

View file

@ -224,12 +224,14 @@ compiler_flag_t compiler_flag[] = {
{&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance.
{&writeasm, 0, "wasm", "Dump Assembler", "Writes out a qc.asm which contains all your functions but in assembler. This is a great way to look for bugs in fteqcc, but can also be used to see exactly what your functions turn into, and thus how to optimise statements better."}, //spit out a qc.asm file, containing an assembler dump of the ENTIRE progs. (Doesn't include initialisation of constants)
{&flag_ifstring, FLAG_MIDCOMPILE,"ifstring", "if(string) fix", "Causes if(string) to behave identically to if(string!="") This is most useful with addons of course, but also has adverse effects with FRIK_FILE's fgets, where it becomes impossible to determin the end of the file. In such a case, you can still use asm {IF string 2;RETURN} to detect eof and leave the function."}, //correction for if(string) no-ifstring to get the standard behaviour.
{&flag_iffloat, FLAG_MIDCOMPILE,"iffloat", "if(-0.0) fix", "Fixes certain floating point logic."},
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensativity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_caseinsensative, 0, "caseinsens", "Case insensativity", "Causes fteqcc to become case insensative whilst compiling names. It's generally not advised to use this as it compiles a little more slowly and provides little benefit. However, it is required for full reacc support."}, //symbols will be matched to an insensative case if the specified case doesn't exist. This should b usable for any mod
{&flag_laxcasts, FLAG_MIDCOMPILE,"lax", "Lax type checks", "Disables many errors (generating warnings instead) when function calls or operations refer to two normally incompatible types. This is required for reacc support, and can also allow certain (evil) mods to compile that were originally written for frikqcc."}, //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
{&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"},
{&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions. This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"},
{&flag_fasttrackarrays, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"fastarrays", "fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes only in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to all arrays or none."}, //correction for if(string) no-ifstring to get the standard behaviour.
{&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions (without iffloat also enabled). This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"},
{&flag_fasttrackarrays, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"fastarrays","fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes only in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to all arrays or none."},
{&flag_assume_integer, FLAG_MIDCOMPILE,"assumeint", "Assume Integers", "Numerical constants are assumed to be integers, instead of floats."},
{NULL}
};
@ -3198,7 +3200,7 @@ void QCC_FinishCompile(void)
}
}*/
if (pr_werror && pr_werror)
if (pr_werror && pr_warning_count != 0)
QCC_Error (ERR_PARSEERRORS, "compilation errors");
// write progdefs.h

View file

@ -12,12 +12,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
//builtins and builtin management.
void PF_print (progfuncs_t *prinst, struct globalvars_s *gvars)
void PF_prints (progfuncs_t *prinst, struct globalvars_s *gvars)
{
char *s;
s = prinst->VarString(prinst, 0);
@ -25,9 +26,27 @@ void PF_print (progfuncs_t *prinst, struct globalvars_s *gvars)
printf("%s", s);
}
void PF_printv (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
printf("%f %f %f\n", G_FLOAT(OFS_PARM0+0), G_FLOAT(OFS_PARM0+1), G_FLOAT(OFS_PARM0+2));
}
void PF_printf (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
printf("%f\n", G_FLOAT(OFS_PARM0));
}
void PF_bad (progfuncs_t *prinst, struct globalvars_s *gvars)
{
printf("bad builtin\n");
}
builtin_t builtins[] = {
PF_print,
PF_print
PF_bad,
PF_prints,
PF_printv,
PF_printf
};
@ -36,7 +55,10 @@ builtin_t builtins[] = {
//Called when the qc library has some sort of serious error.
void Sys_Abort(char *s, ...)
{ //quake handles this with a longjmp.
printf("%s", s);
va_list ap;
va_start(ap, s);
vprintf(s, ap);
va_end(ap);
exit(1);
}
//Called when the library has something to say.
@ -109,10 +131,13 @@ void runtest(char *progsname)
ext.Abort = Sys_Abort;
ext.printf = printf;
ext.numglobalbuiltins = sizeof(builtins)/sizeof(builtins[0]);
ext.globalbuiltins = builtins;
pf = InitProgs(&ext);
pf->Configure(pf, 1024*1024, 1); //memory quantity of 1mb. Maximum progs loadable into the instance of 1
//If you support multiple progs types, you should tell the VM the offsets here, via RegisterFieldVar
pn = pf->LoadProgs(pf, progsname, 0, builtins, sizeof(builtins)/sizeof(builtins[0])); //load the progs, don't care about the crc, and use those builtins.
pn = pf->LoadProgs(pf, progsname, 0, NULL, 0); //load the progs, don't care about the crc, and use those builtins.
if (pn < 0)
printf("test: Failed to load progs \"%s\"\n", progsname);
else
@ -185,11 +210,11 @@ int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Invalid arguments!\nPlease run as, for example:\n%s testprogs.dat --srcfile progs.src\nThe first argument is the name of the progs.dat to run, the remaining arguments are the qcc args to use", argv[0]);
printf("Invalid arguments!\nPlease run as, for example:\n%s testprogs.dat -srcfile progs.src\nThe first argument is the name of the progs.dat to run, the remaining arguments are the qcc args to use", argv[0]);
return 0;
}
compile(argc-2, argv+2);
compile(argc-1, argv+1);
runtest(argv[1]);
return 0;