fteqw/engine/qclib/qcc_pr_lex.c
Spoike 9ae7e2621d SOFTWARE RENDERING IS BROKEN: DO NOT USE ASM VERSION.
Lots of changes.
CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit.
Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit.
Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
2005-02-28 07:16:19 +00:00

3064 lines
62 KiB
C

#ifndef MINIMAL
#include "qcc.h"
#ifdef QCC
#define print printf
#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
void QCC_PR_ConditionCompilation(void);
pbool QCC_PR_UndefineName(char *name);
char *QCC_PR_CheakCompConstString(char *def);
CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
pbool QCC_Include(char *filename);
float QCC_PR_LexOctal (void);
char *compilingfile;
int pr_source_line;
char *pr_file_p;
char *pr_line_start; // start of current source line
int pr_bracelevel;
char pr_token[8192];
token_type_t pr_token_type;
QCC_type_t *pr_immediate_type;
QCC_eval_t pr_immediate;
char pr_immediate_string[8192];
int pr_error_count;
CompilerConstant_t *CompilerConstant;
int numCompilerConstants;
char *pr_punctuation[] =
// longer symbols must be before a shorter partial match
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "(+)", "(-)", "++", "--", "->", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "#" , "@", "&" , "|", "^", ":", NULL};
char *pr_punctuationremap[] = //a nice bit of evilness.
//|= -> (+)
//-> -> .
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)","(+)", "(-)", "++", "--", ".", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "#" , "@", "&" , "|", "^", ":", NULL};
// simple types. function types are dynamically allocated
QCC_type_t *type_void;// = {ev_void/*, &def_void*/};
QCC_type_t *type_string;// = {ev_string/*, &def_string*/};
QCC_type_t *type_float;// = {ev_float/*, &def_float*/};
QCC_type_t *type_vector;// = {ev_vector/*, &def_vector*/};
QCC_type_t *type_entity;// = {ev_entity/*, &def_entity*/};
QCC_type_t *type_field;// = {ev_field/*, &def_field*/};
QCC_type_t *type_function;// = {ev_function/*, &def_function*/,NULL,&type_void};
// type_function is a void() function used for state defs
QCC_type_t *type_pointer;// = {ev_pointer/*, &def_pointer*/};
QCC_type_t *type_integer;// = {ev_integer/*, &def_integer*/};
QCC_type_t *type_variant;// = {ev_integer/*, &def_integer*/};
QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float};
#ifdef QCCONLY
const int type_size[12] = {1,1,1,3,1,1,1,1,1, 1, 0,0};
#endif
/*QCC_def_t def_void = {type_void, "temp"};
QCC_def_t def_string = {type_string, "temp"};
QCC_def_t def_float = {type_float, "temp"};
QCC_def_t def_vector = {type_vector, "temp"};
QCC_def_t def_entity = {type_entity, "temp"};
QCC_def_t def_field = {type_field, "temp"};
QCC_def_t def_function = {type_function, "temp"};
QCC_def_t def_pointer = {type_pointer, "temp"};
QCC_def_t def_integer = {type_integer, "temp"};
*/
QCC_def_t def_ret, def_parms[MAX_PARMS];
//QCC_def_t *def_for_type[9] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer, &def_integer};
void QCC_PR_LexWhitespace (void);
//for compiler constants and file includes.
typedef struct qcc_includechunk_s {
struct qcc_includechunk_s *prev;
char *filename;
char *currentdatapoint;
int currentlinenumber;
} qcc_includechunk_t;
qcc_includechunk_t *currentchunk;
void QCC_PR_IncludeChunk (char *data, pbool duplicate, char *filename)
{
qcc_includechunk_t *chunk = qccHunkAlloc(sizeof(qcc_includechunk_t));
chunk->prev = currentchunk;
currentchunk = chunk;
chunk->currentdatapoint = pr_file_p;
chunk->currentlinenumber = pr_source_line;
if (duplicate)
{
pr_file_p = qccHunkAlloc(strlen(data)+1);
strcpy(pr_file_p, data);
}
else
pr_file_p = data;
}
pbool QCC_PR_UnInclude(void)
{
if (!currentchunk)
return false;
pr_file_p = currentchunk->currentdatapoint;
pr_source_line = currentchunk->currentlinenumber;
currentchunk = currentchunk->prev;
return true;
}
/*
==============
PR_PrintNextLine
==============
*/
void QCC_PR_PrintNextLine (void)
{
char *t;
printf ("%3i:",pr_source_line);
for (t=pr_line_start ; *t && *t != '\n' ; t++)
printf ("%c",*t);
printf ("\n");
}
int ForcedCRC;
int QCC_PR_LexInteger (void);
void QCC_AddFile (char *filename);
void QCC_PR_LexString (void);
pbool QCC_PR_SimpleGetToken (void);
/*
==============
QCC_PR_Precompiler
==============
Runs precompiler stage
*/
pbool QCC_PR_Precompiler(void)
{
char msg[1024];
int ifmode;
int a;
static int ifs = 0;
int level; //#if level
pbool eval = false;
if (*pr_file_p == '#')
{
char *directive;
for (directive = pr_file_p+1; *directive; directive++) //so # define works
{
if (*directive == '\r' || *directive == '\n')
QCC_PR_ParseError(ERR_UNKNOWNPUCTUATION, "Hanging # with no directive\n");
if (*directive > ' ')
break;
}
if (!strncmp(directive, "define", 6))
{
pr_file_p = directive;
QCC_PR_ConditionCompilation();
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "undef", 5))
{
pr_file_p = directive+5;
while(*pr_file_p <= ' ')
pr_file_p++;
QCC_PR_SimpleGetToken ();
QCC_PR_UndefineName(pr_token);
// QCC_PR_ConditionCompilation();
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "if", 2))
{
int origionalline = pr_source_line;
pr_file_p = directive+2;
if (!strncmp(pr_file_p, "def ", 4))
{
ifmode = 0;
pr_file_p+=4;
}
else if (!strncmp(pr_file_p, "ndef ", 5))
{
ifmode = 1;
pr_file_p+=5;
}
else
{
ifmode = 2;
pr_file_p+=0;
//QCC_PR_ParseError("bad \"#if\" type");
}
QCC_PR_SimpleGetToken ();
level = 1;
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
// pr_file_p++;
// pr_source_line++;
if (ifmode == 2)
{
if (atof(pr_token))
eval = true;
}
else
{
// if (!STRCMP(pr_token, "COOP_MODE"))
// eval = false;
if (QCC_PR_CheckCompConstDefined(pr_token))
eval = true;
if (ifmode == 1)
eval = eval?false:true;
}
if (eval)
ifs+=1;
else
{
while (1)
{
while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
pr_file_p++;
if (!*pr_file_p)
{
pr_source_line = origionalline;
QCC_PR_ParseError (ERR_NOENDIF, "#if with no endif");
}
if (*pr_file_p == '#')
{
pr_file_p++;
while(*pr_file_p==' ' || *pr_file_p == '\t')
pr_file_p++;
if (!strncmp(pr_file_p, "endif", 5))
level--;
if (!strncmp(pr_file_p, "if", 2))
level++;
if (!strncmp(pr_file_p, "else", 4) && level == 1)
{
ifs+=1;
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
break;
}
}
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
if (level <= 0)
break;
pr_file_p++; //next line
pr_source_line++;
}
}
}
else if (!strncmp(directive, "else", 4))
{
int origionalline = pr_source_line;
ifs -= 1;
level = 1;
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
while (1)
{
while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
pr_file_p++;
if (!*pr_file_p)
{
pr_source_line = origionalline;
QCC_PR_ParseError(ERR_NOENDIF, "#if with no endif");
}
if (*pr_file_p == '#')
{
pr_file_p++;
while(*pr_file_p==' ' || *pr_file_p == '\t')
pr_file_p++;
if (!strncmp(pr_file_p, "endif", 5))
level--;
if (!strncmp(pr_file_p, "if", 2))
level++;
if (!strncmp(pr_file_p, "else", 4) && level == 1)
{
ifs+=1;
break;
}
}
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
if (level <= 0)
break;
pr_file_p++; //go off the end
pr_source_line++;
}
}
else if (!strncmp(directive, "endif", 5))
{
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
if (ifs <= 0)
QCC_PR_ParseError(ERR_NOPRECOMPILERIF, "unmatched #endif");
else
ifs-=1;
}
else if (!strncmp(directive, "eof", 3))
{
pr_file_p = NULL;
return true;
}
else if (!strncmp(directive, "error", 5))
{
pr_file_p = directive+5;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line, yes, I KNOW we are going to register an error, and not properly leave this function tree, but...
{
pr_file_p++;
}
QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg);
}
else if (!strncmp(directive, "warning", 7))
{
pr_file_p = directive+7;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
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_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++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
printf("#message: %s\n", msg);
}
else if (!strncmp(directive, "copyright", 9))
{
pr_file_p = directive+9;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
if (strlen(msg) >= sizeof(QCC_copyright))
QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
}
else if (!strncmp(directive, "pack", 4))
{
ifmode = 0;
pr_file_p=directive+4;
if (!strncmp(pr_file_p, "id", 2))
pr_file_p+=3;
else
{
ifmode = QCC_PR_LexInteger();
if (ifmode == 0)
ifmode = 1;
pr_file_p++;
}
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
if (ifmode == 0)
QCC_packid = atoi(msg);
else if (ifmode <= 5)
strcpy(QCC_Packname[ifmode-1], msg);
else
QCC_PR_ParseError(ERR_TOOMANYPACKFILES, "No more than 5 packs are allowed");
}
else if (!strncmp(directive, "forcecrc", 8))
{
pr_file_p=directive+8;
ForcedCRC = QCC_PR_LexInteger();
pr_file_p++;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "includelist", 11))
{
pr_file_p=directive+11;
while(*pr_file_p <= ' ')
pr_file_p++;
while(1)
{
QCC_PR_LexWhitespace();
if (!QCC_PR_SimpleGetToken())
{
if (!*pr_file_p)
QCC_Error(ERR_EOF, "eof in includelist");
else
{
pr_file_p++;
pr_source_line++;
}
continue;
}
if (!strcmp(pr_token, "#endlist"))
break;
printf("Including: %s\n", pr_token);
QCC_Include(pr_token);
if (*pr_file_p == '\r')
pr_file_p++;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "include", 7))
{
pr_file_p=directive+7;
while(*pr_file_p <= ' ')
pr_file_p++;
*msg = '\0';
if (*pr_file_p == '\"')
{
pr_file_p++;
for (a=0;a<1023;a++)
{
if (*pr_file_p == '\"')
break;
msg[a] = *pr_file_p++;
}
msg[a] = '\0';
}
else if (*pr_file_p == '<')
{
pr_file_p++;
for (a=0;a<1023;a++)
{
if (*pr_file_p == '>')
break;
msg[a] = *pr_file_p++;
}
msg[a] = '\0';
}
else
QCC_PR_ParseError(0, "Not a string literal");
printf("Including: %s\n", msg);
QCC_Include(msg);
pr_file_p++;
while(*pr_file_p != '\n' && *pr_file_p != '\0' && *pr_file_p <= ' ')
pr_file_p++;
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "datafile", 8))
{
pr_file_p=directive+8;
while(*pr_file_p <= ' ')
pr_file_p++;
QCC_PR_LexString();
printf("Including datafile: %s\n", pr_token);
QCC_AddFile(pr_token);
pr_file_p++;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "output", 6))
{
extern char destfile[1024];
pr_file_p=directive+6;
while(*pr_file_p <= ' ')
pr_file_p++;
QCC_PR_LexString();
strcpy(destfile, pr_token);
printf("Outputfile: %s\n", destfile);
pr_file_p++;
for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
{
pr_file_p++;
}
}
else if (!strncmp(directive, "pragma", 6))
{
pr_file_p=directive+6;
while(*pr_file_p <= ' ')
pr_file_p++;
qcc_token[0] = '\0';
for(a = 0; *pr_file_p != '\n' && *pr_file_p != '\0'; pr_file_p++) //read on until the end of the line
{
if ((*pr_file_p == ' ' || *pr_file_p == '\t'|| *pr_file_p == '(') && !*qcc_token)
{
msg[a] = '\0';
strcpy(qcc_token, msg);
a=0;
continue;
}
msg[a++] = *pr_file_p;
}
msg[a] = '\0';
{
char *end;
for (end = msg + a-1; end>=msg && *end <= ' '; end--)
*end = '\0';
}
if (!*qcc_token)
{
strcpy(qcc_token, msg);
msg[0] = '\0';
}
{
char *end;
for (end = msg + a-1; end>=msg && *end <= ' '; end--)
*end = '\0';
}
if (!QC_strcasecmp(qcc_token, "DONT_COMPILE_THIS_FILE"))
{
while (*pr_file_p)
{
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
pr_file_p++;
if (*pr_file_p == '\n')
{
QCC_PR_NewLine(false);
pr_file_p++;
}
}
}
else if (!QC_strcasecmp(qcc_token, "COPYRIGHT"))
{
if (strlen(msg) >= sizeof(QCC_copyright))
QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
}
else if (!QC_strcasecmp(qcc_token, "TARGET"))
{
if (qcc_targetformat == QCF_HEXEN2 && numstatements)
QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
else if (!QC_strcasecmp(msg, "H2") || !QC_strcasecmp(msg, "HEXEN2"))
{
if (numstatements)
QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
else
qcc_targetformat = QCF_HEXEN2;
}
else if (!QC_strcasecmp(msg, "KK7"))
qcc_targetformat = QCF_KK7;
else if (!QC_strcasecmp(msg, "FTEDEBUG"))
qcc_targetformat = QCF_FTEDEBUG;
else if (!QC_strcasecmp(msg, "FTE"))
qcc_targetformat = QCF_FTE;
else if (!QC_strcasecmp(msg, "STANDARD") || !QC_strcasecmp(msg, "ID"))
qcc_targetformat = QCF_STANDARD;
else if (!QC_strcasecmp(msg, "DEBUG"))
qcc_targetformat = QCF_FTEDEBUG;
else
QCC_PR_ParseWarning(WARN_BADTARGET, "Unknown target \'%s\'. Ignored.", msg);
}
else if (!QC_strcasecmp(qcc_token, "PROGS_SRC"))
{ //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
}
else if (!QC_strcasecmp(qcc_token, "PROGS_DAT"))
{ //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
extern char destfile[1024];
QCC_COM_Parse(msg);
strcpy(destfile, qcc_token);
printf("Outputfile: %s\n", destfile);
}
else if (!QC_strcasecmp(qcc_token, "warning"))
{
int st;
char *s;
s = QCC_COM_Parse(msg);
if (!stricmp(qcc_token, "enable") || !stricmp(qcc_token, "on"))
st = 0;
else if (!stricmp(qcc_token, "disable") || !stricmp(qcc_token, "off"))
st = 1;
else if (!stricmp(qcc_token, "toggle"))
st = 2;
else
st = -1;
if (st>=0)
{
int wn;
s = QCC_COM_Parse(s);
wn = QCC_WarningForName(qcc_token);
if (wn < 0)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
else
{
if (st == 2) //toggle
qccwarningdisabled[wn] = true - qccwarningdisabled[wn];
else
qccwarningdisabled[wn] = st;
}
}
}
else
QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token);
}
return true;
}
return false;
}
/*
==============
PR_NewLine
Call at start of file and when *pr_file_p == '\n'
==============
*/
void QCC_PR_NewLine (pbool incomment)
{
pbool m;
if (*pr_file_p == '\n')
{
pr_file_p++;
m = true;
}
else
m = false;
pr_source_line++;
pr_line_start = pr_file_p;
while(*pr_file_p==' ' || *pr_file_p == '\t')
pr_file_p++;
if (incomment) //no constants if in a comment.
{
}
else if (QCC_PR_Precompiler())
{
}
// if (pr_dumpasm)
// PR_PrintNextLine ();
if (m)
pr_file_p--;
}
/*
==============
PR_LexString
Parses a quoted string
==============
*/
#if 0
void QCC_PR_LexString (void)
{
int c;
int len;
char tmpbuf[2048];
char *text;
char *oldf;
int oldline;
bool fromfile = true;
len = 0;
text = pr_file_p;
do
{
QCC_COM_Parse(text);
// print("Next token is \"%s\"\n", com_token);
if (*text == '\"')
{
text++;
if (fromfile) pr_file_p++;
}
do
{
c = *text++;
if (fromfile) pr_file_p++;
if (!c)
QCC_PR_ParseError ("EOF inside quote");
if (c=='\n')
QCC_PR_ParseError ("newline inside quote");
if (c=='\\')
{ // escape char
c = *text++;
if (fromfile) pr_file_p++;
if (!c)
QCC_PR_ParseError ("EOF inside quote");
if (c == 'n')
c = '\n';
else if (c == '"')
c = '"';
else if (c == '\\')
c = '\\';
else
QCC_PR_ParseError ("Unknown escape char");
}
else if (c=='\"')
{
if (fromfile) pr_file_p++;
break;
}
tmpbuf[len] = c;
len++;
} while (1);
tmpbuf[len] = 0;
// if (fromfile) pr_file_p++;
pr_immediate_type=NULL;
oldline=pr_source_line;
oldf=pr_file_p;
QCC_PR_Lex();
if (pr_immediate_type == &type_string)
{
// print("Appending \"%s\" to \"%s\"\n", pr_immediate_string, tmpbuf);
strcat(tmpbuf, pr_immediate_string);
len+=strlen(pr_immediate_string);
}
else
{
pr_source_line = oldline;
pr_file_p = oldf-1;
QCC_PR_LexWhitespace();
if (*pr_file_p != '\"') //annother string
break;
}
QCC_PR_LexWhitespace();
text = pr_file_p;
} while (1);
strcpy(pr_token, tmpbuf);
pr_token_type = tt_immediate;
pr_immediate_type = &type_string;
strcpy (pr_immediate_string, pr_token);
// print("Found \"%s\"\n", pr_immediate_string);
}
#else
void QCC_PR_LexString (void)
{
int c;
int len;
char *end, *cnst;
int texttype=0;
len = 0;
pr_file_p++;
do
{
c = *pr_file_p++;
if (!c)
QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
if (c=='\n')
QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote");
if (c=='\\')
{ // escape char
c = *pr_file_p++;
if (!c)
QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
if (c == 'n')
c = '\n';
else if (c == 'r')
c = '\r';
else if (c == '"')
c = '"';
else if (c == 't')
c = '\t';
else if (c == 'a')
c = '\a';
else if (c == 'v')
c = '\v';
else if (c == 'f')
c = '\f';
else if (c == 's' || c == 'b')
{
texttype ^= 128;
continue;
}
else if (c == '[')
c = 16;
else if (c == ']')
c = 17;
else if (c == '{')
{
int d;
c = 0;
while ((d = *pr_file_p++) != '}')
{
c = c * 10 + d - '0';
if (d < '0' || d > '9' || c > 255)
QCC_PR_ParseError(ERR_BADCHARACTURECODE, "Bad character code");
}
}
else if (c == '<')
c = 29;
else if (c == '-')
c = 30;
else if (c == '>')
c = 31;
else if (c == '\\')
c = '\\';
else if (c == '\'')
c = '\'';
else if (c >= '0' && c <= '9')
c = (int)QCC_PR_LexOctal();
else if (c == '\r')
{ //sigh
c = *pr_file_p++;
if (c != '\n')
QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r");
pr_source_line++;
}
else if (c == '\n')
{ //sigh
pr_source_line++;
}
else
QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c);
}
else if (c=='\"')
{
if (len >= sizeof(pr_immediate_string)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1);
while(*pr_file_p && *pr_file_p <= ' ')
{
if (*pr_file_p == '\n')
QCC_PR_NewLine(false);
pr_file_p++;
}
if (*pr_file_p == '\"') //have annother go
{
pr_file_p++;
continue;
}
pr_token[len] = 0;
pr_token_type = tt_immediate;
pr_immediate_type = type_string;
strcpy (pr_immediate_string, pr_token);
return;
}
else if (c == '#')
{
for (end = pr_file_p; ; end++)
{
if (*end <= ' ')
break;
if (*end == ')'
|| *end == '('
|| *end == '+'
|| *end == '-'
|| *end == '*'
|| *end == '/'
|| *end == '\\'
|| *end == '|'
|| *end == '&'
|| *end == '='
|| *end == '^'
|| *end == '~'
|| *end == '['
|| *end == ']'
|| *end == '\"'
|| *end == '{'
|| *end == '}'
|| *end == ';'
|| *end == ':'
|| *end == ','
|| *end == '.'
|| *end == '#')
break;
}
c = *end;
*end = '\0';
cnst = QCC_PR_CheakCompConstString(pr_file_p);
if (cnst==pr_file_p)
cnst=NULL;
*end = c;
c = '#'; //undo
if (cnst)
{
QCC_PR_ParseWarning(WARN_MACROINSTRING, "Macro expansion in string");
if (len+strlen(cnst) >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
strcpy(pr_token+len, cnst);
len+=strlen(cnst);
pr_file_p = end;
continue;
}
}
else if (c == 0x7C && flag_acc) //reacc support... reacc is strange.
c = '\n';
pr_token[len] = c|texttype;
len++;
if (len >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
} while (1);
}
#endif
/*
==============
PR_LexNumber
==============
*/
float QCC_PR_LexOctal (void)
{
int c;
int len;
int result;
char *s;
len = 0;
c = *pr_file_p;
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
if (len >= 3)
break; //max of 3
} while ((c >= '0' && c<= '7'));
pr_token[len] = 0;
result = 0;
for (s = pr_token, result = 0; *s; s++)
{
result*=8;
result+=*s-'0';
}
return (float)result;
}
int QCC_PR_LexInteger (void)
{
int c;
int len;
len = 0;
c = *pr_file_p;
if (pr_file_p[0] == '0' && pr_file_p[1] == 'x')
{
pr_token[0] = '0';
pr_token[1] = 'x';
len = 2;
c = *(pr_file_p+=2);
}
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
} while ((c >= '0' && c<= '9') || c == '.' || (c>='a' && c <= 'f'));
pr_token[len] = 0;
return atoi (pr_token);
}
void QCC_PR_LexNumber (void)
{
int num=0;
int base=10;
int c;
int sign=1;
if (*pr_file_p == '-')
{
sign=-1;
pr_file_p++;
}
if (pr_file_p[1] == 'x')
{
pr_file_p+=2;
base = 16;
}
while((c = *pr_file_p))
{
if (c >= '0' && c <= '9')
{
num*=base;
num += c-'0';
}
else if (c >= 'a' && c <= 'f')
{
num*=base;
num += c -'a'+10;
}
else if (c >= 'A' && c <= 'F')
{
num*=base;
num += c -'A'+10;
}
else if (c == '.')
{
pr_file_p++;
pr_immediate_type = type_float;
pr_immediate._float = (float)num;
num = 1;
while(1)
{
c = *pr_file_p;
if (c >= '0' && c <= '9')
{
num*=base;
pr_immediate._float += (c-'0')/(float)(num);
}
else
{
break;
}
pr_file_p++;
}
pr_immediate._float *= sign;
return;
}
else if (c == 'i')
{
pr_file_p++;
pr_immediate_type = type_integer;
pr_immediate._int = num*sign;
return;
}
else break;
pr_file_p++;
}
pr_immediate_type = type_float;
pr_immediate._float = (float)(num*sign);
}
float QCC_PR_LexFloat (void)
{
int c;
int len;
len = 0;
c = *pr_file_p;
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
} while ((c >= '0' && c<= '9') || (c == '.'&&pr_file_p[1]!='.')); //only allow a . if the next isn't too...
pr_token[len] = 0;
return (float)atof (pr_token);
}
/*
==============
PR_LexVector
Parses a single quoted vector
==============
*/
void QCC_PR_LexVector (void)
{
int i;
pr_file_p++;
if (*pr_file_p == '\\')
{//extended characture constant
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
pr_file_p++;
switch(*pr_file_p)
{
case 'n':
pr_immediate._float = '\n';
break;
case 'r':
pr_immediate._float = '\r';
break;
case 't':
pr_immediate._float = '\t';
break;
case '\'':
pr_immediate._float = '\'';
break;
case '\"':
pr_immediate._float = '\"';
break;
case '\\':
pr_immediate._float = '\\';
break;
case '0':
case '1':
case '2': //assume string constant
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
pr_immediate._float = QCC_PR_LexOctal(); //what's the real point? Neatness?
break;
default:
QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad characture constant");
}
if (*pr_file_p != '\'')
QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad characture constant");
pr_file_p++;
return;
}
if (pr_file_p[1] == '\'')
{//character constant
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
pr_immediate._float = pr_file_p[0];
pr_file_p+=2;
return;
}
pr_token_type = tt_immediate;
pr_immediate_type = type_vector;
QCC_PR_LexWhitespace ();
for (i=0 ; i<3 ; i++)
{
pr_immediate.vector[i] = QCC_PR_LexFloat ();
QCC_PR_LexWhitespace ();
}
if (*pr_file_p != '\'')
QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad vector");
pr_file_p++;
}
/*
==============
PR_LexName
Parses an identifier
==============
*/
void QCC_PR_LexName (void)
{
int c;
int len;
len = 0;
c = *pr_file_p;
do
{
pr_token[len] = c;
len++;
pr_file_p++;
c = *pr_file_p;
} while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
|| (c >= '0' && c <= '9'));
pr_token[len] = 0;
pr_token_type = tt_name;
}
/*
==============
PR_LexPunctuation
==============
*/
void QCC_PR_LexPunctuation (void)
{
int i;
int len;
char *p;
pr_token_type = tt_punct;
for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
{
len = strlen(p);
if (!strncmp(p, pr_file_p, len) )
{
strcpy (pr_token, pr_punctuationremap[i]);
if (p[0] == '{')
pr_bracelevel++;
else if (p[0] == '}')
pr_bracelevel--;
pr_file_p += len;
return;
}
}
QCC_PR_ParseError (ERR_UNKNOWNPUCTUATION, "Unknown punctuation");
}
/*
==============
PR_LexWhitespace
==============
*/
void QCC_PR_LexWhitespace (void)
{
int c;
while (1)
{
// skip whitespace
while ( (c = *pr_file_p) <= ' ')
{
if (c=='\n')
{
QCC_PR_NewLine (false);
if (!pr_file_p)
return;
}
if (c == 0)
return; // end of file
pr_file_p++;
}
// skip // comments
if (c=='/' && pr_file_p[1] == '/')
{
while (*pr_file_p && *pr_file_p != '\n')
pr_file_p++;
QCC_PR_NewLine(false);
pr_file_p++;
continue;
}
// skip /* */ comments
if (c=='/' && pr_file_p[1] == '*')
{
do
{
pr_file_p++;
if (pr_file_p[0]=='\n')
QCC_PR_NewLine(true);
if (pr_file_p[1] == 0)
{
pr_file_p++;
return;
}
} while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
pr_file_p++;
continue;
}
break; // a real character has been found
}
}
//============================================================================
#define MAX_FRAMES 8192
char pr_framemodelname[64];
char pr_framemacros[MAX_FRAMES][16];
int pr_framemacrovalue[MAX_FRAMES];
int pr_nummacros, pr_oldmacros;
int pr_macrovalue;
int pr_savedmacro;
void QCC_PR_ClearGrabMacros (void)
{
pr_oldmacros = pr_nummacros;
// pr_nummacros = 0;
pr_macrovalue = 0;
pr_savedmacro = -1;
}
int QCC_PR_FindMacro (char *name)
{
int i;
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!STRCMP (name, pr_framemacros[i]))
{
return pr_framemacrovalue[i];
}
}
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!stricmp (name, pr_framemacros[i]))
{
QCC_PR_ParseWarning(WARN_CASEINSENSATIVEFRAMEMACRO, "Case insensative frame macro");
return pr_framemacrovalue[i];
}
}
return -1;
}
void QCC_PR_ExpandMacro(void)
{
int i = QCC_PR_FindMacro(pr_token);
if (i < 0)
QCC_PR_ParseError (ERR_BADFRAMEMACRO, "Unknown frame macro $%s", pr_token);
sprintf (pr_token,"%d", i);
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
pr_immediate._float = (float)i;
}
// just parses text, returning false if an eol is reached
pbool QCC_PR_SimpleGetToken (void)
{
int c;
int i;
// skip whitespace
while ( (c = *pr_file_p) <= ' ')
{
if (c=='\n' || c == 0)
return false;
pr_file_p++;
}
if (pr_file_p[0] == '/')
{
if (pr_file_p[1] == '/')
{ //comment alert
while(*pr_file_p && *pr_file_p != '\n')
pr_file_p++;
return false;
}
if (pr_file_p[1] == '*')
return false;
}
i = 0;
while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';' && c != ')' && c != '(')
{
pr_token[i] = c;
i++;
pr_file_p++;
}
pr_token[i] = 0;
return i!=0;
}
void QCC_PR_MacroFrame(char *name, int value)
{
int i;
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!STRCMP (name, pr_framemacros[i]))
{
pr_framemacrovalue[i] = value;
if (i>=pr_oldmacros)
QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Duplicate macro defined (%s)", pr_token);
//else it's from an old file, and shouldn't be mentioned.
return;
}
}
strcpy (pr_framemacros[pr_nummacros], name);
pr_framemacrovalue[pr_nummacros] = value;
pr_nummacros++;
if (pr_nummacros >= MAX_FRAMES)
QCC_PR_ParseError(ERR_TOOMANYFRAMEMACROS, "Too many frame macros defined");
}
void QCC_PR_ParseFrame (void)
{
while (QCC_PR_SimpleGetToken ())
{
QCC_PR_MacroFrame(pr_token, pr_macrovalue++);
}
}
/*
==============
PR_LexGrab
Deals with counting sequence numbers and replacing frame macros
==============
*/
void QCC_PR_LexGrab (void)
{
pr_file_p++; // skip the $
// if (!QCC_PR_SimpleGetToken ())
// QCC_PR_ParseError ("hanging $");
if (*pr_file_p <= ' ')
QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
QCC_PR_SimpleGetToken();
if (!*pr_token)
QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
// check for $frame
if (!STRCMP (pr_token, "frame") || !STRCMP (pr_token, "framesave"))
{
QCC_PR_ParseFrame ();
QCC_PR_Lex ();
}
// ignore other known $commands - just for model/spritegen
else if (!STRCMP (pr_token, "cd")
|| !STRCMP (pr_token, "origin")
|| !STRCMP (pr_token, "base")
|| !STRCMP (pr_token, "flags")
|| !STRCMP (pr_token, "scale")
|| !STRCMP (pr_token, "skin") )
{ // skip to end of line
while (QCC_PR_SimpleGetToken ())
;
QCC_PR_Lex ();
}
else if (!STRCMP (pr_token, "flush"))
{
QCC_PR_ClearGrabMacros();
while (QCC_PR_SimpleGetToken ())
;
QCC_PR_Lex ();
}
else if (!STRCMP (pr_token, "framevalue"))
{
QCC_PR_SimpleGetToken ();
pr_macrovalue = atoi(pr_token);
QCC_PR_Lex ();
}
else if (!STRCMP (pr_token, "framerestore"))
{
QCC_PR_SimpleGetToken ();
QCC_PR_ExpandMacro();
pr_macrovalue = (int)pr_immediate._float;
QCC_PR_Lex ();
}
else if (!STRCMP (pr_token, "modelname"))
{
int i;
QCC_PR_SimpleGetToken ();
if (*pr_framemodelname)
QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue);
strncpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname)-1);
pr_framemodelname[sizeof(pr_framemodelname)-1] = '\0';
i = QCC_PR_FindMacro(pr_framemodelname);
if (i)
pr_macrovalue = i;
else
i = 0;
QCC_PR_Lex ();
}
// look for a frame name macro
else
QCC_PR_ExpandMacro ();
}
//===========================
//compiler constants - dmw
pbool QCC_PR_UndefineName(char *name)
{
// int a;
CompilerConstant_t *c;
c = pHash_Get(&compconstantstable, name);
if (!c)
{
QCC_PR_ParseWarning(WARN_NOTDEFINED, "Precompiler constant %s was not defined", name);
return false;
}
Hash_Remove(&compconstantstable, name);
return true;
/*
a = c-CompilerConstant;
// for (a = 0; a < numCompilerConstants; a++)
{
// if (!STRCMP(name, CompilerConstant[a].name))
{
memmove(&CompilerConstant[a], &CompilerConstant[a+1], sizeof(CompilerConstant_t) * (numCompilerConstants-a));
numCompilerConstants--;
if (!STRCMP(name, "OP_NODUP"))
qccop_noduplicatestrings = false;
if (!STRCMP(name, "OP_COMP_ALL")) //group
{
QCC_PR_UndefineName("OP_COMP_STATEMENTS");
QCC_PR_UndefineName("OP_COMP_DEFS");
QCC_PR_UndefineName("OP_COMP_FIELDS");
QCC_PR_UndefineName("OP_COMP_FUNCTIONS");
QCC_PR_UndefineName("OP_COMP_STRINGS");
QCC_PR_UndefineName("OP_COMP_GLOBALS");
QCC_PR_UndefineName("OP_COMP_LINES");
QCC_PR_UndefineName("OP_COMP_TYPES");
}
return true;
}
}
// return false;
*/
}
CompilerConstant_t *QCC_PR_DefineName(char *name)
{
int i;
CompilerConstant_t *cnst;
// if (numCompilerConstants >= MAX_CONSTANTS)
// QCC_PR_ParseError("Too many compiler constants - %i >= %i", numCompilerConstants, MAX_CONSTANTS);
if (strlen(name) >= MAXCONSTANTLENGTH || !*name)
QCC_PR_ParseError(ERR_CONSTANTTOOLONG, "Compiler constant name length is too long or short");
cnst = pHash_Get(&compconstantstable, name);
if (cnst )
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "Duplicate definition for Precompiler constant %s", name);
Hash_Remove(&compconstantstable, name);
}
cnst = qccHunkAlloc(sizeof(CompilerConstant_t));
cnst->used = false;
cnst->numparams = 0;
strcpy(cnst->name, name);
cnst->namelen = strlen(name);
*cnst->value = '\0';
for (i = 0; i < MAXCONSTANTPARAMS; i++)
cnst->params[i][0] = '\0';
pHash_Add(&compconstantstable, cnst->name, cnst, qccHunkAlloc(sizeof(bucket_t)));
if (!STRCMP(name, "OP_NODUP"))
opt_noduplicatestrings = true;
if (!STRCMP(name, "OP_TIME")) //group - optimize for a fast compiler
{
QCC_PR_UndefineName("OP_SIZE");
QCC_PR_UndefineName("OP_SPEED");
QCC_PR_UndefineName("OP_NODUP");
QCC_PR_UndefineName("OP_COMP_ALL");
}
if (!STRCMP(name, "OP_SPEED")) //group - optimize run speed
{
QCC_PR_UndefineName("OP_SIZE");
QCC_PR_UndefineName("OP_TIME");
// QCC_PR_UndefineName("OP_NODUP");
QCC_PR_UndefineName("OP_COMP_ALL");
}
if (!STRCMP(name, "OP_SIZE")) //group - produce small output.
{
QCC_PR_UndefineName("OP_SPEED");
QCC_PR_UndefineName("OP_TIME");
QCC_PR_DefineName("OP_NODUP");
QCC_PR_DefineName("OP_COMP_ALL");
}
if (!STRCMP(name, "OP_COMP_ALL")) //group - compress the output
{
QCC_PR_DefineName("OP_COMP_STATEMENTS");
QCC_PR_DefineName("OP_COMP_DEFS");
QCC_PR_DefineName("OP_COMP_FIELDS");
QCC_PR_DefineName("OP_COMP_FUNCTIONS");
QCC_PR_DefineName("OP_COMP_STRINGS");
QCC_PR_DefineName("OP_COMP_GLOBALS");
QCC_PR_DefineName("OP_COMP_LINES");
QCC_PR_DefineName("OP_COMP_TYPES");
}
return cnst;
}
void QCC_PR_Undefine(void)
{
QCC_PR_SimpleGetToken ();
QCC_PR_UndefineName(pr_token);
// QCC_PR_ParseError("%s was not defined.", pr_token);
}
void QCC_PR_ConditionCompilation(void)
{
char *d;
char *s;
int quote=false;
CompilerConstant_t *cnst;
QCC_PR_SimpleGetToken ();
if (!QCC_PR_SimpleGetToken ())
QCC_PR_ParseError(ERR_NONAME, "No name defined for compiler constant");
cnst = pHash_Get(&compconstantstable, pr_token);
if (cnst)
{
Hash_Remove(&compconstantstable, pr_token);
QCC_PR_ParseWarning(WARN_DUPLICATEPRECOMPILER, "Duplicate definition of %s", pr_token);
}
cnst = QCC_PR_DefineName(pr_token);
if (*pr_file_p == '(')
{
s = pr_file_p+1;
while(*pr_file_p++)
{
if (*pr_file_p == ',')
{
strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
cnst->params[cnst->numparams][pr_file_p-s] = '\0';
cnst->numparams++;
if (cnst->numparams > MAXCONSTANTPARAMS)
QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
pr_file_p++;
s = pr_file_p;
}
if (*pr_file_p == ')')
{
strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
cnst->params[cnst->numparams][pr_file_p-s] = '\0';
cnst->numparams++;
if (cnst->numparams > MAXCONSTANTPARAMS)
QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
pr_file_p++;
break;
}
}
}
else cnst->numparams = -1;
s = pr_file_p;
d = cnst->value;
while(*s == ' ' || *s == '\t')
s++;
while(1)
{
if (*s == '\r' || *s == '\n' || *s == '\0')
{
if (s[-1] == '\\')
{
}
else if (s[-2] == '\\' && s[-1] == '\r' && s[0] == '\n')
{
}
else
break;
}
if (!quote && s[0]=='/'&&(s[1]=='/'||s[1]=='*'))
break;
if (*s == '\"')
quote=!quote;
*d = *s;
d++;
s++;
}
*d = '\0';
d--;
while(*d<= ' ' && d >= cnst->value)
*d-- = '\0';
if (strlen(cnst->value) >= sizeof(cnst->value)) //this is too late.
QCC_PR_ParseError(ERR_CONSTANTTOOLONG, "Macro %s too long (%i not %i)", cnst->name, strlen(cnst->value), sizeof(cnst->value));
}
char *daynames[] =
{
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
};
char *monthnames[] =
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
int QCC_PR_CheakCompConst(void)
{
char *oldpr_file_p = pr_file_p;
int whitestart;
CompilerConstant_t *c;
char *end;
for (end = pr_file_p; ; end++)
{
if (*end <= ' ')
break;
if (*end == ')'
|| *end == '('
|| *end == '+'
|| *end == '-'
|| *end == '*'
|| *end == '/'
|| *end == '|'
|| *end == '&'
|| *end == '='
|| *end == '^'
|| *end == '~'
|| *end == '['
|| *end == ']'
|| *end == '\"'
|| *end == '{'
|| *end == '}'
|| *end == ';'
|| *end == ':'
|| *end == ','
|| *end == '.'
|| *end == '#')
break;
}
strncpy(pr_token, pr_file_p, end-pr_file_p);
pr_token[end-pr_file_p]='\0';
if (!strcmp(pr_token, "varkeyword"))
printf("varkeyword!!!\n");
// printf("%s\n", pr_token);
c = pHash_Get(&compconstantstable, pr_token);
if (c)
{
pr_file_p = oldpr_file_p+strlen(c->name);
while(*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
if (c->numparams>=0)
{
if (*pr_file_p == '(')
{
int p;
char *start;
char buffer[1024];
char *paramoffset[MAXCONSTANTPARAMS+1];
int param=0;
int plevel=0;
pr_file_p++;
while(*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
start = pr_file_p;
while(1)
{
if (*pr_file_p == '(')
plevel++;
else if (!plevel && (*pr_file_p == ',' || *pr_file_p == ')'))
{
paramoffset[param++] = start;
start = pr_file_p+1;
if (*pr_file_p == ')')
{
*pr_file_p = '\0';
pr_file_p++;
break;
}
*pr_file_p = '\0';
pr_file_p++;
while(*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
if (param == MAXCONSTANTPARAMS)
QCC_PR_ParseError(ERR_TOOMANYPARAMS, "Too many parameters in macro call");
} else if (*pr_file_p == ')' )
plevel--;
if (!*pr_file_p)
QCC_PR_ParseError(ERR_EOF, "EOF on macro call");
pr_file_p++;
}
if (param < c->numparams)
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Not enough macro parameters");
paramoffset[param] = start;
*buffer = '\0';
oldpr_file_p = pr_file_p;
pr_file_p = c->value;
for(;;)
{
whitestart = p = strlen(buffer);
while(*pr_file_p <= ' ') //copy across whitespace
{
if (!*pr_file_p)
break;
buffer[p++] = *pr_file_p++;
}
buffer[p] = 0;
if (*pr_file_p == '#') //if you ask for #a##b you will be shot. use #a #b instead, or chain macros.
{
if (pr_file_p[1] == '#')
{ //concatinate (srip out whitespace)
buffer[whitestart] = '\0';
pr_file_p+=2;
}
else
{ //stringify
pr_file_p++;
pr_file_p = QCC_COM_Parse2(pr_file_p);
if (!pr_file_p)
break;
for (p = 0; p < param; p++)
{
if (!STRCMP(qcc_token, c->params[p]))
{
strcat(buffer, "\"");
strcat(buffer, paramoffset[p]);
strcat(buffer, "\"");
break;
}
}
if (p == param)
{
strcat(buffer, "#");
strcat(buffer, qcc_token);
QCC_PR_ParseWarning(0, "Stingification ignored");
}
continue; //already did this one
}
}
pr_file_p = QCC_COM_Parse2(pr_file_p);
if (!pr_file_p)
break;
for (p = 0; p < param; p++)
{
if (!STRCMP(qcc_token, c->params[p]))
{
strcat(buffer, paramoffset[p]);
break;
}
}
if (p == param)
strcat(buffer, qcc_token);
}
for (p = 0; p < param-1; p++)
paramoffset[p][strlen(paramoffset[p])] = ',';
paramoffset[p][strlen(paramoffset[p])] = ')';
pr_file_p = oldpr_file_p;
QCC_PR_IncludeChunk(buffer, true, NULL);
}
else
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without opening brace");
}
else
QCC_PR_IncludeChunk(c->value, false, NULL);
QCC_PR_Lex();
return true;
}
if (!strncmp(pr_file_p, "__TIME__", 8))
{
static char retbuf[256];
#ifdef WIN32
SYSTEMTIME Systime;
GetSystemTime(&Systime);
sprintf(retbuf, "\"%i:%i\"", Systime.wHour, Systime.wMinute);
#else //linux
sprintf(retbuf, "\"unknown time\"");
#endif
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
if (!strncmp(pr_file_p, "__DATE__", 8))
{
static char retbuf[256];
#ifdef WIN32
SYSTEMTIME Systime;
GetSystemTime(&Systime);
//dayname, day, month, year
sprintf(retbuf, "\"%s %i %s %i\"", daynames[Systime.wDayOfWeek], Systime.wDay, monthnames[Systime.wMonth], Systime.wYear);
#else //linux
sprintf(retbuf, "\"unknown date\"");
#endif
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
if (!strncmp(pr_file_p, "__FILE__", 8))
{
static char retbuf[256];
sprintf(retbuf, "\"%s\"", strings + s_file);
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
if (!strncmp(pr_file_p, "__LINE__", 8))
{
static char retbuf[256];
sprintf(retbuf, "\"%i\"", pr_source_line);
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
if (!strncmp(pr_file_p, "__FUNC__", 8))
{
static char retbuf[256];
sprintf(retbuf, "\"%s\"",pr_scope->name);
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
if (!strncmp(pr_file_p, "__NULL__", 8))
{
static char retbuf[256];
sprintf(retbuf, "~0");
pr_file_p = retbuf;
QCC_PR_Lex(); //translate the macro's value
pr_file_p = oldpr_file_p+8;
return true;
}
return false;
}
char *QCC_PR_CheakCompConstString(char *def)
{
char *s;
CompilerConstant_t *c;
c = pHash_Get(&compconstantstable, def);
if (c)
{
s = QCC_PR_CheakCompConstString(c->value);
return s;
}
return def;
}
CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def)
{
CompilerConstant_t *c = pHash_Get(&compconstantstable, def);
return c;
/*int a;
for (a = 0; a < numCompilerConstants; a++)
{
if (!strncmp(def, CompilerConstant[a].name, CompilerConstant[a].namelen+1))
return &CompilerConstant[a];
}
return NULL;
*/
}
//============================================================================
/*
==============
PR_Lex
Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
==============
*/
void QCC_PR_Lex (void)
{
int c;
pr_token[0] = 0;
if (!pr_file_p)
{
if (QCC_PR_UnInclude())
{
QCC_PR_Lex();
return;
}
pr_token_type = tt_eof;
return;
}
QCC_PR_LexWhitespace ();
if (!pr_file_p)
{
if (QCC_PR_UnInclude())
{
QCC_PR_Lex();
return;
}
pr_token_type = tt_eof;
return;
}
c = *pr_file_p;
if (!c)
{
if (QCC_PR_UnInclude())
{
QCC_PR_Lex();
return;
}
pr_token_type = tt_eof;
return;
}
// handle quoted strings as a unit
if (c == '\"')
{
QCC_PR_LexString ();
return;
}
// handle quoted vectors as a unit
if (c == '\'')
{
QCC_PR_LexVector ();
return;
}
// if the first character is a valid identifier, parse until a non-id
// character is reached
if ( c == '~' || c == '%') //let's see which one we make into an operator first... possibly both...
{
pr_file_p++;
pr_token_type = tt_immediate;
pr_immediate_type = type_integer;
pr_immediate._int = QCC_PR_LexInteger ();
return;
}
if ( c == '0' && pr_file_p[1] == 'x')
{
pr_token_type = tt_immediate;
QCC_PR_LexNumber();
return;
}
if ( (c == '.'&&pr_file_p[1] >='0' && pr_file_p[1] <= '9') || (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
{
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
pr_immediate._float = QCC_PR_LexFloat ();
// pr_token_type = tt_immediate;
// QCC_PR_LexNumber ();
return;
}
if (c == '#' && !(pr_file_p[1]=='-' || (pr_file_p[1]>='0' && pr_file_p[1] <='9'))) //hash and not number
{
pr_file_p++;
if (!QCC_PR_CheakCompConst())
{
if (!QCC_PR_SimpleGetToken())
strcpy(pr_token, "unknown");
QCC_PR_ParseError(ERR_CONSTANTNOTDEFINED, "Explicit precompiler usage when not defined %s", pr_token);
}
else
if (pr_token_type == tt_eof)
QCC_PR_Lex();
return;
}
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
{
if (!QCC_PR_CheakCompConst()) //look for a macro.
QCC_PR_LexName ();
else
if (pr_token_type == tt_eof)
{
if (QCC_PR_UnInclude())
{
QCC_PR_Lex();
return;
}
pr_token_type = tt_eof;
}
return;
}
if (c == '$')
{
QCC_PR_LexGrab ();
return;
}
// parse symbol strings until a non-symbol is found
QCC_PR_LexPunctuation ();
}
//=============================================================================
void QCC_PR_ParsePrintDef (int type, QCC_def_t *def)
{
if (qccwarningdisabled[type])
return;
if (def->s_file)
printf ("%s:%i: %s is defined here\n", strings + def->s_file, def->s_line, def->name);
}
/*
============
PR_ParseError
Aborts the current file load
============
*/
#ifndef QCC
void editbadfile(char *file, int line);
#endif
void VARGS QCC_PR_ParseError (int errortype, char *error, ...)
{
va_list argptr;
char string[1024];
va_start (argptr,error);
QC_vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
#ifndef QCC
editbadfile(strings+s_file, pr_source_line);
#endif
printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
longjmp (pr_parse_abort, 1);
}
void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, char *error, ...)
{
va_list argptr;
char string[1024];
va_start (argptr,error);
QC_vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
#ifndef QCC
editbadfile(strings+s_file, pr_source_line);
#endif
printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
QCC_PR_ParsePrintDef(WARN_ERROR, def);
longjmp (pr_parse_abort, 1);
}
void VARGS QCC_PR_ParseWarning (int type, char *error, ...)
{
va_list argptr;
char string[1024];
if (type < ERR_PARSEERRORS && qccwarningdisabled[type])
return;
va_start (argptr,error);
QC_vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
if (type >= ERR_PARSEERRORS)
{
printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
pr_error_count++;
}
else
printf ("%s:%i: warning: %s\n", strings + s_file, pr_source_line, string);
}
void VARGS QCC_PR_Warning (int type, char *file, int line, char *error, ...)
{
va_list argptr;
char string[1024];
if (qccwarningdisabled[type])
return;
va_start (argptr,error);
QC_vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
if (file)
printf ("%s:%i: warning: %s\n", file, line, string);
else
printf ("warning: %s\n", string);
}
/*
=============
PR_Expect
Issues an error if the current token isn't equal to string
Gets the next token
=============
*/
#ifndef COMMONINLINES
void QCC_PR_Expect (char *string)
{
if (STRCMP (string, pr_token))
QCC_PR_ParseError (ERR_EXPECTED, "expected %s, found %s",string, pr_token);
QCC_PR_Lex ();
}
#endif
/*
=============
PR_Check
Returns true and gets the next token if the current token equals string
Returns false and does nothing otherwise
=============
*/
#ifndef COMMONINLINES
pbool QCC_PR_Check (char *string)
{
if (STRCMP (string, pr_token))
return false;
QCC_PR_Lex ();
return true;
}
#endif
pbool QCC_PR_CheckInsens (char *string)
{
if (stricmp (string, pr_token))
return false;
QCC_PR_Lex ();
return true;
}
/*
============
PR_ParseName
Checks to see if the current token is a valid name
============
*/
char *QCC_PR_ParseName (void)
{
static char ident[MAX_NAME];
char *ret;
if (pr_token_type != tt_name)
QCC_PR_ParseError (ERR_NOTANAME, "\"%s\" - not a name", pr_token);
if (strlen(pr_token) >= MAX_NAME-1)
QCC_PR_ParseError (ERR_NAMETOOLONG, "name too long");
strcpy (ident, pr_token);
QCC_PR_Lex ();
ret = qccHunkAlloc(strlen(ident)+1);
strcpy(ret, ident);
return ret;
// return ident;
}
/*
============
PR_FindType
Returns a preexisting complex type that matches the parm, or allocates
a new one and copies it out.
============
*/
//0 if same
QCC_type_t *QCC_PR_NewType (char *name, int basictype);
int typecmp(QCC_type_t *a, QCC_type_t *b)
{
if (a == b)
return 0;
if (!a || !b)
return 1; //different (^ and not both null)
if (a->type != b->type)
return 1;
if (a->num_parms != b->num_parms)
return 1;
if (a->size != b->size)
return 1;
// if (STRCMP(a->name, b->name)) //This isn't 100% clean.
// return 1;
if (typecmp(a->aux_type, b->aux_type))
return 1;
if (a->param || b->param)
{
a = a->param;
b = b->param;
while(a || b)
{
if (typecmp(a, b))
return 1;
a=a->next;
b=b->next;
}
}
return 0;
}
QCC_type_t *QCC_PR_DuplicateType(QCC_type_t *in)
{
QCC_type_t *out, *op, *ip;
if (!in)
return NULL;
out = QCC_PR_NewType(in->name, in->type);
out->aux_type = QCC_PR_DuplicateType(in->aux_type);
out->param = QCC_PR_DuplicateType(in->param);
ip = in->param;
op = NULL;
while(ip)
{
if (!op)
out->param = op = QCC_PR_DuplicateType(ip);
else
op = (op->next = QCC_PR_DuplicateType(ip));
ip = ip->next;
}
out->size = in->size;
out->num_parms = in->num_parms;
out->ofs = in->ofs;
out->name = in->name;
out->parentclass = in->parentclass;
return out;
}
char *TypeName(QCC_type_t *type)
{
static char buffer[2][512];
static int op;
char *ret;
op++;
ret = buffer[op&1];
if (type->type == ev_field)
{
type = type->aux_type;
*ret++ = '.';
}
*ret = 0;
if (type->type == ev_function)
{
strcat(ret, type->aux_type->name);
strcat(ret, " (");
type = type->param;
while(type)
{
strcat(ret, type->name);
type = type->next;
if (type)
strcat(ret, ", ");
}
strcat(ret, ")");
}
else if (type->type == ev_entity && type->parentclass)
{
op++;
ret = buffer[op&1];
*ret = 0;
strcat(ret, "class ");
strcat(ret, type->name);
/* strcat(ret, " {");
type = type->param;
while(type)
{
strcat(ret, type->name);
type = type->next;
if (type)
strcat(ret, ", ");
}
strcat(ret, "}");
*/
}
else
strcpy(ret, type->name);
return buffer[op&1];
}
//#define typecmp(a, b) (a && ((a)->type==(b)->type) && !STRCMP((a)->name, (b)->name))
QCC_type_t *QCC_PR_FindType (QCC_type_t *type)
{
int t;
for (t = 0; t < numtypeinfos; t++)
{
// check = &qcc_typeinfo[t];
if (typecmp(&qcc_typeinfo[t], type))
continue;
// c2 = check->next;
// n2 = type->next;
// for (i=0 ; n2&&c2 ; i++)
// {
// if (!typecmp((c2), (n2)))
// break;
// c2=c2->next;
// n2=n2->next;
// }
// if (n2==NULL&&c2==NULL)
{
return &qcc_typeinfo[t];
}
}
QCC_Error(ERR_INTERNAL, "Error with type");
return type;
}
/*
QCC_type_t *QCC_PR_NextSubType(QCC_type_t *type, QCC_type_t *prev)
{
int p;
if (!prev)
return type->next;
for (p = prev->num_parms; p; p--)
prev = QCC_PR_NextSubType(prev, NULL);
if (prev->num_parms)
switch(prev->type)
{
case ev_function:
}
return prev->next;
}
*/
QCC_type_t *QCC_TypeForName(char *name)
{
int i;
for (i = 0; i < numtypeinfos; i++)
{
if (!STRCMP(qcc_typeinfo[i].name, name))
{
return &qcc_typeinfo[i];
}
}
return NULL;
}
/*
============
PR_SkipToSemicolon
For error recovery, also pops out of nested braces
============
*/
void QCC_PR_SkipToSemicolon (void)
{
do
{
if (!pr_bracelevel && QCC_PR_Check (";"))
return;
QCC_PR_Lex ();
} while (pr_token_type != tt_eof);
}
/*
============
PR_ParseType
Parses a variable type, including field and functions types
============
*/
#ifdef MAX_EXTRA_PARMS
char pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME];
#else
char pr_parm_names[MAX_PARMS][MAX_NAME];
#endif
pbool recursivefunctiontype;
QCC_type_t *QCC_PR_NewType (char *name, int basictype);
//expects a ( to have already been parsed.
QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
{
QCC_type_t *ftype, *ptype, *nptype;
char *name;
int definenames = !recursivefunctiontype;
recursivefunctiontype++;
ftype = QCC_PR_NewType(type_function->name, ev_function);
ftype->aux_type = returntype; // return type
ftype->num_parms = 0;
ptype = NULL;
if (!QCC_PR_Check (")"))
{
if (QCC_PR_Check ("..."))
ftype->num_parms = -1; // variable args
else
do
{
if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
if (QCC_PR_Check ("..."))
{
ftype->num_parms = (ftype->num_parms * -1) - 1;
break;
}
nptype = QCC_PR_ParseType(true);
if (nptype->type == ev_void)
break;
if (!ptype)
{
ptype = nptype;
ftype->param = ptype;
}
else
{
ptype->next = nptype;
ptype = ptype->next;
}
// type->name = "FUNC PARAMETER";
if (STRCMP(pr_token, ",") && STRCMP(pr_token, ")"))
{
name = QCC_PR_ParseName ();
if (definenames)
strcpy (pr_parm_names[ftype->num_parms], name);
}
else if (definenames)
strcpy (pr_parm_names[ftype->num_parms], "");
ftype->num_parms++;
} while (QCC_PR_Check (","));
QCC_PR_Expect (")");
}
recursivefunctiontype--;
if (newtype)
return ftype;
return QCC_PR_FindType (ftype);
}
QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
{
QCC_type_t *ftype, *ptype, *nptype;
char *name;
char argname[64];
int definenames = !recursivefunctiontype;
pbool usesvariants = false;
recursivefunctiontype++;
ftype = QCC_PR_NewType(type_function->name, ev_function);
ftype->aux_type = returntype; // return type
ftype->num_parms = 0;
ptype = NULL;
if (!QCC_PR_Check (")"))
{
if (QCC_PR_Check ("..."))
ftype->num_parms = -1; // variable args
else
do
{
if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
if (QCC_PR_Check ("..."))
{
ftype->num_parms = (ftype->num_parms * -1) - 1;
break;
}
if (QCC_PR_Check("arg"))
{
sprintf(argname, "arg%i", ftype->num_parms);
name = argname;
nptype = QCC_PR_NewType("Variant", ev_variant);
}
else if (QCC_PR_Check("vect")) //this can only be of vector sizes, so...
{
sprintf(argname, "arg%i", ftype->num_parms);
name = argname;
nptype = QCC_PR_NewType("Vector", ev_vector);
}
else
{
name = QCC_PR_ParseName();
QCC_PR_Expect(":");
nptype = QCC_PR_ParseType(true);
}
if (nptype->type == ev_void)
break;
if (!ptype)
{
ptype = nptype;
ftype->param = ptype;
}
else
{
ptype->next = nptype;
ptype = ptype->next;
}
// type->name = "FUNC PARAMETER";
if (definenames)
strcpy (pr_parm_names[ftype->num_parms], name);
ftype->num_parms++;
} while (QCC_PR_Check (";"));
QCC_PR_Expect (")");
}
recursivefunctiontype--;
if (newtype)
return ftype;
return QCC_PR_FindType (ftype);
}
QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto)
{
QCC_type_t *ptype;
char name[128];
sprintf(name, "*%s", pointsto->name);
ptype = QCC_PR_NewType(name, ev_pointer);
ptype->aux_type = pointsto;
return QCC_PR_FindType (ptype);
}
QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto)
{
QCC_type_t *ptype;
char name[128];
sprintf(name, "FIELD TYPE(%s)", pointsto->name);
ptype = QCC_PR_NewType(name, ev_field);
ptype->aux_type = pointsto;
ptype->size = ptype->aux_type->size;
return QCC_PR_FindType (ptype);
}
QCC_type_t *QCC_PR_ParseType (int newtype)
{
QCC_type_t *newparm;
QCC_type_t *newt;
QCC_type_t *type;
char *name;
int i;
// int ofs;
if (QCC_PR_Check ("..")) //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);
newt->aux_type = QCC_PR_ParseType (false);
newt->size = newt->aux_type->size;
newt = QCC_PR_FindType (newt);
type = QCC_PR_NewType("FIELD TYPE", ev_field);
type->aux_type = newt;
type->size = type->aux_type->size;
if (newtype)
return type;
return QCC_PR_FindType (type);
}
if (QCC_PR_Check ("."))
{
newt = QCC_PR_NewType("FIELD TYPE", ev_field);
newt->aux_type = QCC_PR_ParseType (false);
newt->size = newt->aux_type->size;
if (newtype)
return newt;
return QCC_PR_FindType (newt);
}
name = QCC_PR_CheakCompConstString(pr_token);
if (QCC_PR_Check ("class"))
{
// int parms;
QCC_type_t *fieldtype;
char membername[2048];
char *classname = QCC_PR_ParseName();
newt = QCC_PR_NewType(classname, ev_entity);
newt->size=type_entity->size;
type = NULL;
if (QCC_PR_Check(":"))
{
char *parentname = QCC_PR_ParseName();
newt->parentclass = QCC_TypeForName(parentname);
if (!newt->parentclass)
QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not defined", parentname);
}
else
newt->parentclass = type_entity;
QCC_PR_Expect("{");
if (QCC_PR_Check(","))
QCC_PR_ParseError(ERR_NOTANAME, "member missing name");
while (!QCC_PR_Check("}"))
{
// if (QCC_PR_Check(","))
// type->next = QCC_PR_NewType(type->name, type->type);
// else
newparm = QCC_PR_ParseType(true);
if (newparm->type == ev_struct || newparm->type == ev_union) //we wouldn't be able to handle it.
QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
if (!QCC_PR_Check(";"))
{
newparm->name = QCC_CopyString(pr_token)+strings;
QCC_PR_Lex();
if (QCC_PR_Check("["))
{
type->next->size*=atoi(pr_token);
QCC_PR_Lex();
QCC_PR_Expect("]");
}
QCC_PR_Check(";");
}
else
newparm->name = QCC_CopyString("")+strings;
sprintf(membername, "%s::"MEMBERFIELDNAME, classname, newparm->name);
fieldtype = QCC_PR_NewType(newparm->name, ev_field);
fieldtype->aux_type = newparm;
QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 1);
newparm->ofs = newt->size;
newt->num_parms++;
if (type)
type->next = newparm;
else
newt->param = newparm;
type = newparm;
}
QCC_PR_Expect(";");
return NULL;
}
if (QCC_PR_Check ("struct"))
{
newt = QCC_PR_NewType("struct", ev_struct);
newt->size=0;
QCC_PR_Expect("{");
type = NULL;
if (QCC_PR_Check(","))
QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
newparm = NULL;
while (!QCC_PR_Check("}"))
{
if (QCC_PR_Check(","))
{
if (!newparm)
QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
newparm = QCC_PR_NewType(newparm->name, newparm->type);
}
else
newparm = QCC_PR_ParseType(true);
if (!QCC_PR_Check(";"))
{
newparm->name = QCC_CopyString(pr_token)+strings;
QCC_PR_Lex();
if (QCC_PR_Check("["))
{
newparm->size*=atoi(pr_token);
QCC_PR_Lex();
QCC_PR_Expect("]");
}
QCC_PR_Check(";");
}
else
newparm->name = QCC_CopyString("")+strings;
newparm->ofs = newt->size;
newt->size += newparm->size;
newt->num_parms++;
if (type)
type->next = newparm;
else
newt->param = newparm;
type = newparm;
}
return newt;
}
if (QCC_PR_Check ("union"))
{
newt = QCC_PR_NewType("union", ev_union);
newt->size=0;
QCC_PR_Expect("{");
type = NULL;
if (QCC_PR_Check(","))
QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
newparm = NULL;
while (!QCC_PR_Check("}"))
{
if (QCC_PR_Check(","))
{
if (!newparm)
QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
newparm = QCC_PR_NewType(newparm->name, newparm->type);
}
else
newparm = QCC_PR_ParseType(true);
if (QCC_PR_Check(";"))
newparm->name = QCC_CopyString("")+strings;
else
{
newparm->name = QCC_CopyString(pr_token)+strings;
QCC_PR_Lex();
QCC_PR_Expect(";");
}
newparm->ofs = 0;
if (newparm->size > newt->size)
newt->size = newparm->size;
newt->num_parms++;
if (type)
type->next = newparm;
else
newt->param = newparm;
type = newparm;
}
return newt;
}
type = NULL;
for (i = 0; i < numtypeinfos; i++)
{
if (!STRCMP(qcc_typeinfo[i].name, name))
{
type = &qcc_typeinfo[i];
break;
}
}
if (i == numtypeinfos)
{
if (!*name)
return NULL;
if (!stricmp("Void", name))
type = type_void;
else if (!stricmp("Real", name))
type = type_float;
else if (!stricmp("Vector", name))
type = type_vector;
else if (!stricmp("Object", name))
type = type_entity;
else if (!stricmp("String", name))
type = type_string;
else if (!stricmp("PFunc", name))
type = type_function;
else
{
QCC_PR_ParseError (ERR_NOTATYPE, "\"%s\" is not a type", name);
type = type_float; // shut up compiler warning
}
}
QCC_PR_Lex ();
if (QCC_PR_Check ("(")) //this is followed by parameters. Must be a function.
return QCC_PR_ParseFunctionType(newtype, type);
else
{
if (newtype)
{
type = QCC_PR_DuplicateType(type);
}
return type;
}
}
#endif