1
0
Fork 0
forked from fte/fteqw

Add support for char/short/bitfields. Fix up some other stuff for better C compat.

This commit is contained in:
Shpoike 2024-12-12 13:13:12 +00:00
parent 0650610667
commit affb96a3b3
11 changed files with 1334 additions and 425 deletions

View file

@ -1259,6 +1259,19 @@ ELSE()
#SET(INSTALLTARGS ${INSTALLTARGS} httpserver)
ENDIF()
SET(FTE_TOOL_QCVM false CACHE BOOL "Compile standalone qcvm.")
IF(FTE_TOOL_QCVM)
ADD_EXECUTABLE(qcvm
engine/qclib/test.c
engine/qclib/hash.c
${FTE_QCVM_FILES}
)
SET_TARGET_PROPERTIES(qcvm PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON}")
TARGET_LINK_LIBRARIES(qcvm ${FTEQCC_LIBS} ${SYS_LIBS})
SET(INSTALLTARGS ${INSTALLTARGS} qcvm)
ENDIF()
SET(FTE_TOOL_QCC true CACHE BOOL "Compile commandline qc compiler.")
IF(FTE_TOOL_QCC)
ADD_EXECUTABLE(fteqcc

View file

@ -468,7 +468,7 @@ reeval:
ptr = QCPOINTERM(i);
*(unsigned char *)ptr = (char)OPA->_float;
break;
case OP_STOREP_B: //store (byte) character in a string
case OP_STOREP_I8: //store (byte) character in a string
i = OPB->_int + (OPC->_int)*sizeof(pbyte);
errorif (QCPOINTERWRITEFAIL(i, sizeof(pbyte)))
{
@ -483,6 +483,21 @@ reeval:
ptr = QCPOINTERM(i);
*(pbyte *)ptr = (pbyte)OPA->_int;
break;
case OP_STOREP_I16: //store short to a pointer
i = OPB->_int + (OPC->_int)*sizeof(short);
errorif (QCPOINTERWRITEFAIL(i, sizeof(short)))
{
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(short), sizeof(short))))
{
if (i == -1)
break;
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
}
}
else
ptr = QCPOINTERM(i);
*(short *)ptr = (short)OPA->_int;
break;
case OP_STOREF_F:
case OP_STOREF_I:
@ -1106,7 +1121,7 @@ reeval:
ptr = QCPOINTERM(i);
OPC->_float = *(unsigned char *)ptr;
break;
case OP_LOADP_B: //load character from a string/pointer
case OP_LOADP_U8: //load character from a string/pointer
i = (unsigned int)OPA->_int + (int)OPB->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(pbyte)))
{
@ -1124,6 +1139,60 @@ reeval:
ptr = QCPOINTERM(i);
OPC->_int = *(pbyte *)ptr;
break;
case OP_LOADP_I8: //load character from a string/pointer
i = (unsigned int)OPA->_int + (int)OPB->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(pbyte)))
{
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int, sizeof(pbyte))))
{
if (i == -1)
{
OPC->_int = 0;
break;
}
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
}
}
else
ptr = QCPOINTERM(i);
OPC->_int = *(char *)ptr;
break;
case OP_LOADP_U16: //load character from a string/pointer
i = (unsigned int)OPA->_int + (int)OPB->_int*2;
errorif (QCPOINTERREADFAIL(i, sizeof(short)))
{
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int*2, sizeof(short))))
{
if (i == -1)
{
OPC->_int = 0;
break;
}
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
}
}
else
ptr = QCPOINTERM(i);
OPC->_int = *(unsigned short *)ptr;
break;
case OP_LOADP_I16: //load character from a string/pointer
i = (unsigned int)OPA->_int + (int)OPB->_int*2;
errorif (QCPOINTERREADFAIL(i, sizeof(short)))
{
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int*2, sizeof(short))))
{
if (i == -1)
{
OPC->_int = 0;
break;
}
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
}
}
else
ptr = QCPOINTERM(i);
OPC->_int = *(short *)ptr;
break;
case OP_LOADP_I:
case OP_LOADP_F:
case OP_LOADP_FLD:
@ -1653,6 +1722,8 @@ reeval:
case OP_CONV_FI64: OPC->i64 = OPA->_float; break;
case OP_CONV_I64D: OPC->_double = OPA->i64; break;
case OP_CONV_DI64: OPC->i64 = OPA->_double; break;
case OP_CONV_U64D: OPC->_double = OPA->u64; break;
case OP_CONV_DU64: OPC->u64 = OPA->_double; break;
case OP_ADD_D: OPC->_double = OPA->_double + OPB->_double; break;
case OP_SUB_D: OPC->_double = OPA->_double - OPB->_double; break;
case OP_MUL_D: OPC->_double = OPA->_double * OPB->_double; break;
@ -1662,8 +1733,11 @@ reeval:
case OP_EQ_D: OPC->_int = OPA->_double == OPB->_double; break;
case OP_NE_D: OPC->_int = OPA->_double != OPB->_double; break;
case OP_BITEXTEND_I: OPC->_int = ( signed int)(OPA->_int << (32-(OPB->_uint&0xff)-(OPB->_uint>>8))) >> (32-(OPB->_uint&0xff)); break; //shift it up and down. should sign extend.
case OP_BITEXTEND_U: OPC->_uint = (unsigned int)(OPA->_uint << (32-(OPB->_uint&0xff)-(OPB->_uint>>8))) >> (32-(OPB->_uint&0xff)); break; //shift it up and down. should clear the bits.
case OP_BITCOPY_I: i=((1<<(OPB->_uint&0xff))-1);OPC->_int=(OPC->_int&~(i<<(OPB->_uint>>8)))|(((OPA->_int&i)<<(OPB->_uint>>8)));break; //replaces the specified bits (uses the same format bitextend uses to select its input to extend)
case OP_CONV_UF: OPC->_float = OPA->_uint; break;
case OP_CONV_FU: OPC->_uint = OPA->_float; break;
case OP_UNUSED:
case OP_POP:

View file

@ -339,8 +339,8 @@ enum qcop_e {
OP_STOREF_I, //1 non-string reference/int
//r5744+
OP_STOREP_B,//((char*)b)[(int)c] = (int)a
OP_LOADP_B, //(int)c = *(char*)
OP_STOREP_I8, //((char*)b)[(int)c] = (int)a
OP_LOADP_U8, //(int)c = *(unsigned char*)
//r5768+
//opcodes for 32bit uints
@ -397,6 +397,18 @@ enum qcop_e {
OP_EQ_D,
OP_NE_D,
//r6614+
OP_STOREP_I16, //((short*)b)[(int)c] = (int)a
OP_LOADP_I16, //(int)c = *(signed short*)a (sign extends)
OP_LOADP_U16, //(unsigned int)c = *(unsigned short*)a
OP_LOADP_I8, //(unsigned int)c = *(signed char*)a (sign extends)
OP_BITEXTEND_I, //sign extend (for signed bitfields)
OP_BITEXTEND_U, //zero extend (for unsigned bitfields)
OP_BITCOPY_I, //copy lower bits from the input to some part of the output
OP_CONV_UF, //OPC.f=(float)OPA.i -- 0xffffffffu*0.5=0 otherwise.
OP_CONV_FU, //OPC.i=(int)OPA.f
OP_CONV_U64D, //OPC.d=(double)OPA.u64 -- useful mostly so decompilers don't do weird stuff.
OP_CONV_DU64, //OPC.u64=(uint64_t)OPA.d
OP_NUMREALOPS,
@ -531,8 +543,8 @@ enum qcop_e {
//uint64 opcodes. they match the int32 ones so emulation is basically swapping them over.
OP_BITNOT_I64, //BITXOR ~0
OP_BITCLR_I64,
OP_GE_I64, //LT_I64
OP_GT_I64, //LE_I64
OP_GE_I64, //LE_I64
OP_GT_I64, //LT_I64
OP_ADD_U64,
OP_SUB_U64,
@ -544,8 +556,8 @@ enum qcop_e {
OP_BITNOT_U64, //BITXOR ~0
OP_BITCLR_U64,
OP_LSHIFT_U64I,
OP_GE_U64, //LT_U64
OP_GT_U64, //LE_U64
OP_GE_U64, //LE_U64
OP_GT_U64, //LT_U64
OP_EQ_U64,
OP_NE_U64,
@ -557,6 +569,8 @@ enum qcop_e {
OP_BITCLR_D,
OP_LSHIFT_DI,
OP_RSHIFT_DI,
OP_GE_D, //LE_D
OP_GT_D, //LT_D
OP_WSTATE, //for the 'w' part of CWSTATE. will probably never be used, but hey, hexen2...
@ -618,7 +632,12 @@ typedef struct statement32_s
typedef struct
{
struct QCC_def_s *sym;
unsigned int ofs;
union
{
unsigned int ofs;
// unsigned int bofs;
signed int jumpofs;
};
struct QCC_type_s *cast; //the entire sref is considered null if there is no cast, although it *MAY* have an ofs specified if its part of a jump instruction
} QCC_sref_t;
typedef struct qcc_statement_s

View file

@ -562,6 +562,7 @@ static int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int
}
prinst.pr_xfunction = f;
prinst.spushed = 0;
return f->first_statement - 1; // offset the s++
}
@ -1911,6 +1912,7 @@ typedef struct {
int fnum;
int progsnum;
int statement;
int spushed;
} qcthreadstack_t;
typedef struct qcthread_s {
int fstackdepth;
@ -1947,6 +1949,7 @@ struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf)
thread->fstack[i-ed].fnum = prinst.pr_stack[i].f - pr_progstate[prinst.pr_stack[i].progsnum].functions;
thread->fstack[i-ed].progsnum = prinst.pr_stack[i].progsnum;
thread->fstack[i-ed].statement = prinst.pr_stack[i].s;
thread->fstack[i-ed].spushed = prinst.pr_stack[i].pushed;
if (i+1 == prinst.pr_depth)
f = prinst.pr_xfunction;
@ -1996,7 +1999,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
mfunction_t *f, *oldf;
int i,l,ls, olds;
int i,l,ls, olds, oldp;
progsnum_t initial_progs;
int oldexitdepth;
int *glob;
@ -2033,12 +2036,14 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
prinst.pr_stack[prinst.pr_depth].f = prinst.pr_xfunction;
prinst.pr_stack[prinst.pr_depth].s = prinst.pr_xstatement;
prinst.pr_stack[prinst.pr_depth].progsnum = initial_progs;
prinst.pr_stack[prinst.pr_depth].pushed = prinst.spushed;
}
else
{
prinst.pr_stack[prinst.pr_depth].progsnum = thread->fstack[i].progsnum;
prinst.pr_stack[prinst.pr_depth].f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
prinst.pr_stack[prinst.pr_depth].s = thread->fstack[i].statement;
prinst.pr_stack[prinst.pr_depth].pushed = thread->fstack[i].spushed;
}
if (i+1 == thread->fstackdepth)
@ -2080,6 +2085,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
// PR_EnterFunction (progfuncs, f, initial_progs);
oldf = prinst.pr_xfunction;
olds = prinst.pr_xstatement;
oldp = prinst.spushed;
prinst.pr_xfunction = f;
s = thread->xstatement;
@ -2098,6 +2104,7 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
prinst.exitdepth = oldexitdepth;
prinst.pr_xfunction = oldf;
prinst.pr_xstatement = olds;
prinst.spushed = oldp;
}
void PDECL PR_AbortStack (pubprogfuncs_t *ppf)

View file

@ -95,7 +95,8 @@ ev_union, //not really sure why this is separate from struct
ev_accessor,//some weird type to provide class-like functions over a basic type.
ev_enum, //just a numeric type
ev_typedef, //so typedefs can refer to their original type (primarily for structs).
ev_boolean, //exists to optimise if(-0) workarounds. engine just sees int/float.
ev_boolean, //exists to optimise if(-0) workarounds. engine just sees int/float. uses parentclass
ev_bitfld, //erk... structs only... converted to their parentclass on read.
} etype_t;
enum {
DEBUG_TRACE_OFF, //debugging should be off.

View file

@ -66,6 +66,12 @@ extern progfuncs_t *qccprogfuncs;
#define LIKEPRINTF(x)
#endif
#if __STDC_VERSION__ >= 199901L
#define qc_inlinestatic static inline
#else
#define qc_inlinestatic static
#endif
void *qccHunkAlloc(size_t mem);
void qccClearHunk(void);
@ -373,7 +379,8 @@ struct QCC_typeparam_s
pbool optional:1; //argument may safely be omitted, for builtin functions. for qc functions use the defltvalue instead.
pbool isvirtual:1; //const, with implicit initialisation only. valid for structs
unsigned char out; //0=in,1==inout,2=out
unsigned int ofs; //FIXME: make byte offsets, for bytes/shorts.
unsigned int ofs; //word offset.
unsigned int bitofs; //for bitfields (and chars/shorts).
unsigned int arraysize;
char *paramname;
};
@ -403,6 +410,8 @@ typedef struct QCC_type_s
pbool typedefed:1; //name is in the typenames list.
pbool vargs:1; //function has vargs
pbool vargcount:1; //function has special varg count param
unsigned int bits;//valid for bitfields (and structs).
unsigned int align:7;
const char *name;
const char *aname;
@ -487,6 +496,7 @@ struct temp_s {
unsigned int size;
struct QCC_function_s *lastfunc;
unsigned int lastline;
unsigned int laststatement;
};
extern size_t tempsused;
@ -506,6 +516,7 @@ typedef struct
} type;
QCC_sref_t base;
unsigned int bitofs; //for bitfields.
QCC_sref_t index;
QCC_type_t *cast; //entity.float is float, not pointer.
struct accessor_s *accessor; //the accessor field of base that we're trying to use
@ -526,7 +537,7 @@ extern int QCC_packid;
extern const unsigned int type_size[];
//extern QCC_def_t *def_for_type[9];
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_invalid, *type_variant, *type_floatfield;
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_sint8, *type_uint8, *type_sint16, *type_uint16, *type_integer, *type_uint, *type_int64, *type_uint64, *type_invalid, *type_variant, *type_floatfield;
extern char *basictypenames[];
struct QCC_function_s
@ -769,7 +780,7 @@ void QCC_PR_Lex (void);
QCC_type_t *QCC_PR_NewType (const char *name, int basictype, pbool typedefed); //note: name must be hunk/immediate
QCC_type_t *QCC_PointerTypeTo(QCC_type_t *type);
QCC_type_t *QCC_GenArrayType(QCC_type_t *type, unsigned int arraysize);
QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail);
QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail, pbool ignoreptr);
QCC_sref_t QCC_PR_ParseDefaultInitialiser(QCC_type_t *type);
extern pbool type_inlinefunction;
QCC_type_t *QCC_TypeForName(const char *name);
@ -777,7 +788,7 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype);
QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype);
QCC_type_t *QCC_PR_GenFunctionType (QCC_type_t *rettype, struct QCC_typeparam_s *args, int numargs);
char *QCC_PR_ParseName (void);
struct QCC_typeparam_s *QCC_PR_FindStructMember(QCC_type_t *t, const char *membername, unsigned int *out_ofs);
struct QCC_typeparam_s *QCC_PR_FindStructMember(QCC_type_t *t, const char *membername, unsigned int *out_ofs, unsigned int *out_bitofs);
QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto);
const char *QCC_VarAtOffset(QCC_sref_t ref);

