revamp fteqcc a little to cope with a.b.c+=f;f++; more correctly/efficiently.

also fix some preprocessor issues with nexuiz's qc code.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4482 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-09-26 14:36:52 +00:00
parent db3f55f24a
commit d741392ef2
19 changed files with 2982 additions and 1198 deletions

View File

@ -87,6 +87,6 @@ testapp.bin: qcvm.so test.o
$(CC) $(BASE_CFLAGS) -o testapp.bin -O3 $(BASE_LDFLAGS) qcvm.so test.o
tests: testapp.bin
@$(foreach a,$(wildcard tests/*.src), echo TEST: $a; ./testapp.bin progs.dat -srcfile $a; echo; echo)
@$(foreach a,$(wildcard tests/*.src), echo TEST: $a; rm progs.dat; ./testapp.bin progs.dat -srcfile $a; echo; echo)
.PHONY: tests

View File

@ -39,8 +39,18 @@ int QC_strcasecmp (const char *s1, const char *s2);
#ifdef _MSC_VER
#define QC_vsnprintf _vsnprintf
static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vsnprintf (dest, size-1, fmt, args);
va_end (args);
//make sure its terminated.
dest[size-1] = 0;
}
#else
#define QC_vsnprintf vsnprintf
#define QC_snprintfz snprintf
#endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
@ -62,7 +72,7 @@ int SafeOpenWrite (char *filename, int maxsize);
int SafeOpenRead (char *filename);
void SafeRead (int handle, void *buffer, long count);
void SafeWrite (int handle, void *buffer, long count);
void SafeClose(int handle);
pbool SafeClose(int hand);
int SafeSeek(int hand, int ofs, int mode);
void *SafeMalloc (long size);

View File

@ -411,8 +411,8 @@ reeval:
tmpf = OPA->_float;
ptr = QCPOINTER(OPB);
OPC->_vector[0] = (ptr->_vector[0] *= tmpf);
OPC->_vector[0] = (ptr->_vector[1] *= tmpf);
OPC->_vector[0] = (ptr->_vector[2] *= tmpf);
OPC->_vector[1] = (ptr->_vector[1] *= tmpf);
OPC->_vector[2] = (ptr->_vector[2] *= tmpf);
break;
case OP_DIVSTORE_F: // f /= f
@ -824,8 +824,8 @@ reeval:
case OP_GLOBALADDRESS:
OPC->_int = ENGINEPOINTER(&OPA->_int + OPB->_int); /*pointer arithmatic*/
break;
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
OPC->_int = OPA->_int + OPB->_int*4;
case OP_ADD_PIW: //pointer to 32 bit (remember to *3 for vectors)
OPC->_int = OPA->_int + OPB->_int*sizeof(float);
break;
case OP_LOADA_I:
@ -882,7 +882,7 @@ reeval:
pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad pointer read in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name));
}
ptr = QCPOINTERM(OPA->_int + OPB->_int*4);
ptr = QCPOINTERM(i);
OPC->_int = ptr->_int;
break;
@ -948,10 +948,10 @@ reeval:
break;
case OP_BITSET: // b (+) a
case OP_BITSETSTORE_F: // b (+) a
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
break;
case OP_BITSETP: // .b (+) a
case OP_BITSETSTOREP_F: // .b (+) a
if (QCPOINTERWRITEFAIL(OPB))
{
pr_xstatement = st-pr_statements;
@ -960,10 +960,10 @@ reeval:
ptr = QCPOINTER(OPB);
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
break;
case OP_BITCLR: // b (-) a
case OP_BITCLRSTORE_F: // b (-) a
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
break;
case OP_BITCLRP: // .b (-) a
case OP_BITCLRSTOREP_F: // .b (-) a
if (QCPOINTERWRITEFAIL(OPB))
{
pr_xstatement = st-pr_statements;
@ -1118,8 +1118,8 @@ reeval:
case OP_MUL_VI:
tmpi = OPB->_int;
OPC->_vector[0] = OPA->_vector[0] * tmpi;
OPC->_vector[1] = OPA->_vector[0] * tmpi;
OPC->_vector[2] = OPA->_vector[0] * tmpi;
OPC->_vector[1] = OPA->_vector[1] * tmpi;
OPC->_vector[2] = OPA->_vector[2] * tmpi;
break;
case OP_MUL_IV:
tmpi = OPA->_int;

View File

@ -431,6 +431,16 @@ int PDECL PR_InitEnts(pubprogfuncs_t *ppf, int max_ents)
sv_num_edicts = 0;
#if 0
{
int i;
for (i = 0; i < prinst.numfields; i++)
{
printf("%s(%i) %i -> %i\n", prinst.field[i].name, prinst.field[i].type, prinst.field[i].progsofs, prinst.field[i].ofs);
}
}
#endif
max_fields_size = fields_size;
prinst.edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *), "edicttable");

View File

@ -148,10 +148,10 @@ enum qcop_e {
OP_THINKTIME, //87
OP_BITSET, //88 redundant, for h2 compat
OP_BITSETP, //89
OP_BITCLR, //90
OP_BITCLRP, //91
OP_BITSETSTORE_F, //88 redundant, for h2 compat
OP_BITSETSTOREP_F, //89
OP_BITCLRSTORE_F, //90
OP_BITCLRSTOREP_F, //91
OP_RAND0, //92
OP_RAND1, //93
@ -227,7 +227,7 @@ enum qcop_e {
OP_LSHIFT_I,
OP_GLOBALADDRESS,
OP_POINTER_ADD, //32 bit pointers
OP_ADD_PIW, //add B words to A pointer
OP_LOADA_F,
OP_LOADA_V,
@ -328,8 +328,9 @@ enum qcop_e {
These ops are emulated out, always, and are only present in the compiler.
*/
OP_BITSET_I, //220
OP_BITSETP_I,
OP_BITSETSTORE_I, //220
OP_BITSETSTOREP_I,
OP_BITCLRSTORE_I,
OP_MULSTORE_I,
OP_DIVSTORE_I,
@ -338,9 +339,9 @@ enum qcop_e {
OP_MULSTOREP_I,
OP_DIVSTOREP_I,
OP_ADDSTOREP_I,
OP_SUBSTOREP_I,
OP_SUBSTOREP_I, //230
OP_MULSTORE_IF, //230
OP_MULSTORE_IF,
OP_MULSTOREP_IF,
OP_DIVSTORE_IF,
OP_DIVSTOREP_IF,
@ -350,8 +351,8 @@ enum qcop_e {
OP_SUBSTOREP_IF,
OP_MULSTORE_FI,
OP_MULSTOREP_FI,
OP_DIVSTORE_FI, //240
OP_MULSTOREP_FI, //240
OP_DIVSTORE_FI,
OP_DIVSTOREP_FI,
OP_ADDSTORE_FI,
OP_ADDSTOREP_FI,
@ -374,6 +375,10 @@ enum qcop_e {
OP_LT_P,
OP_GT_P,
OP_ANDSTORE_F,
OP_BITCLR_F,
OP_BITCLR_I,
OP_NUMOPS
};

View File

@ -523,7 +523,7 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v
else
QC_snprintfz (line, sizeof(line), "entity %i", val->edict);
if (verbose)
if (verbose && (unsigned)val->edict < (unsigned)sv_num_edicts)
{
struct edict_s *ed = EDICT_NUM(progfuncs, val->edict);
int size = strlen(line);
@ -877,6 +877,7 @@ char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs)
int i;
ddef16_t *def16;
ddef32_t *def32;
int nameofs = 0;
static char line[128];
switch (current_progstate->structtype)
@ -884,23 +885,31 @@ char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs)
case PST_DEFAULT:
case PST_KKQWSV:
def16 = ED_GlobalAtOfs16(progfuncs, ofs);
if (!def16)
sprintf (line,"%i(?""?""?)", ofs);
else
sprintf (line,"%i(%s)", ofs, def16->s_name+progfuncs->funcs.stringtable);
if (def16)
nameofs = def16->s_name;
break;
case PST_QTEST:
case PST_FTE32:
def32 = ED_GlobalAtOfs32(progfuncs, ofs);
if (!def32)
sprintf (line,"%i(?""?""?)", ofs);
else
sprintf (line,"%i(%s)", ofs, def32->s_name+progfuncs->funcs.stringtable);
if (def32)
nameofs = def32->s_name;
break;
default:
Sys_Error("Bad struct type in PR_GlobalStringNoContents");
}
if (nameofs)
sprintf (line,"%i(%s)", ofs, nameofs+progfuncs->funcs.stringtable);
else
{
if (ofs >= OFS_RETURN && ofs < OFS_PARM0)
sprintf (line,"%i(return_%c)", ofs, 'x' + (ofs - OFS_RETURN)%3);
else if (ofs >= OFS_PARM0 && ofs < RESERVED_OFS)
sprintf (line,"%i(parm%i_%c)", ofs, (ofs - OFS_PARM0)/3, 'x' + (ofs - OFS_PARM0)%3);
else
sprintf (line,"%i(?""?""?)", ofs);
}
i = strlen(line);
for ( ; i<20 ; i++)
strcat (line," ");

View File

@ -8,7 +8,7 @@
#define Host_Error Sys_Error
// I put the following here to resolve "undefined reference to `__imp__vsnprintf'" with MinGW64 ~ Moodles
#ifdef _WIN32
#if 0//def _WIN32
#if (_MSC_VER >= 1400)
//with MSVC 8, use MS extensions
#define snprintf linuxlike_snprintf_vc8
@ -150,22 +150,9 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
#if !defined(MINIMAL) && !defined(OMIT_QCC)
if ( (unsigned)op < OP_NUMOPS)
{
int i;
QC_snprintfz (out, outlen, "%s", pr_opcodes[op].name);
QC_snprintfz (out, outlen, "%-12s ", pr_opcodes[op].opname);
outlen -= strlen(out);
out += strlen(out);
QC_snprintfz (out, outlen, " ");
outlen -= 1;
out += 1;
QC_snprintfz (out, outlen, "%s ", pr_opcodes[op].name);
i = strlen(pr_opcodes[op].name);
for ( ; i<10 ; i++)
{
QC_snprintfz (out, outlen, " ");
outlen -= 1;
out += 1;
}
}
else
#endif
@ -175,15 +162,15 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
out += strlen(out);
}
if (op == OP_IF_F || op == OP_IFNOT_F)
if (op == OP_IF_F || op == OP_IFNOT_F || op == OP_IF_I || op == OP_IFNOT_I || op == OP_IF_S || op == OP_IFNOT_S)
{
QC_snprintfz (out, outlen, "%sbranch %i",PR_GlobalStringNoContents(progfuncs, arg[0]),arg[1]);
QC_snprintfz (out, outlen, "%sbranch %i(%i)",PR_GlobalStringNoContents(progfuncs, arg[0]),(short)arg[1], statementnum+(short)arg[0]);
outlen -= strlen(out);
out += strlen(out);
}
else if (op == OP_GOTO)
{
QC_snprintfz (out, outlen, "branch %i",arg[0]);
QC_snprintfz (out, outlen, "branch %i(%i)",(short)arg[0], statementnum+(short)arg[0]);
outlen -= strlen(out);
out += strlen(out);
}
@ -727,7 +714,7 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, char *key)
char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
static char buf[256];
static char buf[8192];
fdef_t *fdef;
eval_t *val;
char *assignment;
@ -1129,7 +1116,7 @@ static char *lastfile = 0;
lastline = externs->useeditor(&progfuncs->funcs, lastfile, lastline, statement, 0, NULL);
if (!pr_progstate[pn].linenums)
return statement;
if (lastline < 0)
if (lastline <= 0)
return -lastline;
if (pr_progstate[pn].linenums[statement] != lastline)
@ -1221,6 +1208,7 @@ void PR_ExecuteCode (progfuncs_t *progfuncs, int s)
if (!--runaway) \
{ \
pr_xstatement = st-pr_statements; \
PR_RunError (&progfuncs->funcs, "runaway loop error\n");\
PR_StackTrace(&progfuncs->funcs); \
printf ("runaway loop error\n"); \
while(pr_depth > prinst.exitdepth) \

View File

@ -347,6 +347,18 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name
prinst.field[fnum].ofs = ofs = prinst.field[i].ofs;
break;
}
if (prinst.field[i].type == ev_vector && prinst.field[i].progsofs+1 == (unsigned)progsofs)
{
// printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+1, prinst.field[i].ofs+1);
prinst.field[fnum].ofs = ofs = prinst.field[i].ofs+1;
break;
}
if (prinst.field[i].type == ev_vector && prinst.field[i].progsofs+2 == (unsigned)progsofs)
{
// printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+2, prinst.field[i].ofs+2);
prinst.field[fnum].ofs = ofs = prinst.field[i].ofs+2;
break;
}
}
}
}