View file

@ -39,6 +39,7 @@ const unsigned int type_size[] = {1, //void
0, //ev_enum...
0, //ev_typedef
1, //ev_bool...
0, //bitfld...
};
char *basictypenames[] = {
@ -60,7 +61,9 @@ char *basictypenames[] = {
"union",
"accessor",
"enum",
"bool"
"typedef",
"bool",
"bitfield",
};
/*

File diff suppressed because it is too large Load diff

View file

@ -93,9 +93,13 @@ QCC_type_t *type_field; //.void
QCC_type_t *type_function; //void()
QCC_type_t *type_floatfunction; //float()
QCC_type_t *type_pointer; //??? * - careful with this one
QCC_type_t *type_sint8; //char - these small types are technically ev_bitfield, but typedefed and aligned.
QCC_type_t *type_uint8; //unsigned char
QCC_type_t *type_sint16; //short
QCC_type_t *type_uint16; //unsigned short
QCC_type_t *type_integer; //int32
QCC_type_t *type_uint; //uint32
QCC_type_t *type_int64; //int64
QCC_type_t *type_int64; //int64
QCC_type_t *type_uint64; //uint64
QCC_type_t *type_variant; //__variant
QCC_type_t *type_invalid; //technically void, but shouldn't really ever be used.
@ -1611,8 +1615,33 @@ int QCC_PR_LexEscapedCodepoint(void)
c = '\\';
else if (c == '\'')
c = '\'';
else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud).
c = 0xe012 + c - '0';
else if (c >= '0' && c <= '9')
{
if (flag_qcfuncs)
c = 0xe012 + c - '0'; //WARNING: This is not an octal code, but uses 'yellow' numbers instead (as on hud).
else //C compat
{
int d = c, base = 8;
c = 0;
if (d >= '0' && d < '0'+base)
c = c*base + (d - '0');
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code \\%c", d);
d = (unsigned char)*pr_file_p++;
if (d >= '0' && d < '0'+base)
c = c*base + (d - '0');
else
pr_file_p --; //oops. only one char valid...
d = (unsigned char)*pr_file_p++;
if (d >= '0' && d < '0'+base)
c = c*base + (d - '0');
else
pr_file_p --; //oops. only twoish chars valid...
}
}
else if (c == '\r')
{ //sigh
c = *pr_file_p++;
@ -2081,6 +2110,7 @@ static void QCC_PR_LexNumber (void)
}
else if (c == 'f' || c == 'F')
{
pr_immediate_type = type_float;
pr_file_p++;
break;
}
@ -2139,7 +2169,7 @@ static void QCC_PR_LexNumber (void)
{ //length suffix was first.
//long-long?
if (*pr_file_p == c)
pr_token[tokenlen++] = *pr_file_p++;
islong++, pr_token[tokenlen++] = *pr_file_p++;
//check for signed suffix...
c = *pr_file_p;
isunsigned = (c == 'u')||(c=='U');
@ -2157,13 +2187,13 @@ static void QCC_PR_LexNumber (void)
islong = true;
//long-long?
if (*pr_file_p == c)
pr_token[tokenlen++] = *pr_file_p++;
islong++, pr_token[tokenlen++] = *pr_file_p++;
}
}
pr_token[tokenlen++] = 0;
num *= sign;
if (islong)
{
if (islong >= (flag_ILP32?2:1))
{ //enough longs for our 64bit type.
pr_immediate_type = (isunsigned)?type_uint64:type_int64;
pr_immediate.i64 = num;
}
@ -2190,7 +2220,16 @@ static void QCC_PR_LexNumber (void)
{
//float f = num;
if (flag_assume_integer)// || (base != 10 && sign > 0 && (long long)f != (long long)num))
pr_immediate_type = type_integer;
{
if (num > UINT64_C(0x7fffffffffffffff))
pr_immediate_type = type_uint64;
else if (num > 0xffffffffu)
pr_immediate_type = type_int64;
else if (num > 0x7fffffffu)
pr_immediate_type = type_uint;
else
pr_immediate_type = type_integer;
}
else if (flag_qccx && base == 16)
{
pr_immediate_type = type_float;
@ -2200,9 +2239,10 @@ static void QCC_PR_LexNumber (void)
pr_immediate_type = type_float;
}
if (pr_immediate_type == type_integer)
if (pr_immediate_type == type_int64 || pr_immediate_type == type_uint64)
pr_immediate.i64 = num*sign;
else if (pr_immediate_type == type_integer || pr_immediate_type == type_uint)
{
pr_immediate_type = type_integer;
qccxhex:
pr_immediate._int = num*sign;
@ -3376,12 +3416,18 @@ static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t
}
if (!strcmp(constname, "__LINE__"))
{
QC_snprintfz(retbuf, retbufsize, "%i", pr_source_line);
int line = pr_source_line;
if (currentchunk && currentchunk->cnst) //if we're in a macro, use the line the macro was on.
line = currentchunk->currentlinenumber;
QC_snprintfz(retbuf, retbufsize, "%i", line);
return retbuf;
}
if (!strcmp(constname, "__LINESTR__"))
{
QC_snprintfz(retbuf, retbufsize, "\"%i\"", pr_source_line);
int line = pr_source_line;
if (currentchunk && currentchunk->cnst) //if we're in a macro, use the line the macro was on.
line = currentchunk->currentlinenumber;
QC_snprintfz(retbuf, retbufsize, "\"%i\"", line);
return retbuf;
}
if (!strcmp(constname, "__FUNC__") || !strcmp(constname, "__func__"))
@ -4252,7 +4298,17 @@ Gets the next token
void QCC_PR_Expect (const char *string)
{
if (STRCMP (string, pr_token))
QCC_PR_ParseError (ERR_EXPECTED, "expected %s%s%s, found %s%s%s", col_location, string, col_none, col_name, pr_token, col_none);
{
if (pr_token_type == tt_immediate && pr_immediate_type == type_string)
{
if (pr_immediate_strlen > 32)
QCC_PR_ParseError (ERR_EXPECTED, "expected %s%s%s, found string immediate", col_location, string, col_none);
else
QCC_PR_ParseError (ERR_EXPECTED, "expected %s%s%s, found %s\"%s\"%s", col_location, string, col_none, col_name, pr_token, col_none);
}
else
QCC_PR_ParseError (ERR_EXPECTED, "expected %s%s%s, found %s%s%s", col_location, string, col_none, col_name, pr_token, col_none);
}
QCC_PR_Lex ();
}
#endif
@ -4530,7 +4586,7 @@ static int typecmp_strict(QCC_type_t *a, QCC_type_t *b)
if (a->vargcount != b->vargcount)
return 1;
if (a->size != b->size)
if (a->size != b->size || a->bits != b->bits || a->align != b->align)
return 1;
if (a->accessors != b->accessors)
@ -4579,7 +4635,7 @@ int typecmp(QCC_type_t *a, QCC_type_t *b)
if (a->vargcount != b->vargcount)
return 1;
if (a->size != b->size)
if (a->size != b->size || a->bits != b->bits)
return 1;
if ((a->type == ev_entity && a->parentclass) || a->type == ev_struct || a->type == ev_union)
@ -4957,6 +5013,10 @@ void QCC_PR_SkipToSemicolon (void)
} while (pr_token_type != tt_eof);
}
qc_inlinestatic QCC_eval_t *QCC_SRef_Data(QCC_sref_t ref)
{
return (QCC_eval_t*)&ref.sym->symboldata[ref.ofs];
}
/*
============
@ -5033,7 +5093,7 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
if (QCC_PR_CheckToken ("..."))
{
t = QCC_PR_ParseType(false, true); //the evil things I do...
t = QCC_PR_ParseType(false, true, false); //the evil things I do...
if (!t)
{
ftype->vargs = true;
@ -5078,7 +5138,7 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
break;
}
t = QCC_PR_ParseType(false, false);
t = QCC_PR_ParseType(false, false, false);
}
paramlist[numparms].defltvalue.cast = NULL;
paramlist[numparms].ofs = 0;
@ -5225,7 +5285,7 @@ QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
{
name = QCC_PR_ParseName();
QCC_PR_Expect(":");
nptype = QCC_PR_ParseType(true, false);
nptype = QCC_PR_ParseType(true, false, false);
}
if (!nptype)
@ -5238,6 +5298,7 @@ QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
paramlist[numparms].optional = false;
paramlist[numparms].isvirtual = false;
paramlist[numparms].ofs = 0;
paramlist[numparms].bitofs = 0;
paramlist[numparms].arraysize = 0;
paramlist[numparms].type = nptype;
@ -5437,7 +5498,7 @@ struct accessor_s *QCC_PR_ParseAccessorMember(QCC_type_t *classtype, pbool isinl
f = QCC_PR_ParseImmediateStatements (def.sym, functype, false);
pr_classtype = NULL;
pr_scope = NULL;
def.sym->symboldata[def.ofs].function = f - functions;
QCC_SRef_Data(def)->function = f - functions;
f->def = def.sym;
def.sym->initialized = 1;
}
@ -5495,7 +5556,7 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
QCC_type_t *newt, *type, *newparm;
struct QCC_typeparam_s *parms = NULL, *oldparm;
int numparms = 0;
int ofs;
int ofs, bitofs;
unsigned int arraysize;
char *parmname;
@ -5503,6 +5564,8 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
pbool isstatic = false;
pbool isvirt = false;
pbool definedsomething = false;
unsigned int bitsize;
unsigned int bitalign = 0; //alignment of largest element...
if (QCC_PR_CheckToken("{"))
{
@ -5555,6 +5618,7 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
newt->size = newt->parentclass->size;
else
newt->size=0;
bitsize = newt->size<<5;
type = NULL;
@ -5624,7 +5688,7 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
// isignored = true;
//now parse the actual type.
newparm = QCC_PR_ParseType(false, false);
newparm = QCC_PR_ParseType(false, false, true);
definedsomething = false;
}
type = newparm;
@ -5679,8 +5743,26 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
if (QCC_PR_CheckToken(":"))
{
QCC_PR_IntConstExpr();
QCC_PR_ParseWarning(WARN_IGNOREDKEYWORD, "bitfields are not supported");
int bits = QCC_PR_IntConstExpr();
if (bits > 64)
QCC_PR_ParseWarning(ERR_BADNOTTYPE, "too many bits");
else if (type->type == ev_integer || type->type == ev_uint || type->type == ev_int64 || type->type == ev_uint64)
{
QCC_type_t *bitfld;
//prmote to bigger if big.
if (bits > 32 && type->type == ev_integer)
type = type_int64;
if (bits > 32 && type->type == ev_uint)
type = type_uint64;
bitfld = QCC_PR_NewType("bitfld", ev_bitfld, false);
bitfld->bits = bits;
bitfld->size = type->size;
bitfld->parentclass = type;
bitfld->align = type->align; //use the parent's alignment, for some reason.
type = bitfld;
}
else
QCC_PR_ParseWarning(ERR_BADNOTTYPE, "bitfields must be integer types");
}
if ((isnonvirt || isvirt) && type->type != ev_function)
@ -5727,25 +5809,59 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
}
parms = realloc(parms, sizeof(*parms) * (numparms+4));
oldparm = QCC_PR_FindStructMember(newt, parmname, &ofs);
oldparm = QCC_PR_FindStructMember(newt, parmname, &ofs, &bitofs);
if (type->align)
{
if (bitalign < type->align)
bitalign = type->align; //bigger than that...
}
else
bitalign = 32; //struct must be word aligned.
if (oldparm && oldparm->arraysize == arraysize && !typecmp_lax(oldparm->type, type))
{
ofs <<= 5;
ofs += bitofs;
if (!isvirt)
continue;
}
else if (structtype == ev_union)
{
ofs = 0;
if (type->size*(arraysize?arraysize:1) > newt->size)
newt->size = type->size*(arraysize?arraysize:1);
if (type->bits)
{
if (bitsize < type->bits*(arraysize?arraysize:1))
bitsize = type->bits*(arraysize?arraysize:1);
}
else
{
if (bitsize < 32*type->size*(arraysize?arraysize:1))
bitsize = 32*type->size*(arraysize?arraysize:1);
}
}
else
{
ofs = newt->size;
newt->size += type->size*(arraysize?arraysize:1);
if (type->bits)
{
if (type->bits < type->align && type->type == ev_bitfld)
{ //only realigns when it cross its parent's alignment boundary.
if ((bitsize&(type->align-1)) + type->bits > type->align)
bitsize = (bitsize+type->align-1)&~(type->align-1); //these must be aligned, so we can take pointers etc.
}
else if (type->align)
bitsize = (bitsize+type->align-1)&~(type->align-1); //these must be aligned, so we can take pointers etc.
ofs = bitsize;
bitsize += type->bits*(arraysize?arraysize:1);
}
else
{
bitsize = (bitsize+31)&~31; //provide padding to keep non-bitfield stuff word aligned
ofs = bitsize;
bitsize += 32 * type->size*(arraysize?arraysize:1);
}
}
parms[numparms].ofs = ofs;
parms[numparms].ofs = ofs>>5;
parms[numparms].bitofs = ofs - (parms[numparms].ofs<<5);
parms[numparms].arraysize = arraysize;
parms[numparms].out = false;
parms[numparms].optional = false;
@ -5756,7 +5872,7 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
numparms++;
/*if (type->type == ev_vector && arraysize == 0)
{ //add in vec_x/y/z members too.
{ //add in vec_x/y/z members too...?
int c;
for (c = 0; c < 3; c++)
{
@ -5773,6 +5889,17 @@ static QCC_type_t *QCC_PR_ParseStruct(etype_t structtype)
}
}*/
}
if (bitalign) //compute tail padding.
bitsize = (bitsize+bitalign-1)&~(bitalign-1);
newt->size = (bitsize+31)>>5; //FIXME: change to bytes, for pointers.
newt->align = bitalign;
if (bitalign&31)
newt->bits = bitsize;
else
newt->bits = 0; //all word aligned. nothing special going on sizewise (maybe inside though).
if (!numparms)
QCC_PR_ParseError(ERR_NOTANAME, "%s %s has no members", structtype==ev_union?"union":"struct", newt->name);
@ -5942,7 +6069,7 @@ QCC_type_t *QCC_PR_ParseEntClass(void)
continue;
}
basetype = QCC_PR_ParseType(false, false);
basetype = QCC_PR_ParseType(false, false, false);
if (!basetype)
QCC_PR_ParseError(ERR_INTERNAL, "In class %s, expected type, found %s", classname, pr_token);
@ -6187,6 +6314,7 @@ QCC_type_t *QCC_PR_ParseEntClass(void)
parms = realloc(parms, sizeof(*parms) * (numparms+1));
parms[numparms].ofs = 0;
parms[numparms].bitofs = 0;
parms[numparms].out = false;
parms[numparms].optional = false;
parms[numparms].isvirtual = isvirt;
@ -6376,7 +6504,7 @@ 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
*/
QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail, pbool ignoreptr)
{
QCC_type_t *newt;
QCC_type_t *type;
@ -6404,7 +6532,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_PR_Lex ();
type = QCC_PR_NewType("FIELD_TYPE", ev_field, false);
type->aux_type = QCC_PR_ParseType (false, false);
type->aux_type = QCC_PR_ParseType (false, false, ignoreptr);
type->size = type->aux_type->size;
newt = QCC_PR_FindType (type);
@ -6424,7 +6552,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckToken ("..")) //so we don't end up with the user specifying '. .vector blah' (hexen2 added the .. token for array ranges)
{
newt = QCC_PR_NewType("FIELD_TYPE", ev_field, false);
newt->aux_type = QCC_PR_ParseType (false, false);
newt->aux_type = QCC_PR_ParseType (false, false, ignoreptr);
newt->size = newt->aux_type->size;
@ -6448,7 +6576,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//however, we can't cope parsing that with regular types, so we support that ONLY when . was already specified.
//this is pretty much an evil syntax hack.
pbool ptr = QCC_PR_CheckToken ("*");
type = QCC_PR_ParseType(false, false);
type = QCC_PR_ParseType(false, false, ignoreptr);
if (!type)
QCC_PR_ParseError(0, "Expected type\n");
if (ptr)
@ -6496,7 +6624,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckToken(":"))
{
type = QCC_PR_ParseType(false, false);
type = QCC_PR_ParseType(false, false, false);
if (type)
TypeName(type, parentname, sizeof(parentname));
else
@ -6667,9 +6795,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
else if (bits > 32)
type = (isunsigned?type_uint64:type_int64);
else if (bits <= 8)
type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "chars are not supported, using int"); //permitted
type = (isunsigned?type_uint8:type_sint8);
else if (bits <= 16)
type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "shorts are not supported, using int"); //permitted
type = (isunsigned?type_uint16:type_sint16);
else
type = (isunsigned?type_uint:type_integer);
}
@ -6689,11 +6817,14 @@ wasctype:
if (!type)
return NULL;
while (QCC_PR_CheckToken("*"))
if (!ignoreptr)
{
if (QCC_PR_CheckKeyword(keyword_const, "const"))
QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword");
type = QCC_PointerTypeTo(type);
while (QCC_PR_CheckToken("*"))
{
if (QCC_PR_CheckKeyword(keyword_const, "const"))
QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword");
type = QCC_PointerTypeTo(type);
}
}
if (flag_qcfuncs && QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function.

View file

@ -1372,7 +1372,7 @@ static void QCC_FinaliseDef(QCC_def_t *def)
}
if (def->symbolheader != def)
{
{ //finalise the parent/root symbol first.
def->symbolheader->used |= def->used;
QCC_FinaliseDef(def->symbolheader);
def->referenced = true;
@ -1474,11 +1474,6 @@ static void QCC_FinaliseDef(QCC_def_t *def)
}
else
{
/* globalspertype[def->type->type].size += def->symbolsize;
globalspertype[def->type->type].entries += 1;
globalspertype[def->type->type].vars += !def->constant;
globalspertype[def->type->type].consts += def->constant;
*/
if (def->ofs)
{
if (def->symbolheader == def)
@ -1529,22 +1524,41 @@ static void QCC_FinaliseDef(QCC_def_t *def)
def->reloc->used = true;
QCC_FinaliseDef(def->reloc);
if (def->type->type == ev_function/*misordered inits/copies*/ || def->type->type == ev_integer/*dp-style global index*/)
qcc_pr_globals[def->ofs]._int += qcc_pr_globals[def->reloc->ofs]._int;
{
//printf("func Reloc %s %s@%i==%x -> %s@%i==%x==%s\n", def->symbolheader->name, def->name,def->ofs, def->symboldata->_int, def->reloc->name,def->reloc->ofs, def->reloc->symboldata->_int, functions[def->reloc->symboldata->_int].name);
def->symboldata->_int += def->reloc->symboldata->_int;
}
else if (def->type->type == ev_pointer/*signal to the engine to fix up the offset*/)
{
if (qcc_pr_globals[def->ofs]._int & 0x80000000)
QCC_Error(ERR_INTERNAL, "dupe reloc, type... %s", def->type->name);
else if (flag_undefwordsize)
QCC_PR_ParseWarning(ERR_BADEXTENSION, "pointer relocs are disabled for this target.");
qcc_pr_globals[def->ofs]._int += def->reloc->ofs;
qcc_pr_globals[def->ofs]._int *= VMWORDSIZE;
//printf("Reloc %s %s@%i==%x -> %s@%i==%x\n", def->symbolheader->name, def->name,def->ofs, def->symboldata->_int, def->reloc->name,def->reloc->ofs, def->symboldata->_int+def->reloc->ofs*VMWORDSIZE);
if (def->symboldata->_int & 0x80000000)
QCC_PR_ParseWarning(0, "dupe reloc, %s", def->type->name);
else
{
if (flag_undefwordsize)
QCC_PR_ParseWarning(ERR_BADEXTENSION, "pointer relocs are disabled for this target.");
def->symboldata->_int += def->reloc->ofs*VMWORDSIZE;
qcc_pr_globals[def->ofs]._int |= 0x80000000;
def->symboldata->_int |= 0x80000000; //we're using this as a hint to the engine to let it know that there's no dupes.
}
}
else
QCC_Error(ERR_INTERNAL, "unknown reloc type... %s", def->type->name);
}
{
QCC_def_t *prev, *sub;
for (prev = def, sub = prev->next; sub && prev != def->deftail; sub = (prev=sub)->next)
{
if (sub->reloc && !sub->used)
{ //make sure any children are finalised properly if they're relocs.
sub->used = true;
sub->referenced = true;
QCC_FinaliseDef(sub);
}
}
}
#ifdef DEBUG_DUMP_GLOBALMAP
if (!def->referenced)
externs->Printf("Unreferenced ");
@ -2160,7 +2174,7 @@ static pbool QCC_WriteData (int crc)
if (def->symbolheader->used)
{
char typestr[256];
QCC_sref_t sr = {def, 0, def->type};
QCC_sref_t sr = {def, {0}, def->type};
QCC_PR_Warning(WARN_NOTREFERENCED, def->filen, def->s_line, "%s %s%s%s = %s used, but not referenced.", TypeName(def->type, typestr, sizeof(typestr)), col_symbol, def->name, col_none, QCC_VarAtOffset(sr));
}
/*if (opt_unreferenced && def->type->type != ev_field)
@ -2224,7 +2238,7 @@ static pbool QCC_WriteData (int crc)
def->name = ""; //reloc, can't strip it (engine needs to fix em up), but can clear its name.
else if (def->scope && !def->scope->privatelocals && !def->isstatic)
continue; //def is a local, which got shared and should be 0...
else if ((def->scope||def->constant||flag_noreflection) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
else if ((def->scope||def->constant||(flag_noreflection&&strncmp(def->name, "autocvar_", 9))) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
{
if (opt_constant_names)
{
@ -3580,6 +3594,7 @@ QCC_type_t *QCC_PR_NewType (const char *name, int basictype, pbool typedefed)
qcc_typeinfo[numtypeinfos].params = NULL;
qcc_typeinfo[numtypeinfos].size = type_size[basictype];
qcc_typeinfo[numtypeinfos].typedefed = typedefed;
qcc_typeinfo[numtypeinfos].align = 32; //assume this alignment for now. some types allow tighter alignment, though mostly only in structs.
qcc_typeinfo[numtypeinfos].filen = s_filen;
qcc_typeinfo[numtypeinfos].line = pr_source_line;
@ -3621,22 +3636,27 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
*/
type_void = QCC_PR_NewType("void", ev_void, true);
type_string = QCC_PR_NewType("string", ev_string, true);
type_string = QCC_PR_NewType(flag_qcfuncs?"string":"__string", ev_string, true);
type_float = QCC_PR_NewType("float", ev_float, true);
type_double = QCC_PR_NewType("__double", ev_double, true);
type_vector = QCC_PR_NewType("vector", ev_vector, true);
type_entity = QCC_PR_NewType("entity", ev_entity, true);
type_vector = QCC_PR_NewType(flag_qcfuncs?"vector":"__vector", ev_vector, true);
type_entity = QCC_PR_NewType(flag_qcfuncs?"entity":"__entity", ev_entity, true);
type_field = QCC_PR_NewType("__field", ev_field, false);
type_field->aux_type = type_void;
type_function = QCC_PR_NewType("__function", ev_function, false);
type_function->aux_type = type_void;
type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false);
type_integer = QCC_PR_NewType("__int", ev_integer, true);
type_uint = QCC_PR_NewType("__uint", ev_uint, true);
type_integer = QCC_PR_NewType("__int32", ev_integer, true);
type_uint = QCC_PR_NewType("__uint32", ev_uint, true);
type_int64 = QCC_PR_NewType("__int64", ev_int64, true);
type_uint64 = QCC_PR_NewType("__uint64", ev_uint64, true);
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
type_sint8 = QCC_PR_NewType("__int8", ev_bitfld, true); type_sint8 ->parentclass = type_integer; type_sint8 ->size = type_sint8 ->parentclass->size; type_sint8 ->align = type_sint8 ->bits = 8;
type_uint8 = QCC_PR_NewType("__uint8", ev_bitfld, true); type_uint8 ->parentclass = type_uint; type_uint8 ->size = type_uint8 ->parentclass->size; type_uint8 ->align = type_uint8 ->bits = 8;
type_sint16 = QCC_PR_NewType("__int16", ev_bitfld, true); type_sint16->parentclass = type_integer; type_sint16->size = type_sint16->parentclass->size; type_sint16->align = type_sint16->bits = 16;
type_uint16 = QCC_PR_NewType("__uint16", ev_bitfld, true); type_uint16->parentclass = type_uint; type_uint16->size = type_uint16->parentclass->size; type_uint16->align = type_uint16->bits = 16;
type_invalid = QCC_PR_NewType("invalid", ev_void, false);
type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false);
@ -3650,10 +3670,8 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_floatfunction = QCC_PR_NewType("__floatfunction", ev_function, false);
type_floatfunction->aux_type = type_float;
type_bfloat = QCC_PR_NewType("__bfloat", ev_boolean, true);
type_bfloat->parentclass = type_float;
type_bint = QCC_PR_NewType("__bint", ev_boolean, true);
type_bint->parentclass = type_uint;
type_bfloat = QCC_PR_NewType("__bfloat", ev_boolean, true); type_bfloat->parentclass = type_float; //has value 0.0 or 1.0
type_bint = QCC_PR_NewType("__bint", ev_boolean, true); type_bint->parentclass = type_uint; //has value 0 or 1
//type_field->aux_type = type_float;
@ -3662,6 +3680,11 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
// QCC_PR_NewType("__int", ev_integer, keyword_integer?true:false);
QCC_PR_NewType("variant", ev_variant, true);
if (*type_string->name != '_') QCC_PR_NewType("__string", ev_string, true); //make sure some core types __string always work with a double-underscore prefix
if (*type_vector->name != '_') QCC_PR_NewType("__vector", ev_vector, true); //make sure some core types __string always work with a double-underscore prefix
if (*type_entity->name != '_') QCC_PR_NewType("__entity", ev_entity, true); //make sure some core types __string always work with a double-underscore prefix
QCC_PR_NewType("__int", ev_integer, true);
QCC_PR_NewType("__uint", ev_uint, true);
@ -4684,6 +4707,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
flag_assume_double = true; //and any immediates with a decimal points are assumed to be doubles, consistent with C.
flag_qcfuncs = false; //there's a few parsing quirks where our attempt to parse qc functions will misparse valid C.
flag_macroinstrings = false;//hacky preqcc hack.
flag_boundchecks = false; //nope... not C's style.
qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too.
qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird.
@ -4706,6 +4730,8 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
val = "201112L";
else if (!stricmp(myargv[i]+5, "c17"))
val = "201710L";
else if (!stricmp(myargv[i]+5, "c23"))
val = "202311L";
else
val = NULL;
cnst = QCC_PR_DefineName("__STDC_VERSION__");
@ -5448,7 +5474,7 @@ pbool QCC_main (int argc, const char **argv) //as part of the quake engine
for (p = 0; compiler_flag[p].enabled; p++)
{
*compiler_flag[p].enabled = compiler_flag[p].flags & FLAG_ASDEFAULT;
*compiler_flag[p].enabled = !!(compiler_flag[p].flags & FLAG_ASDEFAULT);
}
parseonly = autoprototyped = autoprototype = false;

View file

@ -13418,8 +13418,8 @@ void PR_DumpPlatform_f(void)
#define globalfloat(need,name) {#name, "float", QW|NQ, "ssqc global"},
#define globalentity(need,name) {#name, "entity", QW|NQ, "ssqc global"},
#define globalint(need,name) {#name, "int", QW|NQ, "ssqc global"},
#define globaluint(need,name) {#name, "unsigned int", QW|NQ, "ssqc global"},
#define globaluint64(need,name) {#name, "unsigned __long", QW|NQ, "ssqc global"},
#define globaluint(need,name) {#name, "__uint", QW|NQ, "ssqc global"},
#define globaluint64(need,name) {#name, "__uint64", QW|NQ, "ssqc global"},
#define globalstring(need,name) {#name, "string", QW|NQ, "ssqc global"},
#define globalvec(need,name) {#name, "vector", QW|NQ, "ssqc global"},
#define globalfunc(need,name,typestr) {#name, typestr, QW|NQ, "ssqc global"},
@ -13440,8 +13440,8 @@ void PR_DumpPlatform_f(void)
#define globalvector(name) {#name, "vector", CS},
#define globalstring(name) {#name, "string", CS},
#define globalint(name) {#name, "int", CS},
#define globaluint(name) {#name, "unsigned int", CS},
#define globaluint64(name) {#name, "unsigned __long", CS},
#define globaluint(name) {#name, "__uint", CS},
#define globaluint64(name) {#name, "__uint64", CS},
csqcglobals
#undef globalfunction
#undef globalfloat