View File

@ -176,7 +176,7 @@ typedef struct
int targetflags; //weather we need to mark the progs as a newer version
char *name;
char *opname;
int priority;
int priority; //FIXME: priority should be done differently...
enum {ASSOC_LEFT, ASSOC_RIGHT, ASSOC_RIGHT_RESULT} associative;
struct QCC_type_s **type_a, **type_b, **type_c;
} QCC_opcode_t;

View File

@ -1,6 +1,8 @@
#ifndef PROGSLIB_H
#define PROGSLIB_H
#include <stdlib.h>
#ifdef _MSC_VER
#define VARGS __cdecl
#endif

View File

@ -331,7 +331,7 @@ typedef struct temp_s {
struct QCC_def_s *lastfunc;
#endif
struct temp_s *next;
pbool used;
int used;
unsigned int size;
} temp_t;
void QCC_PurgeTemps(void);
@ -366,6 +366,23 @@ typedef struct QCC_def_s
temp_t *temp;
} QCC_def_t;
typedef struct
{
enum{
REF_GLOBAL, //(global.ofs) - use vector[2] is an array ref or vector_z
REF_ARRAY, //(global.ofs+wordoffset) - constant offsets should be direct references, variable offsets will generally result in function calls
REF_POINTER,//*(pointerdef+wordindex) - maths...
REF_FIELD, //(entity.field) - reading is a single load, writing requires address+storep
REF_STRING, //"hello"[1]=='e' - special opcodes, or str2chr builtin, or something
} type;
QCC_def_t *base;
QCC_def_t *index;
QCC_type_t *cast; //entity.float is float, not pointer.
int postinc; //+1 or -1
pbool readonly; //for whatever reason, like base being a const
} QCC_ref_t;
//============================================================================
// pr_loc.h -- program local defs
@ -398,7 +415,7 @@ struct QCC_function_s
char *file; // source file with definition
int file_line;
struct QCC_def_s *def;
unsigned int parm_ofs[MAX_PARMS]; // always contiguous, right?
// unsigned int parm_ofs[MAX_PARMS]; // always contiguous, right?
};
@ -503,8 +520,10 @@ extern pbool flag_hashonly;
extern pbool flag_fasttrackarrays;
extern pbool flag_assume_integer;
extern pbool flag_msvcstyle;
extern pbool flag_debugmacros;
extern pbool flag_filetimes;
extern pbool flag_typeexplicit;
extern pbool flag_noboundchecks;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;
@ -635,7 +654,6 @@ enum {
WARN_DEADCODE,
WARN_UNREACHABLECODE,
WARN_NOTSTANDARDBEHAVIOUR,
WARN_INEFFICIENTPLUSPLUS,
WARN_DUPLICATEPRECOMPILER,
WARN_IDENTICALPRECOMPILER,
WARN_FTE_SPECIFIC, //extension that only FTEQCC will have a clue about.
@ -811,6 +829,7 @@ void QCC_PR_NewLine (pbool incomment);
#define GDF_STATIC 2
#define GDF_CONST 4
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool allocate, int arraysize, unsigned int flags);
char *QCC_PR_CheckCompConstTooltip(char *word, char *outstart, char *outend);
void QCC_PR_PrintDefs (void);

View File

@ -775,6 +775,11 @@ struct {
int SafeOpenWrite (char *filename, int maxsize)
{
int i;
if (strlen(filename) >= sizeof(qccfile[0].name))
{
QCC_Error(ERR_TOOMANYOPENFILES, "Filename %s too long", filename);
return -1;
}
for (i = 0; i < MAXQCCFILES; i++)
{
if (!qccfile[i].buff)
@ -848,14 +853,16 @@ int SafeSeek(int hand, int ofs, int mode)
return 0;
}
}
void SafeClose(int hand)
pbool SafeClose(int hand)
{
externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
pbool ret;
ret = externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
// if (qccfile[hand].buffismalloc)
free(qccfile[hand].buff);
// else
// externs->memfree(qccfile[hand].buff);
qccfile[hand].buff = NULL;
return ret;
}
qcc_cachedsourcefile_t *qcc_sourcefile;

File diff suppressed because it is too large Load Diff

View File

@ -6,16 +6,6 @@
#endif
#include "time.h"
#ifdef _WIN64
#ifdef _SDL
#define snprintf linuxlike_snprintf
int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...) LIKEPRINTF(3);
#define vsnprintf linuxlike_vsnprintf
int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr);
//void *__imp__vsnprintf = vsnprintf;
#endif
#endif
#define MEMBERFIELDNAME "__m%s"
#define STRCMP(s1,s2) (((*s1)!=(*s2)) || strcmp(s1+1,s2+1)) //saves about 2-6 out of 120 - expansion of idea from fastqcc
@ -68,13 +58,13 @@ static void Q_strlcpy(char *dest, const char *src, int sizeofdest)
char *pr_punctuation[] =
// longer symbols must be before a shorter partial match
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "++", "--", "->", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "&=", "++", "--", "->", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
char *pr_punctuationremap[] = //a nice bit of evilness.
//(+) -> |=
//-> -> .
//(-) -> &~=
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "++", "--", ".", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "&=", "++", "--", ".", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
// simple types. function types are dynamically allocated
QCC_type_t *type_void;// = {ev_void/*, &def_void*/};
@ -386,12 +376,13 @@ int ParsePrecompilerIf(int level)
return eval;
}
static void QCC_PR_SkipToEndOfLine(void)
//returns true if it was white/comments only. false if there was actual text that was skipped.
static void QCC_PR_SkipToEndOfLine(pbool errorifnonwhite)
{
pbool handlecomments = true;
pbool handleccomments = true;
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
if (*pr_file_p == '/' && pr_file_p[1] == '*' && handlecomments)
if (*pr_file_p == '/' && pr_file_p[1] == '*' && handleccomments)
{
pr_file_p += 2;
while(*pr_file_p)
@ -406,9 +397,9 @@ static void QCC_PR_SkipToEndOfLine(void)
pr_file_p++;
}
}
else if (*pr_file_p == '/' && pr_file_p[1] == '/' && handlecomments)
else if (*pr_file_p == '/' && pr_file_p[1] == '/' && handleccomments)
{
handlecomments = false;
handleccomments = false;
pr_file_p += 2;
}
else if (*pr_file_p == '\\' && pr_file_p[1] == '\r' && pr_file_p[2] == '\n')
@ -416,6 +407,32 @@ static void QCC_PR_SkipToEndOfLine(void)
pr_file_p+=3;
pr_source_line++;
}
else if (*pr_file_p == '\"' && handleccomments)
{
if (errorifnonwhite)
{
errorifnonwhite = false;
QCC_PR_ParseWarning (ERR_UNKNOWNPUCTUATION, "unexpected tokens at end of line");
}
pr_file_p++;
while (*pr_file_p)
{
if (*pr_file_p == '\n')
break; //this text is junk/ignored, so ignore the obvious error here.
else if (*pr_file_p == '\"')
{
pr_file_p++;
break;
}
else if (*pr_file_p == '\\' && pr_file_p[1] == '\"')
pr_file_p+=2; //don't trip on "\"/*"
else if (*pr_file_p == '\\' && pr_file_p[1] == '\\')
pr_file_p+=2; //don't trip on "\\"//"foo
else
pr_file_p++;
//any other \ should be part of the actual string, which we don't care about here
}
}
else if (*pr_file_p == '\\' && pr_file_p[1] == '\n')
{ /*linux endings*/
pr_file_p+=2;
@ -423,7 +440,15 @@ static void QCC_PR_SkipToEndOfLine(void)
pr_source_line++;
}
else
{
if (errorifnonwhite && handleccomments && !qcc_iswhite(*pr_file_p))
{
errorifnonwhite = false;
QCC_PR_ParseWarning(ERR_UNKNOWNPUCTUATION, "unexpected tokens at end of line");
}
pr_file_p++;
}
}
}
/*
@ -456,7 +481,7 @@ pbool QCC_PR_Precompiler(void)
{
pr_file_p = directive;
QCC_PR_ConditionCompilation();
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
}
else if (!strncmp(directive, "undef", 5))
{
@ -468,7 +493,7 @@ pbool QCC_PR_Precompiler(void)
QCC_PR_UndefineName(pr_token);
// QCC_PR_ConditionCompilation();
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
}
else if (!strncmp(directive, "if", 2))
{
@ -502,11 +527,6 @@ pbool QCC_PR_Precompiler(void)
if (ifmode == 2)
{
eval = ParsePrecompilerIf(PPI_TOPLEVEL);
if(*pr_file_p != '\r' && *pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
QCC_PR_ParseError (ERR_NOENDIF, "junk on the end of #if line");
}
}
else
{
@ -521,7 +541,7 @@ pbool QCC_PR_Precompiler(void)
eval = eval?false:true;
}
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
level = 1;
if (eval)
@ -551,12 +571,13 @@ pbool QCC_PR_Precompiler(void)
if (!strncmp(pr_file_p, "else", 4) && level == 1)
{
ifs+=1;
QCC_PR_SkipToEndOfLine();
pr_file_p+=4;
QCC_PR_SkipToEndOfLine(true);
break;
}
}
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(false);
if (level <= 0)
break;
@ -573,7 +594,8 @@ pbool QCC_PR_Precompiler(void)
ifs -= 1;
level = 1;
QCC_PR_SkipToEndOfLine();
pr_file_p = directive+4;
QCC_PR_SkipToEndOfLine(true);
while (1)
{
while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
@ -598,11 +620,13 @@ pbool QCC_PR_Precompiler(void)
if (!strncmp(pr_file_p, "else", 4) && level == 1)
{
ifs+=1;
pr_file_p+=4;
QCC_PR_SkipToEndOfLine(true);
break;
}
}
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(false);
if (level <= 0)
break;
pr_file_p++; //go off the end
@ -611,7 +635,8 @@ pbool QCC_PR_Precompiler(void)
}
else if (!strncmp(directive, "endif", 5))
{
QCC_PR_SkipToEndOfLine();
pr_file_p = directive+5;
QCC_PR_SkipToEndOfLine(true);
if (ifs <= 0)
QCC_PR_ParseError(ERR_NOPRECOMPILERIF, "unmatched #endif");
else
@ -630,7 +655,7 @@ pbool QCC_PR_Precompiler(void)
msg[a] = '\0';
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg);
}
@ -642,21 +667,23 @@ pbool QCC_PR_Precompiler(void)
msg[a-1] = '\0';
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s", msg);
}
else if (!strncmp(directive, "message", 7))
{
pr_file_p = directive+7;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
QCC_PR_SkipToEndOfLine();
printf("#message: %s\n", msg);
if (flag_msvcstyle)
printf ("%s(%i) : #message: %s\n", strings + s_file, pr_source_line, msg);
else
printf ("%s:%i: #message: %s\n", strings + s_file, pr_source_line, msg);
QCC_PR_SkipToEndOfLine(false);
}
else if (!strncmp(directive, "copyright", 9))
{
@ -666,7 +693,7 @@ pbool QCC_PR_Precompiler(void)
msg[a-1] = '\0';
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
if (strlen(msg) >= sizeof(QCC_copyright))
QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
@ -690,10 +717,7 @@ pbool QCC_PR_Precompiler(void)
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
QCC_PR_SkipToEndOfLine(true);
if (ifmode == 0)
QCC_packid = atoi(msg);
@ -715,7 +739,7 @@ pbool QCC_PR_Precompiler(void)
msg[a-1] = '\0';
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
}
else if (!strncmp(directive, "includelist", 11))
{
@ -743,17 +767,18 @@ pbool QCC_PR_Precompiler(void)
continue;
}
if (!strcmp(pr_token, "#endlist"))
{
QCC_PR_SkipToEndOfLine(true);
break;
}
QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir, true);
if (*pr_file_p == '\r')
pr_file_p++;
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
}
QCC_PR_SkipToEndOfLine();
}
else if (!strncmp(directive, "include", 7))
{
@ -792,11 +817,7 @@ pbool QCC_PR_Precompiler(void)
pr_file_p++;
while(*pr_file_p != '\n' && *pr_file_p != '\0' && qcc_iswhitesameline(*pr_file_p))
pr_file_p++;
QCC_PR_SkipToEndOfLine();
QCC_PR_SkipToEndOfLine(true);
}
else if (!strncmp(directive, "datafile", 8))
{
@ -954,7 +975,7 @@ pbool QCC_PR_Precompiler(void)
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);
QCC_PR_ParseWarning(WARN_BADPRAGMA, "pragma %s: unable to change optimisation options 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')
@ -1132,7 +1153,7 @@ pbool QCC_PR_Precompiler(void)
}
}
if (!compiler_flag[f].enabled)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag not recognised");
QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag %s not recognised", qcc_token);
}
}
@ -2295,6 +2316,8 @@ void QCC_PR_ConditionCompilation(void)
int dbuflen;
char *s;
int quote=false;
pbool preprocessorhack = false;
int comment = 0;
CompilerConstant_t *cnst;
QCC_PR_SimpleGetToken ();
@ -2372,12 +2395,36 @@ void QCC_PR_ConditionCompilation(void)
s++;
}
/*
This began as a bug. It is still evil, but its oh so useful.
In C,
#define foobar \
foo\
bar\
moo
becomes foobarmoo, not foo\nbar\nmoo
#define hacks however, require that it becomes
foo\nbar\nmoo
# cannot be used on the first line of the macro, and then is only valid as the first non-white char of the following lines
so if present, the preceeding \\\n and following \\\n must become an actual \n instead of being stripped.
*/
for (exploitcheck = s; *exploitcheck && qcc_iswhite(*exploitcheck); exploitcheck++)
;
if (*exploitcheck == '#')
{
QCC_PR_ParseWarning(WARN_EVILPREPROCESSOR, "preprocessor directive within preprocessor constant %s", cnst->name);
QCC_PR_ParseWarning(WARN_EVILPREPROCESSOR, "preprocessor directive within preprocessor macro %s", cnst->name);
*d++ = '\n';
preprocessorhack = true;
}
else if (preprocessorhack)
{
*d++ = '\n';
preprocessorhack = false;
}
}
}
@ -2656,6 +2703,14 @@ int QCC_PR_CheckCompConst(void)
QCC_PR_IncludeChunkEx(buffer, true, NULL, c);
}
free(buffer);
if (flag_debugmacros)
{
if (flag_msvcstyle)
printf ("%s(%i) : macro %s: %s\n", strings+s_file, pr_source_line, c->name, pr_file_p);
else
printf ("%s:%i: macro %s: %s\n", strings+s_file, pr_source_line, c->name, pr_file_p);
}
}
else
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without argument list");
@ -2763,6 +2818,40 @@ CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def)
return c;
}
char *QCC_PR_CheckCompConstTooltip(char *word, char *outstart, char *outend)
{
int i;
CompilerConstant_t *c = QCC_PR_CheckCompConstDefined(word);
if (c)
{
char *out = outstart;
if (c->numparams >= 0)
{
QC_snprintfz(out, outend-out, "#define %s(", c->name);
out += strlen(out);
for (i = 0; i < c->numparams-1; i++)
{
QC_snprintfz(out, outend-out, "%s,", c->params[i]);
out += strlen(out);
}
if (i < c->numparams)
{
QC_snprintfz(out, outend-out, "%s", c->params[i]);
out += strlen(out);
}
QC_snprintfz(out, outend-out, ")", c->name);
}
else
QC_snprintfz(out, outend-out, "#define %s", c->name);
out += strlen(out);
if (c->value && *c->value)
QC_snprintfz(out, outend-out, "\n%s", c->value);
return outstart;
}
return NULL;
}
//============================================================================
/*
@ -3809,8 +3898,9 @@ QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto)
if (e == ptype)
{
char name[128];
sprintf(name, "ptr to %s", pointsto->name);
e->name = strdup(name);
QC_snprintfz(name, sizeof(name), "ptr to %s", pointsto->name);
e->name = qccHunkAlloc(strlen(name)+1);
strcpy(e->name, name);
}
return e;
}
@ -3818,13 +3908,17 @@ QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto)
{
QCC_type_t *ptype;
char name[128];
sprintf(name, "FIELD_TYPE(%s)", pointsto->name);
QC_snprintfz(name, sizeof(name), "FIELD_TYPE(%s)", pointsto->name);
ptype = QCC_PR_NewType(name, ev_field, false);
ptype->aux_type = pointsto;
ptype->size = ptype->aux_type->size;
return QCC_PR_FindType (ptype);
}
extern char *basictypenames[];
extern QCC_type_t **basictypes[];
QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int arraysize, unsigned int ofs, int referable, unsigned int flags);
pbool type_inlinefunction;
/*newtype=true: creates a new type always
silentfail=true: function is permitted to return NULL if it was not given a type, otherwise never returns NULL
@ -3901,6 +3995,10 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
char *parmname;
int arraysize;
pbool redeclaration;
int basicindex;
QCC_def_t *d;
QCC_type_t *pc;
pbool found = false;
parmname = QCC_PR_ParseName();
classname = qccHunkAlloc(strlen(parmname)+1);
@ -4149,42 +4247,89 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
}
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].optional = false;
parms[numparms].paramname = parmname;
parms[numparms].arraysize = arraysize;
parms[numparms].type = newparm;
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 (basicindex < pp[i].ofs+1) //if we found one with the index
basicindex = pp[i].ofs+1; //make sure we don't union it.
}
}
}
parms[numparms].ofs = basicindex; //ulp, its new
numparms++;
fieldtype = QCC_PR_NewType(parmname, ev_field, false);
fieldtype->aux_type = newparm;
fieldtype->size = newparm->size;
{
QCC_type_t *pc;
QCC_def_t *d;
pc = newt;
d = NULL;
while(pc && !d)
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)
{ //don't go all weird with unioning generic fields
sprintf(membername, "::%s%i", basictypenames[newparm->type], basicindex+1);
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
if (!d)
{
sprintf(membername, "%s::"MEMBERFIELDNAME, pc->name, parmname);
d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, 0);
if (d && typecmp(d->type, fieldtype))
{
char bufc[256];
char bufp[256];
TypeName(((d->type->type==ev_field)?d->type->aux_type:d->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);
break;
}
pc = pc->parentclass;
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST);
for (i = 0; i < newparm->size; i++)
((int *)qcc_pr_globals)[i+d->ofs] = pr.size_fields + i;
pr.size_fields += i;
d->references++; //always referenced, so you can inherit safely.
}
if (d)
continue;
}
//and make sure we can do member::__fname
//actually, that seems pointless.
sprintf(membername, "%s::"MEMBERFIELDNAME, classname, parmname);
QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 0, 0);
// printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, GDF_CONST);
d->references++; //always referenced, so you can inherit safely.
}
if (redeclaration)

View File

@ -9,6 +9,9 @@
#include "qcc.h"
#include "gui.h"
//#define EMBEDDEBUG
void AddSourceFile(char *format, ...);
#ifndef TVM_SETBKCOLOR
#define TVM_SETBKCOLOR (TV_FIRST + 29)
@ -66,13 +69,72 @@ int PDECL QCC_FileSize (const char *fname)
length = ftell(f);
fclose(f);
if (strcmp(progssrcname, fname))
AddSourceFile("%s/%s", progssrcname, fname);
return length;
}
#ifdef AVAIL_ZLIB
#include "../libs/zlib.h"
#endif
pbool PDECL QCC_WriteFile (const char *name, void *data, int len)
{
long length;
FILE *f;
char *ext = strrchr(name, '.');
if (!stricmp(ext, ".gz"))
{
#ifdef AVAIL_ZLIB
pbool okay = true;
char out[1024*8];
z_stream strm = {
data,
len,
0,
out,
sizeof(out),
0,
NULL,
NULL,
NULL,
NULL,
NULL,
Z_BINARY,
0,
0
};
f = fopen(name, "wb");
if (!f)
return false;
deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS|16, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
while(okay && deflate(&strm, Z_FINISH) == Z_OK)
{
if (sizeof(out) - strm.avail_out != fwrite(out, 1, sizeof(out) - strm.avail_out, f))
okay = false;
strm.next_out = out;
strm.avail_out = sizeof(out);
}
if (sizeof(out) - strm.avail_out != fwrite(out, 1, sizeof(out) - strm.avail_out, f))
okay = false;
deflateEnd(&strm);
fclose(f);
if (!okay)
unlink(name);
return okay;
#else
return false;
#endif
}
f = fopen(name, "wb");
if (!f)
return false;
@ -139,6 +201,7 @@ int logprintf(const char *format, ...)
#define MDI_WINDOW_CLASS_NAME "FTEMDIWINDOW"
#define EDIT_WINDOW_CLASS_NAME "FTEEDITWINDOW"
#define OPTIONS_WINDOW_CLASS_NAME "FTEOPTIONSWINDOW"
#define ENGINE_WINDOW_CLASS_NAME "FTEEMBEDDEDWINDOW"
#define EM_GETSCROLLPOS (WM_USER + 221)
#define EM_SETSCROLLPOS (WM_USER + 222)
@ -150,8 +213,12 @@ void GUIPrint(HWND wnd, char *msg);
char finddef[256];
char greptext[256];
char enginebinary[MAX_PATH] = "fteglqw.exe";
char enginebasedir[MAX_PATH] = "../..";
char enginecommandline[8192] = "-game test -window +map start";
void RunCompiler(char *args);
void RunEngine(void);
HINSTANCE ghInstance;
HMODULE richedit;
@ -160,6 +227,7 @@ pbool resetprogssrc; //progs.src was changed, reload project info.
HWND mainwindow;
HWND gamewindow;
HWND mdibox;
HWND outputwindow;
HWND outputbox;
@ -178,15 +246,24 @@ struct{
int washit;
} buttons[] = {
{"Compile"},
{"Edit"},
{"Progs.src"},
#ifdef EMBEDDEBUG
{"Run"},
#endif
{"Options"},
{"Quit"}
};
#define ID_COMPILE 0
#define ID_EDIT 1
#define ID_OPTIONS 2
#define ID_QUIT 3
enum
{
ID_COMPILE = 0,
ID_EDIT,
#ifdef EMBEDDEBUG
ID_RUN,
#endif
ID_OPTIONS,
ID_QUIT
};
#define NUMBUTTONS sizeof(buttons)/sizeof(buttons[0])
@ -197,6 +274,28 @@ void GUI_DialogPrint(char *title, char *text)
MessageBox(mainwindow, text, title, 0);
}
//available in xp+
typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
BOOL (WINAPI * pSetWindowSubclass)(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
LRESULT (WINAPI *pDefSubclassProc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_KEYDOWN)
{
if (wParam == VK_F3)
{
SetFocus(search_name);
return 0;
}
if (wParam == VK_F5)
{
RunEngine();
return 0;
}
}
return pDefSubclassProc(hWnd, uMsg, wParam, lParam);
}
HWND CreateAnEditControl(HWND parent)
{
HWND newc;
@ -263,6 +362,18 @@ HWND CreateAnEditControl(HWND parent)
SendMessage(newc, EM_EXLIMITTEXT, 0, 1<<20);
}
if (!pDefSubclassProc || !pSetWindowSubclass)
{
HMODULE lib = LoadLibrary("comctl32.dll");
if (lib)
{
pDefSubclassProc = (void*)GetProcAddress(lib, "DefSubclassProc");
pSetWindowSubclass = (void*)GetProcAddress(lib, "SetWindowSubclass");
}
}
if (pDefSubclassProc && pSetWindowSubclass)
pSetWindowSubclass(newc, MySubclassWndProc, 0, (DWORD_PTR)parent);
ShowWindow(newc, SW_SHOW);
return newc;
@ -301,6 +412,9 @@ enum {
IDI_O_APPLY,
IDI_O_TARGET,
IDI_O_SYNTAX_HIGHLIGHTING,
IDI_O_ENGINE,
IDI_O_ENGINEBASEDIR,
IDI_O_ENGINECOMMANDLINE,
IDM_FIRSTCHILD
};
@ -485,6 +599,7 @@ char *WordUnderCursor(editor_t *editor, char *buffer, int buffersize)
}
char *GetTooltipText(editor_t *editor)
{
static char buffer[1024];
char wordbuf[256];
char *defname;
defname = WordUnderCursor(editor, wordbuf, sizeof(wordbuf));
@ -493,10 +608,13 @@ char *GetTooltipText(editor_t *editor)
else if (globalstable.numbuckets)
{
QCC_def_t *def;
char *macro = QCC_PR_CheckCompConstTooltip(defname, buffer, buffer + sizeof(buffer));
if (*macro)
return macro;
def = QCC_PR_GetDef(NULL, defname, NULL, false, 0, false);
if (def)
{
static char buffer[1024];
char typebuf[1024];
//note function argument names do not persist beyond the function def. we might be able to read the function's localdefs for them, but that's unreliable/broken with builtins where they're most needed.
if (def->comment)
@ -510,7 +628,7 @@ char *GetTooltipText(editor_t *editor)
else
return NULL;//"Type info not available. Compile first.";
}
static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message,
static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
RECT rect;
@ -1136,7 +1254,7 @@ void EditFile(char *name, int line)
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)EditorWndProc;
wndclass.lpfnWndProc = EditorWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = ghInstance;
@ -1280,12 +1398,240 @@ pbool EditorModified(editor_t *e)
//the engine thread simply sits waiting for responses from the engine
typedef struct
{
int pipeclosed;
DWORD tid;
HWND window;
HANDLE thread;
HANDLE pipefromengine;
HANDLE pipetoengine;
} enginewindow_t;
void EngineCommand(enginewindow_t *ctx, char *message, ...)
{
//qcresume - resume running
//qcinto - singlestep. execute-with-debugging child functions
//qcover - singlestep. execute-without-debugging child functions
//qcout - singlestep. leave current function and enter parent.
//qcbreak "$loc" - set breakpoint
//qcwatch "$var" - set watchpoint
//qcstack - force-report stack trace
va_list va;
char finalmessage[1024];
va_start (va, message);
vsnprintf (finalmessage, sizeof(finalmessage)-1, message, va);
va_end (va);
if (ctx->pipetoengine)
{
DWORD written = 0;
WriteFile(ctx->pipetoengine, finalmessage, strlen(finalmessage), &written, NULL);
}
}
unsigned int WINAPI threadwrapper(void *args)
{
enginewindow_t *ctx = args;
{
PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo;
SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE};
char cmdline[8192];
_snprintf(cmdline, sizeof(cmdline), "\"%s\" %s -plugin qcdebug", enginebinary, enginecommandline);
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
startinfo.hStdInput = NULL;
startinfo.hStdError = NULL;
startinfo.hStdOutput = NULL;
startinfo.dwFlags |= STARTF_USESTDHANDLES;
//create pipes for the stdin/stdout.
CreatePipe(&ctx->pipefromengine, &startinfo.hStdOutput, &pipesec, 0);
CreatePipe(&startinfo.hStdInput, &ctx->pipetoengine, &pipesec, 0);
SetHandleInformation(ctx->pipefromengine, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(ctx->pipetoengine, HANDLE_FLAG_INHERIT, 0);
EngineCommand(ctx, "vid_recenter %i %i %i %i %#p\n", 0, 0, 640, 480, (void*)ctx->window);
CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, enginebasedir, &startinfo, &childinfo);
//these ends of the pipes were inherited by now, so we can discard them in the caller.
CloseHandle(startinfo.hStdOutput);
CloseHandle(startinfo.hStdInput);
}
{
char buffer[8192];
unsigned int bufoffs = 0;
char *nl;
while(1)
{
DWORD avail;
//use Peek so we can read exactly how much there is without blocking, so we don't have to read byte-by-byte.
PeekNamedPipe(ctx->pipefromengine, NULL, 0, NULL, &avail, NULL);
if (!avail)
avail = 1; //so we do actually sleep.
if (avail > sizeof(buffer)-1 - bufoffs)
avail = sizeof(buffer)-1 - bufoffs;
if (!ReadFile(ctx->pipefromengine, buffer + bufoffs, avail, &avail, NULL) || !avail)
{
break;
}
bufoffs += avail;
while(1)
{
buffer[bufoffs] = 0;
nl = strchr(buffer, '\n');
if (nl)
{
*nl = 0;
if (!strncmp(buffer, "status ", 7))
{
//SetWindowText(ctx->window, buffer+7);
}
else if (!strcmp(buffer, "status"))
{
//SetWindowText(ctx->window, "Engine");
}
else if (!strcmp(buffer, "curserver"))
{
//not interesting
}
else if (!strncmp(buffer, "qcstack ", 6))
{
//qcvm is giving a stack trace
//stack reset
//stack "$func" "$loc"
//local $depth
}
else if (!strncmp(buffer, "qcstep ", 5))
{
//qcvm stepped to the line specified, often dupes
//qcstep "$location"
EngineCommand(ctx, "qcstep\n"); //moves on to the next statement
}
else if (!strncmp(buffer, "qcvalue ", 6))
{
//qcvalue "$variableformula" "$value"
}
else if (!strncmp(buffer, "qcreloaded ", 6))
{
//so we can resend any breakpoint commands
//qcreloaded "$vmname" "$progsname"
EngineCommand(ctx, "qcresume\n");
}
else
{
//handle anything else we need to handle here
printf("Unknown command from engine \"%s\"\n", buffer);
}
nl++;
bufoffs -= (nl-buffer);
memmove(buffer, nl, bufoffs);
}
else
break;
}
}
}
ctx->pipeclosed = true;
PostMessage(ctx->window, WM_CLOSE, 0, 0); //and tell the owning window to try to close it again
return 0;
}
static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
enginewindow_t *e;
switch (message)
{
case WM_CREATE:
e = malloc(sizeof(*e));
memset(e, 0, sizeof(*e));
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)e);
e->window = hWnd;
e->thread = (HANDLE)CreateThread(NULL, 0, threadwrapper, e, 0, &e->tid);
break;
case WM_SIZE:
{
RECT r;
e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
GetClientRect(hWnd, &r);
EngineCommand(e, "vid_recenter %i %i %i %i %#p\n", r.left, r.top, r.right-r.left, r.bottom - r.top, (void*)e->window);
}
goto gdefault;
case WM_CLOSE:
e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (e->pipeclosed)
{
DestroyWindow(hWnd);
return 0;
}
//ask the engine to quit
EngineCommand(e, "quit force\n");
break;
case WM_DESTROY:
e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
EngineCommand(e, "quit force\n"); //just in case
WaitForSingleObject(e->thread, INFINITE);
CloseHandle(e->thread);
free(e);
if (hWnd == gamewindow)
gamewindow = NULL;
break;
default:
gdefault:
return DefMDIChildProc(hWnd,message,wParam,lParam);
}
return 0;
}
void RunEngine(void)
{
if (!gamewindow)
{
WNDCLASS wndclass;
MDICREATESTRUCT mcs;
memset(&wndclass, 0, sizeof(wndclass));
wndclass.style = 0;
wndclass.lpfnWndProc = EngineWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = ghInstance;
wndclass.hIcon = 0;
wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
wndclass.hbrBackground = (void *)COLOR_WINDOW;
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = ENGINE_WINDOW_CLASS_NAME;
RegisterClass(&wndclass);
memset(&mcs, 0, sizeof(mcs));
mcs.szClass = ENGINE_WINDOW_CLASS_NAME;
mcs.szTitle = "Debug";
mcs.hOwner = ghInstance;
mcs.x = CW_USEDEFAULT;
mcs.y = CW_USEDEFAULT;
mcs.cx = 640;
mcs.cy = 480;
mcs.style = WS_OVERLAPPEDWINDOW;
mcs.lParam = 0;
gamewindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs);
ShowWindow(gamewindow, SW_SHOW);
}
else
{
enginewindow_t *e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(gamewindow, GWLP_USERDATA);
}
SendMessage(mdibox, WM_MDIACTIVATE, (WPARAM)gamewindow, 0);
}
@ -1295,7 +1641,12 @@ HWND nokeywords_coexistitem;
HWND autoprototype_item;
HWND autohighlight_item;
HWND extraparmsitem;
static LONG CALLBACK OptionsWndProc(HWND hWnd,UINT message,
#ifdef EMBEDDEBUG
HWND w_enginebinary;
HWND w_enginebasedir;
HWND w_enginecommandline;
#endif
static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
int i;
@ -1332,6 +1683,11 @@ static LONG CALLBACK OptionsWndProc(HWND hWnd,UINT message,
}
fl_autohighlight = Button_GetCheck(autohighlight_item);
Edit_GetText(extraparmsitem, parameters, sizeof(parameters)-1);
#ifdef EMBEDDEBUG
Edit_GetText(w_enginebinary, enginebinary, sizeof(enginebinary)-1);
Edit_GetText(w_enginebasedir, enginebasedir, sizeof(enginebasedir)-1);
Edit_GetText(w_enginecommandline, enginecommandline, sizeof(enginecommandline)-1);
#endif
if (wParam == IDI_O_USE)
buttons[ID_COMPILE].washit = true;
@ -1531,7 +1887,7 @@ void OptionsDialog(void)
memset(&wndclass, 0, sizeof(wndclass));
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)OptionsWndProc;
wndclass.lpfnWndProc = OptionsWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = ghInstance;
@ -1589,7 +1945,7 @@ void OptionsDialog(void)
r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, ghInstance, NULL);
subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
0, 0, 400, height-48, optionsmenu, NULL, ghInstance, NULL);
0, 0, 400, height-40*4-8, optionsmenu, NULL, ghInstance, NULL);
num = 0;
for (i = 0; optimisations[i].enabled; i++)
@ -1621,46 +1977,77 @@ void OptionsDialog(void)
CreateWindow("BUTTON","O0",
WS_CHILD | WS_VISIBLE,
8,height-88,64,32,
8,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL0,
ghInstance,
NULL);
CreateWindow("BUTTON","O1",
WS_CHILD | WS_VISIBLE,
8+64,height-88,64,32,
8+64,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL1,
ghInstance,
NULL);
CreateWindow("BUTTON","O2",
WS_CHILD | WS_VISIBLE,
8+64*2,height-88,64,32,
8+64*2,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL2,
ghInstance,
NULL);
CreateWindow("BUTTON","O3",
WS_CHILD | WS_VISIBLE,
8+64*3,height-88,64,32,
8+64*3,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL3,
ghInstance,
NULL);
CreateWindow("BUTTON","Debug",
WS_CHILD | WS_VISIBLE,
8+64*4,height-88,64,32,
8+64*4,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_DEBUG,
ghInstance,
NULL);
CreateWindow("BUTTON","Default",
WS_CHILD | WS_VISIBLE,
8+64*5,height-88,64,32,
8+64*5,height-40*5-8,64,32,
optionsmenu,
(HMENU)IDI_O_DEFAULT,
ghInstance,
NULL);
#ifdef EMBEDDEBUG
w_enginebinary = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT",
enginebinary,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30*3, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINE,
ghInstance,
NULL);
w_enginebasedir = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT",
enginebasedir,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30*2, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINEBASEDIR,
ghInstance,
NULL);
w_enginecommandline = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT",
enginecommandline,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINECOMMANDLINE,
ghInstance,
NULL);
#endif
CreateWindow("BUTTON","Apply",
WS_CHILD | WS_VISIBLE,
8,height-40,64,32,
@ -1780,7 +2167,7 @@ void OptionsDialog(void)
static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
int width;
@ -1854,7 +2241,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
}
break;
case WM_CTLCOLORBTN:
return GetSysColorBrush(COLOR_HIGHLIGHT);//COLOR_BACKGROUND;
return (LRESULT)GetSysColorBrush(COLOR_HIGHLIGHT);//COLOR_BACKGROUND;
case WM_DESTROY:
mainwindow = NULL;
break;
@ -1879,6 +2266,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
SetWindowPos(buttons[i].hwnd, NULL, width*i, rect.bottom-rect.top - 32, width, 32, 0);
}
break;
// goto gdefault;
case WM_PAINT:
hdc=BeginPaint(hWnd,(LPPAINTSTRUCT)&ps);
@ -1920,7 +2308,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
GenericMenu(wParam);
break;
}
break;
goto gdefault;
case WM_NOTIFY:
if (lParam)
{
@ -1966,6 +2354,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
}
}
default:
gdefault:
if (mdibox)
return DefFrameProc(hWnd,mdibox,message,wParam,lParam);
else
@ -1974,7 +2363,7 @@ static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
return 0;
}
static LONG CALLBACK OutputWindowProc(HWND hWnd,UINT message,
static LRESULT CALLBACK OutputWindowProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
RECT rect;
@ -2074,6 +2463,11 @@ int GUIprintf(const char *msg, ...)
va_start (argptr,msg);
args = QC_vsnprintf (buf,sizeof(buf)-1, msg,argptr);
va_end (argptr);
buf[sizeof(buf)-5] = '.';
buf[sizeof(buf)-4] = '.';
buf[sizeof(buf)-3] = '.';
buf[sizeof(buf)-2] = '\n';
buf[sizeof(buf)-1] = 0;
printf("%s", buf);
if (logfile)
@ -2225,7 +2619,14 @@ void RunCompiler(char *args)
argc = GUI_BuildParms(args, argv);
CompileParams(&funcs, true, argc, argv);
if (CompileParams(&funcs, true, argc, argv))
{
if (gamewindow)
{
enginewindow_t *e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(gamewindow, GWLP_USERDATA);
EngineCommand(e, "restart\n");
}
}
if (logfile)
fclose(logfile);
@ -2243,7 +2644,7 @@ void CreateOutputWindow(void)
if (!outputwindow)
{
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)OutputWindowProc;
wndclass.lpfnWndProc = OutputWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = ghInstance;
@ -2264,8 +2665,7 @@ void CreateOutputWindow(void)
mcs.style = WS_OVERLAPPEDWINDOW;
mcs.lParam = 0;
outputwindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0,
(LONG_PTR) (LPMDICREATESTRUCT) &mcs);
outputwindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs);
ShowWindow(outputwindow, SW_SHOW);
}
@ -2355,9 +2755,11 @@ void AddSourceFile(char *format, ...)
item.item.state = TVIS_EXPANDED;
item.item.stateMask = TVIS_EXPANDED;
item.item.mask = TVIF_TEXT|TVIF_STATE;
while(slash = strchr(item.item.pszText, '/'))
while(item.item.pszText)
{
*slash = '\0';
slash = strchr(item.item.pszText, '/');
if (slash)
*slash++ = '\0';
item.hParent = TreeView_GetChild(projecttree, item.hParent);
do
{
@ -2379,9 +2781,8 @@ void AddSourceFile(char *format, ...)
}
else pi = item.hParent;
item.item.pszText = slash+1;
item.item.pszText = slash;
}
SendMessage(projecttree,TVM_INSERTITEM,0,(LPARAM)&item);
}
//progssrcname should already have been set.
@ -2418,6 +2819,7 @@ void SetProgsSrc(void)
pr_file_p = QCC_COM_Parse(buffer);
if (*qcc_token == '#')
{
AddSourceFile("%s", progssrcname);
free(buffer); //aaaahhh! newstyle!
return;
}
@ -2528,7 +2930,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
resetprogssrc = true;
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.lpfnWndProc = MainWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = ghInstance;
@ -2579,7 +2981,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
WS_CHILD | WS_VISIBLE,
0, 0, 5, 5,
mainwindow,
(HMENU)(i+1),
(HMENU)(LONG_PTR)(i+1),
ghInstance,
NULL);
}
@ -2698,6 +3100,13 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
buttons[ID_EDIT].washit = false;
EditFile(progssrcname, -1);
}
#ifdef EMBEDDEBUG
if (buttons[ID_RUN].washit)
{
buttons[ID_RUN].washit = false;
RunEngine();
}
#endif
if (buttons[ID_OPTIONS].washit)
{
buttons[ID_OPTIONS].washit = false;

View File

@ -20,7 +20,7 @@ extern int optres_test2;
int writeasm;
pbool verbose;
pbool qcc_nopragmaoptimise;
extern unsigned int locals_marshalled;
pbool QCC_PR_SimpleGetToken (void);
void QCC_PR_LexWhitespace (void);
@ -220,8 +220,8 @@ optimisations_t optimisations[] =
//level 0 = no optimisations
//level 1 = size optimisations
//level 2 = speed optimisations
//level 3 = dodgy optimisations.
//level 4 = experimental... must be used explicitly
//level 3 = unsafe optimisations (they break multiprogs).
//level 4 = experimental or extreeme features... 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."},
@ -229,8 +229,8 @@ optimisations_t optimisations[] =
{&opt_constant_names, "c", 2, FLAG_KILLSDEBUGGERS, "constant_names", "This optimisation strips out the names of constants (but not strings) from your progs, resulting in smaller files. It makes decompilers leave out names or fabricate numerical ones."},
{&opt_constant_names_strings, "cs", 3, FLAG_KILLSDEBUGGERS, "constant_names_strings", "This optimisation strips out the names of string constants from your progs. However, this can break addons, so don't use it in those cases."},
{&opt_dupconstdefs, "d", 1, FLAG_ASDEFAULT, "dupconstdefs", "This will merge definitions of constants which are the same value. Pay extra attention to assignment to constant warnings."},
{&opt_noduplicatestrings, "s", 1, 0, "noduplicatestrings", "This will compact the string table that is stored in the progs. It will be considerably smaller with this."},
{&opt_locals, "l", 1, FLAG_KILLSDEBUGGERS, "locals", "Strips out local names and definitions. This makes it REALLY hard to decompile"},
{&opt_noduplicatestrings, "s", 1, FLAG_ASDEFAULT, "noduplicatestrings", "This will compact the string table that is stored in the progs. It will be considerably smaller with this."},
{&opt_locals, "l", 1, FLAG_KILLSDEBUGGERS, "locals", "Strips out local names and definitions. Most decompiles will break on this."},
{&opt_function_names, "n", 1, FLAG_KILLSDEBUGGERS, "function_names", "This strips out the names of functions which are never called. Doesn't make much of an impact though."},
{&opt_filenames, "f", 1, FLAG_KILLSDEBUGGERS, "filenames", "This strips out the filenames of the progs. This can confuse the really old decompilers, but is nothing to the more recent ones."},
{&opt_unreferenced, "u", 1, FLAG_ASDEFAULT, "unreferenced", "Removes the entries of unreferenced variables. Doesn't make a difference in well maintained code."},
@ -240,9 +240,9 @@ optimisations_t optimisations[] =
{&opt_return_only, "ro", 3, FLAG_KILLSDEBUGGERS, "return_only", "Functions ending in a return statement do not need a done statement at the end of the function. This can confuse some decompilers, making functions appear larger than they were."},
{&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", 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_stripfunctions, "sf", 3, FLAG_KILLSDEBUGGERS, "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", 2, FLAG_ASDEFAULT|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}
};
@ -297,12 +297,14 @@ compiler_flag_t compiler_flag[] = {
{&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 (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_msvcstyle, FLAG_MIDCOMPILE,"msvcstyle", "MSVC-style errors", "Generates warning and error messages in a format that msvc understands, to facilitate ide integration."},
{&flag_debugmacros, FLAG_MIDCOMPILE,"flag_debugmacros", "Verbose Macro Expansion", "Print out the contents of macros that are expanded. This can help look inside macros that are expanded and is especially handy if people are using preprocessor hacks."},
{&flag_filetimes, 0, "filetimes", "Check Filetimes", "Recompiles the progs only if the file times are modified."},
{&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."},
{&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
{&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
{&flag_noboundchecks, FLAG_MIDCOMPILE,"noboundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
{NULL}
};
@ -632,9 +634,10 @@ void QCC_UnmarshalLocals(void)
unsigned int maxo;
int i;
extern int tempsused;
QCC_def_t *largestfunc = NULL;
ofs = numpr_globals;
maxo = ofs;
maxo = ofs+locals_marshalled;
for (def = pr.def_head.next ; def ; def = def->next)
{
@ -659,7 +662,8 @@ void QCC_UnmarshalLocals(void)
if (numpr_globals > MAX_REGS)
QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals are in use to unmarshal all locals");
printf("Total of %i locals, %i temps\n", maxo-ofs, tempsused);
if (verbose)
printf("Total of %i locals, %i temps\n", maxo-ofs, tempsused);
}
CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
@ -844,12 +848,15 @@ pbool QCC_WriteData (int crc)
{
int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED;
pr_scope = def->scope;
if (QCC_PR_Warning(wt, strings + def->s_file, def->s_line, "%s no references.", def->name))
if (strcmp(def->name, "IMMEDIATE"))
{
if (!warnedunref)
if (QCC_PR_Warning(wt, strings + def->s_file, def->s_line, "%s no references.", def->name))
{
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "You can use the noref prefix or pragma to silence this message.");
warnedunref = true;
if (!warnedunref)
{
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "You can use the noref prefix or pragma to silence this message.");
warnedunref = true;
}
}
}
pr_scope = NULL;
@ -885,7 +892,7 @@ pbool QCC_WriteData (int crc)
// numfunctions++;
}
else if (def->type->type == ev_field && def->constant && (!def->scope || def->isstatic))
else if (def->type->type == ev_field && def->constant && (!def->scope || def->isstatic || def->initialized))
{
if (numfielddefs >= MAX_FIELDS)
QCC_PR_ParseError(0, "Too many fields. Limit is %u\n", MAX_FIELDS);
@ -1447,31 +1454,57 @@ strofs = (strofs+3)&~3;
SafeSeek (h, 0, SEEK_SET);
SafeWrite (h, &progs, sizeof(progs));
SafeClose (h);
if (!SafeClose (h))
{
printf("Error while writing output %s\n", destfile);
return false;
}
printf("Compile finished: %s\n", destfile);
if (!debugtarget)
{
if (opt_filenames)
{
printf("Not writing linenumbers file due to conflicting optimisation\n");
printf("Not writing linenumbers file due to conflicting optimisation (try -Ono-f)\n");
}
else
{
unsigned int lnotype = *(unsigned int*)"LNOF";
unsigned int version = 1;
StripExtension(destfile);
strcat(destfile, ".lno");
if (verbose)
printf("Writing %s for debugging\n", destfile);
h = SafeOpenWrite (destfile, 2*1024*1024);
SafeWrite (h, &lnotype, sizeof(int));
SafeWrite (h, &version, sizeof(int));
SafeWrite (h, &numglobaldefs, sizeof(int));
SafeWrite (h, &numpr_globals, sizeof(int));
SafeWrite (h, &numfielddefs, sizeof(int));
SafeWrite (h, &numstatements, sizeof(int));
SafeWrite (h, statement_linenums, numstatements*sizeof(int));
SafeClose (h);
pbool gz = false;
while(1)
{
char *ext;
ext = strrchr(destfile, '.');
if (strchr(ext, '/') || strchr(ext, '\\'))
break;
if (!stricmp(ext, ".gz"))
{
*ext = 0;
gz = true;
continue;
}
*ext = 0;
break;
}
if (strlen(destfile) < sizeof(destfile)-(4+3))
{
strcat(destfile, ".lno");
if (gz)
strcat(destfile, ".gz");
if (verbose)
printf("Writing %s for debugging\n", destfile);
h = SafeOpenWrite (destfile, 2*1024*1024);
SafeWrite (h, &lnotype, sizeof(int));
SafeWrite (h, &version, sizeof(int));
SafeWrite (h, &numglobaldefs, sizeof(int));
SafeWrite (h, &numpr_globals, sizeof(int));
SafeWrite (h, &numfielddefs, sizeof(int));
SafeWrite (h, &numstatements, sizeof(int));
SafeWrite (h, statement_linenums, numstatements*sizeof(int));
SafeClose (h);
}
}
}
@ -2740,7 +2773,18 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
if (!stricmp(myargv[i]+2, "all"))
{
for (j = 0; j < ERR_PARSEERRORS; j++)
qccwarningaction[j] = WA_WARN;
if (qccwarningaction[j] == WA_IGNORE)
{
if (j == WARN_FIXEDRETURNVALUECONFLICT)
continue;
qccwarningaction[j] = WA_WARN;
}
}
else if (!stricmp(myargv[i]+2, "extra"))
{
for (j = 0; j < ERR_PARSEERRORS; j++)
if (qccwarningaction[j] == WA_IGNORE)
qccwarningaction[j] = WA_WARN;
}
else if (!stricmp(myargv[i]+2, "none"))
{
@ -2908,7 +2952,6 @@ void QCC_SetDefaultProperties (void)
qccwarningaction[WARN_FIXEDRETURNVALUECONFLICT] = WA_IGNORE;
qccwarningaction[WARN_EXTRAPRECACHE] = WA_IGNORE;
qccwarningaction[WARN_DEADCODE] = WA_IGNORE;
qccwarningaction[WARN_INEFFICIENTPLUSPLUS] = WA_IGNORE;
qccwarningaction[WARN_FTE_SPECIFIC] = WA_IGNORE;
qccwarningaction[WARN_EXTENSION_USED] = WA_IGNORE;
qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE;
@ -3020,6 +3063,7 @@ void QCC_main (int argc, char **argv) //as part of the quake engine
myargc = argc;
myargv = argv;
pr_scope = NULL;
locals_marshalled = 0;
qcc_compileactive = true;
@ -3613,7 +3657,7 @@ void QCC_FinishCompile(void)
printf("numtemps %i\n", numtemps);
}
if (!flag_msvcstyle)
printf("%i warnings\n", pr_warning_count);
printf("Done. %i warnings\n", pr_warning_count);
}
qcc_compileactive = false;

View File

@ -6,12 +6,12 @@
#ifdef AVAIL_ZLIB
#ifdef _WIN32
#define ZEXPORT VARGS
#include "../libs/zlib.h"
#include <zlib.h>
#ifdef _WIN64
# pragma comment (lib, "../libs/zlib64.lib")
//# pragma comment (lib, "../libs/zlib64.lib")
#else
# pragma comment (lib, "../libs/zlib.lib")
//# pragma comment (lib, "../libs/zlib.lib")
#endif
#else
#include <zlib.h>
@ -92,12 +92,12 @@ int SafeSeek(int hand, int ofs, int mode);
int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle)
{
int i;
if (method == 0) //copy
if (method == 0) //copy, allows a lame pass-through.
{
SafeWrite(handle, in, len);
return len;
}
else if (method == 1) //xor encryption
else if (method == 1) //xor encryption, not secure. maybe useful for the string table.
{
for (i = 0; i < len; i++)
in[i] = in[i] ^ 0xA5;

View File

@ -7,7 +7,7 @@
#define MAX_PARMS 8
// I put the following here to resolve "undefined reference to `__imp__vsnprintf'" with MinGW64 ~ Moodles
#ifdef _WIN32
#if 0//def _WIN32
#if (_MSC_VER >= 1400)
//with MSVC 8, use MS extensions
#define snprintf linuxlike_snprintf_vc8

View File

@ -18,7 +18,7 @@
//builtins and builtin management.
void PF_prints (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
void PF_puts (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
{
char *s;
s = prinst->VarString(prinst, 0);
@ -26,16 +26,378 @@ void PF_prints (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
printf("%s", s);
}
void PF_printv (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void PF_putv (pubprogfuncs_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 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void PF_putf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
printf("%f\n", G_FLOAT(OFS_PARM0));
}
#ifdef _WIN32
#define Q_snprintfz _snprintf
#define Q_vsnprintf _vsnprintf
#else
#define Q_snprintfz snprintf
#define Q_vsnprintf vsnprintf
#endif
char *va(char *format, ...)
{
va_list argptr;
static char string[1024];
va_start (argptr, format);
Q_vsnprintf (string, sizeof(string), format,argptr);
va_end (argptr);
return string;
}
void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, char *s, int firstarg, char *outbuf, int outbuflen)
{
const char *s0;
char *o = outbuf, *end = outbuf + outbuflen, *err;
int width, precision, thisarg, flags;
char formatbuf[16];
char *f;
int argpos = firstarg;
int isfloat;
static int dummyivec[3] = {0, 0, 0};
static float dummyvec[3] = {0, 0, 0};
#define PRINTF_ALTERNATE 1
#define PRINTF_ZEROPAD 2
#define PRINTF_LEFT 4
#define PRINTF_SPACEPOSITIVE 8
#define PRINTF_SIGNPOSITIVE 16
formatbuf[0] = '%';
#define GETARG_FLOAT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_VECTOR(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
#define GETARG_INT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_INT(OFS_PARM0 + 3 * (a))) : 0)
#define GETARG_INTVECTOR(a) (((a)>=firstarg && (a)<prinst->callargc) ? ((int*) G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec)
#define GETARG_STRING(a) (((a)>=firstarg && (a)<prinst->callargc) ? (PR_GetStringOfs(prinst, OFS_PARM0 + 3 * (a))) : "")
for(;;)
{
s0 = s;
switch(*s)
{
case 0:
goto finished;
case '%':
++s;
if(*s == '%')
goto verbatim;
// complete directive format:
// %3$*1$.*2$ld
width = -1;
precision = -1;
thisarg = -1;
flags = 0;
isfloat = -1;
// is number following?
if(*s >= '0' && *s <= '9')
{
width = strtol(s, &err, 10);
if(!err)
{
printf("PF_sprintf: bad format string: %s\n", s0);
goto finished;
}
if(*err == '$')
{
thisarg = width + (firstarg-1);
width = -1;
s = err + 1;
}
else
{
if(*s == '0')
{
flags |= PRINTF_ZEROPAD;
if(width == 0)
width = -1; // it was just a flag
}
s = err;
}
}
if(width < 0)
{
for(;;)
{
switch(*s)
{
case '#': flags |= PRINTF_ALTERNATE; break;
case '0': flags |= PRINTF_ZEROPAD; break;
case '-': flags |= PRINTF_LEFT; break;
case ' ': flags |= PRINTF_SPACEPOSITIVE; break;
case '+': flags |= PRINTF_SIGNPOSITIVE; break;
default:
goto noflags;
}
++s;
}
noflags:
if(*s == '*')
{
++s;
if(*s >= '0' && *s <= '9')
{
width = strtol(s, &err, 10);
if(!err || *err != '$')
{
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
s = err + 1;
}
else
width = argpos++;
width = GETARG_FLOAT(width);
if(width < 0)
{
flags |= PRINTF_LEFT;
width = -width;
}
}
else if(*s >= '0' && *s <= '9')
{
width = strtol(s, &err, 10);
if(!err)
{
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
s = err;
if(width < 0)
{
flags |= PRINTF_LEFT;
width = -width;
}
}
// otherwise width stays -1
}
if(*s == '.')
{
++s;
if(*s == '*')
{
++s;
if(*s >= '0' && *s <= '9')
{
precision = strtol(s, &err, 10);
if(!err || *err != '$')
{
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
s = err + 1;
}
else
precision = argpos++;
precision = GETARG_FLOAT(precision);
}
else if(*s >= '0' && *s <= '9')
{
precision = strtol(s, &err, 10);
if(!err)
{
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
s = err;
}
else
{
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
}
for(;;)
{
switch(*s)
{
case 'h': isfloat = 1; break;
case 'l': isfloat = 0; break;
case 'L': isfloat = 0; break;
case 'j': break;
case 'z': break;
case 't': break;
default:
goto nolength;
}
++s;
}
nolength:
// now s points to the final directive char and is no longer changed
if (*s == 'p' || *s == 'P')
{
//%p is slightly different from %x.
//always 8-bytes wide with 0 padding, always ints.
flags |= PRINTF_ZEROPAD;
if (width < 0) width = 8;
if (isfloat < 0) isfloat = 0;
}
else if (*s == 'i')
{
//%i defaults to ints, not floats.
if(isfloat < 0) isfloat = 0;
}
//assume floats, not ints.
if(isfloat < 0)
isfloat = 1;
if(thisarg < 0)
thisarg = argpos++;
if(o < end - 1)
{
f = &formatbuf[1];
if(*s != 's' && *s != 'c')
if(flags & PRINTF_ALTERNATE) *f++ = '#';
if(flags & PRINTF_ZEROPAD) *f++ = '0';
if(flags & PRINTF_LEFT) *f++ = '-';
if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' ';
if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+';
*f++ = '*';
if(precision >= 0)
{
*f++ = '.';
*f++ = '*';
}
if (*s == 'p')
*f++ = 'x';
else if (*s == 'P')
*f++ = 'X';
else
*f++ = *s;
*f++ = 0;
if(width < 0) // not set
width = 0;
switch(*s)
{
case 'd': case 'i':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
o += strlen(o);
break;
case 'o': case 'u': case 'x': case 'X': case 'p': case 'P':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
o += strlen(o);
break;
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
o += strlen(o);
break;
case 'v': case 'V':
f[-2] += 'g' - 'v';
if(precision < 0) // not set
Q_snprintfz(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
width, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
width, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
width, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
);
else
Q_snprintfz(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
);
o += strlen(o);
break;
case 'c':
//UTF-8-FIXME: figure it out yourself
// if(flags & PRINTF_ALTERNATE)
{
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
o += strlen(o);
}
/* else
{
unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg));
char charbuf16[16];
const char *buf = u8_encodech(c, NULL, charbuf16);
if(!buf)
buf = "";
if(precision < 0) // not set
precision = end - o - 1;
o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision);
}
*/ break;
case 's':
//UTF-8-FIXME: figure it out yourself
// if(flags & PRINTF_ALTERNATE)
{
if(precision < 0) // not set
Q_snprintfz(o, end - o, formatbuf, width, GETARG_STRING(thisarg));
else
Q_snprintfz(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
o += strlen(o);
}
/* else
{
if(precision < 0) // not set
precision = end - o - 1;
o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision);
}
*/ break;
default:
printf("PF_sprintf: invalid format string: %s\n", s0);
goto finished;
}
}
++s;
break;
default:
verbatim:
if(o < end - 1)
*o++ = *s;
s++;
break;
}
}
finished:
*o = 0;
}
void PF_printf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char outbuf[4096];
PF_sprintf_internal(prinst, pr_globals, PR_GetStringOfs(prinst, OFS_PARM0), 1, outbuf, sizeof(outbuf));
printf("%s", outbuf);
}
void PF_spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
struct edict_s *ed;
ed = ED_Alloc(prinst);
pr_globals = PR_globals(prinst, PR_CURRENT);
RETURN_EDICT(prinst, ed);
}
void PF_bad (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
{
@ -44,9 +406,11 @@ void PF_bad (pubprogfuncs_t *prinst, struct globalvars_s *gvars)
builtin_t builtins[] = {
PF_bad,
PF_prints,
PF_printv,
PF_printf
PF_puts,
PF_putv,
PF_putf,
PF_printf,
PF_spawn
};