mirror of
https://github.com/id-Software/Quake-Tools.git
synced 2026-03-20 00:49:35 +01:00
The source release of the qutils.
This commit is contained in:
42
qutils/QCC/MAKEFILE
Normal file
42
qutils/QCC/MAKEFILE
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
EXES = qcc
|
||||
NTEXES = qcc.exe
|
||||
|
||||
#==============================================================================
|
||||
|
||||
EXT= .o
|
||||
|
||||
all: $(EXES)
|
||||
|
||||
clean:
|
||||
rm *.o *.obj $(EXES) $(NTEXES)
|
||||
|
||||
next:
|
||||
make "CFLAGS = -g -Wall -I.."
|
||||
|
||||
nextinstall:
|
||||
make "CFLAGS = -O4 -g -Wall -I.. -arch i386 -arch hppa"
|
||||
cp $(EXES) /LocalApps
|
||||
|
||||
alpha:
|
||||
make "CFLAGS = -g -I.." "LDFLAGS = -lm"
|
||||
|
||||
alphainstall:
|
||||
make "CFLAGS = -O4 -I.." "LDFLAGS = -lm"
|
||||
cp $(EXES) /LocalApps
|
||||
|
||||
nt:
|
||||
nmake /nologo "CFLAGS = -nologo -Zi -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
|
||||
|
||||
ntinstall:
|
||||
nmake /nologo "CFLAGS = -nologo -Ox -G5 -DWIN32 -I.." "LDFLAGS = " "EXT = .obj"
|
||||
cp $(NTEXES) f:\nt\id
|
||||
|
||||
#==============================================================================
|
||||
|
||||
QCCFILES = qcc$(EXT) pr_lex$(EXT) pr_comp$(EXT) cmdlib$(EXT)
|
||||
qcc : $(QCCFILES)
|
||||
$(CC) $(CFLAGS) -o qcc $(QCCFILES)
|
||||
|
||||
cmdlib$(EXT) : ../cmdlib.c
|
||||
$(CC) $(CFLAGS) -c -o cmdlib$(EXT) ../cmdlib.c
|
||||
936
qutils/QCC/PR_COMP.C
Normal file
936
qutils/QCC/PR_COMP.C
Normal file
@@ -0,0 +1,936 @@
|
||||
|
||||
#include "qcc.h"
|
||||
|
||||
|
||||
pr_info_t pr;
|
||||
def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable
|
||||
int pr_edict_size;
|
||||
|
||||
//========================================
|
||||
|
||||
def_t *pr_scope; // the function being parsed, or NULL
|
||||
qboolean pr_dumpasm;
|
||||
string_t s_file; // filename for function definition
|
||||
|
||||
int locals_end; // for tracking local variables vs temps
|
||||
|
||||
jmp_buf pr_parse_abort; // longjump with this on parse error
|
||||
|
||||
void PR_ParseDefs (void);
|
||||
|
||||
//========================================
|
||||
|
||||
|
||||
opcode_t pr_opcodes[] =
|
||||
{
|
||||
{"<DONE>", "DONE", -1, false, &def_entity, &def_field, &def_void},
|
||||
|
||||
{"*", "MUL_F", 2, false, &def_float, &def_float, &def_float},
|
||||
{"*", "MUL_V", 2, false, &def_vector, &def_vector, &def_float},
|
||||
{"*", "MUL_FV", 2, false, &def_float, &def_vector, &def_vector},
|
||||
{"*", "MUL_VF", 2, false, &def_vector, &def_float, &def_vector},
|
||||
|
||||
{"/", "DIV", 2, false, &def_float, &def_float, &def_float},
|
||||
|
||||
{"+", "ADD_F", 3, false, &def_float, &def_float, &def_float},
|
||||
{"+", "ADD_V", 3, false, &def_vector, &def_vector, &def_vector},
|
||||
|
||||
{"-", "SUB_F", 3, false, &def_float, &def_float, &def_float},
|
||||
{"-", "SUB_V", 3, false, &def_vector, &def_vector, &def_vector},
|
||||
|
||||
{"==", "EQ_F", 4, false, &def_float, &def_float, &def_float},
|
||||
{"==", "EQ_V", 4, false, &def_vector, &def_vector, &def_float},
|
||||
{"==", "EQ_S", 4, false, &def_string, &def_string, &def_float},
|
||||
{"==", "EQ_E", 4, false, &def_entity, &def_entity, &def_float},
|
||||
{"==", "EQ_FNC", 4, false, &def_function, &def_function, &def_float},
|
||||
|
||||
{"!=", "NE_F", 4, false, &def_float, &def_float, &def_float},
|
||||
{"!=", "NE_V", 4, false, &def_vector, &def_vector, &def_float},
|
||||
{"!=", "NE_S", 4, false, &def_string, &def_string, &def_float},
|
||||
{"!=", "NE_E", 4, false, &def_entity, &def_entity, &def_float},
|
||||
{"!=", "NE_FNC", 4, false, &def_function, &def_function, &def_float},
|
||||
|
||||
{"<=", "LE", 4, false, &def_float, &def_float, &def_float},
|
||||
{">=", "GE", 4, false, &def_float, &def_float, &def_float},
|
||||
{"<", "LT", 4, false, &def_float, &def_float, &def_float},
|
||||
{">", "GT", 4, false, &def_float, &def_float, &def_float},
|
||||
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_float},
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_vector},
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_string},
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_entity},
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_field},
|
||||
{".", "INDIRECT", 1, false, &def_entity, &def_field, &def_function},
|
||||
|
||||
{".", "ADDRESS", 1, false, &def_entity, &def_field, &def_pointer},
|
||||
|
||||
{"=", "STORE_F", 5, true, &def_float, &def_float, &def_float},
|
||||
{"=", "STORE_V", 5, true, &def_vector, &def_vector, &def_vector},
|
||||
{"=", "STORE_S", 5, true, &def_string, &def_string, &def_string},
|
||||
{"=", "STORE_ENT", 5, true, &def_entity, &def_entity, &def_entity},
|
||||
{"=", "STORE_FLD", 5, true, &def_field, &def_field, &def_field},
|
||||
{"=", "STORE_FNC", 5, true, &def_function, &def_function, &def_function},
|
||||
|
||||
{"=", "STOREP_F", 5, true, &def_pointer, &def_float, &def_float},
|
||||
{"=", "STOREP_V", 5, true, &def_pointer, &def_vector, &def_vector},
|
||||
{"=", "STOREP_S", 5, true, &def_pointer, &def_string, &def_string},
|
||||
{"=", "STOREP_ENT", 5, true, &def_pointer, &def_entity, &def_entity},
|
||||
{"=", "STOREP_FLD", 5, true, &def_pointer, &def_field, &def_field},
|
||||
{"=", "STOREP_FNC", 5, true, &def_pointer, &def_function, &def_function},
|
||||
|
||||
{"<RETURN>", "RETURN", -1, false, &def_void, &def_void, &def_void},
|
||||
|
||||
{"!", "NOT_F", -1, false, &def_float, &def_void, &def_float},
|
||||
{"!", "NOT_V", -1, false, &def_vector, &def_void, &def_float},
|
||||
{"!", "NOT_S", -1, false, &def_vector, &def_void, &def_float},
|
||||
{"!", "NOT_ENT", -1, false, &def_entity, &def_void, &def_float},
|
||||
{"!", "NOT_FNC", -1, false, &def_function, &def_void, &def_float},
|
||||
|
||||
{"<IF>", "IF", -1, false, &def_float, &def_float, &def_void},
|
||||
{"<IFNOT>", "IFNOT", -1, false, &def_float, &def_float, &def_void},
|
||||
|
||||
// calls returns REG_RETURN
|
||||
{"<CALL0>", "CALL0", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL1>", "CALL1", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL2>", "CALL2", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL3>", "CALL3", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL4>", "CALL4", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL5>", "CALL5", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL6>", "CALL6", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL7>", "CALL7", -1, false, &def_function, &def_void, &def_void},
|
||||
{"<CALL8>", "CALL8", -1, false, &def_function, &def_void, &def_void},
|
||||
|
||||
{"<STATE>", "STATE", -1, false, &def_float, &def_float, &def_void},
|
||||
|
||||
{"<GOTO>", "GOTO", -1, false, &def_float, &def_void, &def_void},
|
||||
|
||||
{"&&", "AND", 6, false, &def_float, &def_float, &def_float},
|
||||
{"||", "OR", 6, false, &def_float, &def_float, &def_float},
|
||||
|
||||
{"&", "BITAND", 2, false, &def_float, &def_float, &def_float},
|
||||
{"|", "BITOR", 2, false, &def_float, &def_float, &def_float},
|
||||
|
||||
{NULL}
|
||||
};
|
||||
|
||||
#define TOP_PRIORITY 6
|
||||
#define NOT_PRIORITY 4
|
||||
|
||||
def_t *PR_Expression (int priority);
|
||||
|
||||
def_t junkdef;
|
||||
|
||||
//===========================================================================
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_Statement
|
||||
|
||||
Emits a primitive statement, returning the var it places it's value in
|
||||
============
|
||||
*/
|
||||
def_t *PR_Statement ( opcode_t *op, def_t *var_a, def_t *var_b)
|
||||
{
|
||||
dstatement_t *statement;
|
||||
def_t *var_c;
|
||||
|
||||
statement = &statements[numstatements];
|
||||
numstatements++;
|
||||
|
||||
statement_linenums[statement-statements] = pr_source_line;
|
||||
statement->op = op - pr_opcodes;
|
||||
statement->a = var_a ? var_a->ofs : 0;
|
||||
statement->b = var_b ? var_b->ofs : 0;
|
||||
if (op->type_c == &def_void || op->right_associative)
|
||||
{
|
||||
var_c = NULL;
|
||||
statement->c = 0; // ifs, gotos, and assignments
|
||||
// don't need vars allocated
|
||||
}
|
||||
else
|
||||
{ // allocate result space
|
||||
var_c = malloc (sizeof(def_t));
|
||||
memset (var_c, 0, sizeof(def_t));
|
||||
var_c->ofs = numpr_globals;
|
||||
var_c->type = op->type_c->type;
|
||||
|
||||
statement->c = numpr_globals;
|
||||
numpr_globals += type_size[op->type_c->type->type];
|
||||
}
|
||||
|
||||
if (op->right_associative)
|
||||
return var_a;
|
||||
return var_c;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseImmediate
|
||||
|
||||
Looks for a preexisting constant
|
||||
============
|
||||
*/
|
||||
def_t *PR_ParseImmediate (void)
|
||||
{
|
||||
def_t *cn;
|
||||
|
||||
// check for a constant with the same value
|
||||
for (cn=pr.def_head.next ; cn ; cn=cn->next)
|
||||
{
|
||||
if (!cn->initialized)
|
||||
continue;
|
||||
if (cn->type != pr_immediate_type)
|
||||
continue;
|
||||
if (pr_immediate_type == &type_string)
|
||||
{
|
||||
if (!strcmp(G_STRING(cn->ofs), pr_immediate_string) )
|
||||
{
|
||||
PR_Lex ();
|
||||
return cn;
|
||||
}
|
||||
}
|
||||
else if (pr_immediate_type == &type_float)
|
||||
{
|
||||
if ( G_FLOAT(cn->ofs) == pr_immediate._float )
|
||||
{
|
||||
PR_Lex ();
|
||||
return cn;
|
||||
}
|
||||
}
|
||||
else if (pr_immediate_type == &type_vector)
|
||||
{
|
||||
if ( ( G_FLOAT(cn->ofs) == pr_immediate.vector[0] )
|
||||
&& ( G_FLOAT(cn->ofs+1) == pr_immediate.vector[1] )
|
||||
&& ( G_FLOAT(cn->ofs+2) == pr_immediate.vector[2] ) )
|
||||
{
|
||||
PR_Lex ();
|
||||
return cn;
|
||||
}
|
||||
}
|
||||
else
|
||||
PR_ParseError ("weird immediate type");
|
||||
}
|
||||
|
||||
// allocate a new one
|
||||
cn = malloc (sizeof(def_t));
|
||||
cn->next = NULL;
|
||||
|
||||
pr.def_tail->next = cn;
|
||||
pr.def_tail = cn;
|
||||
|
||||
cn->search_next = pr.search;
|
||||
pr.search = cn;
|
||||
|
||||
cn->type = pr_immediate_type;
|
||||
cn->name = "IMMEDIATE";
|
||||
cn->initialized = 1;
|
||||
cn->scope = NULL; // always share immediates
|
||||
|
||||
// copy the immediate to the global area
|
||||
cn->ofs = numpr_globals;
|
||||
pr_global_defs[cn->ofs] = cn;
|
||||
numpr_globals += type_size[pr_immediate_type->type];
|
||||
if (pr_immediate_type == &type_string)
|
||||
pr_immediate.string = CopyString (pr_immediate_string);
|
||||
|
||||
memcpy (pr_globals + cn->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]);
|
||||
|
||||
PR_Lex ();
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
|
||||
void PrecacheSound (def_t *e, int ch)
|
||||
{
|
||||
char *n;
|
||||
int i;
|
||||
|
||||
if (!e->ofs)
|
||||
return;
|
||||
n = G_STRING(e->ofs);
|
||||
for (i=0 ; i<numsounds ; i++)
|
||||
if (!strcmp(n, precache_sounds[i]))
|
||||
return;
|
||||
if (numsounds == MAX_SOUNDS)
|
||||
Error ("PrecacheSound: numsounds == MAX_SOUNDS");
|
||||
strcpy (precache_sounds[i], n);
|
||||
if (ch >= '1' && ch <= '9')
|
||||
precache_sounds_block[i] = ch - '0';
|
||||
else
|
||||
precache_sounds_block[i] = 1;
|
||||
numsounds++;
|
||||
}
|
||||
|
||||
void PrecacheModel (def_t *e, int ch)
|
||||
{
|
||||
char *n;
|
||||
int i;
|
||||
|
||||
if (!e->ofs)
|
||||
return;
|
||||
n = G_STRING(e->ofs);
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
if (!strcmp(n, precache_models[i]))
|
||||
return;
|
||||
if (numsounds == MAX_SOUNDS)
|
||||
Error ("PrecacheModels: numsounds == MAX_SOUNDS");
|
||||
strcpy (precache_models[i], n);
|
||||
if (ch >= '1' && ch <= '9')
|
||||
precache_models_block[i] = ch - '0';
|
||||
else
|
||||
precache_models_block[i] = 1;
|
||||
nummodels++;
|
||||
}
|
||||
|
||||
void PrecacheFile (def_t *e, int ch)
|
||||
{
|
||||
char *n;
|
||||
int i;
|
||||
|
||||
if (!e->ofs)
|
||||
return;
|
||||
n = G_STRING(e->ofs);
|
||||
for (i=0 ; i<numfiles ; i++)
|
||||
if (!strcmp(n, precache_files[i]))
|
||||
return;
|
||||
if (numfiles == MAX_FILES)
|
||||
Error ("PrecacheFile: numfiles == MAX_FILES");
|
||||
strcpy (precache_files[i], n);
|
||||
if (ch >= '1' && ch <= '9')
|
||||
precache_files_block[i] = ch - '0';
|
||||
else
|
||||
precache_files_block[i] = 1;
|
||||
numfiles++;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseFunctionCall
|
||||
============
|
||||
*/
|
||||
def_t *PR_ParseFunctionCall (def_t *func)
|
||||
{
|
||||
def_t *e;
|
||||
int arg;
|
||||
type_t *t;
|
||||
|
||||
t = func->type;
|
||||
|
||||
if (t->type != ev_function)
|
||||
PR_ParseError ("not a function");
|
||||
|
||||
// copy the arguments to the global parameter variables
|
||||
arg = 0;
|
||||
if (!PR_Check(")"))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (t->num_parms != -1 && arg >= t->num_parms)
|
||||
PR_ParseError ("too many parameters");
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
|
||||
if (arg == 0 && func->name)
|
||||
{
|
||||
// save information for model and sound caching
|
||||
if (!strncmp(func->name,"precache_sound", 14))
|
||||
PrecacheSound (e, func->name[14]);
|
||||
else if (!strncmp(func->name,"precache_model", 14))
|
||||
PrecacheModel (e, func->name[14]);
|
||||
else if (!strncmp(func->name,"precache_file", 13))
|
||||
PrecacheFile (e, func->name[13]);
|
||||
}
|
||||
|
||||
if (t->num_parms != -1 && ( e->type != t->parm_types[arg] ) )
|
||||
PR_ParseError ("type mismatch on parm %i", arg);
|
||||
// a vector copy will copy everything
|
||||
def_parms[arg].type = t->parm_types[arg];
|
||||
PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]);
|
||||
arg++;
|
||||
} while (PR_Check (","));
|
||||
|
||||
if (t->num_parms != -1 && arg != t->num_parms)
|
||||
PR_ParseError ("too few parameters");
|
||||
PR_Expect (")");
|
||||
}
|
||||
if (arg >8)
|
||||
PR_ParseError ("More than eight parameters");
|
||||
|
||||
|
||||
PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0);
|
||||
|
||||
def_ret.type = t->aux_type;
|
||||
return &def_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseValue
|
||||
|
||||
Returns the global ofs for the current token
|
||||
============
|
||||
*/
|
||||
def_t *PR_ParseValue (void)
|
||||
{
|
||||
def_t *d;
|
||||
char *name;
|
||||
|
||||
// if the token is an immediate, allocate a constant for it
|
||||
if (pr_token_type == tt_immediate)
|
||||
return PR_ParseImmediate ();
|
||||
|
||||
name = PR_ParseName ();
|
||||
|
||||
// look through the defs
|
||||
d = PR_GetDef (NULL, name, pr_scope, false);
|
||||
if (!d)
|
||||
PR_ParseError ("Unknown value \"%s\"", name);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_Term
|
||||
============
|
||||
*/
|
||||
def_t *PR_Term (void)
|
||||
{
|
||||
def_t *e, *e2;
|
||||
etype_t t;
|
||||
|
||||
if (PR_Check ("!"))
|
||||
{
|
||||
e = PR_Expression (NOT_PRIORITY);
|
||||
t = e->type->type;
|
||||
if (t == ev_float)
|
||||
e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0);
|
||||
else if (t == ev_string)
|
||||
e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0);
|
||||
else if (t == ev_entity)
|
||||
e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0);
|
||||
else if (t == ev_vector)
|
||||
e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0);
|
||||
else if (t == ev_function)
|
||||
e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0);
|
||||
else
|
||||
{
|
||||
e2 = NULL; // shut up compiler warning;
|
||||
PR_ParseError ("type mismatch for !");
|
||||
}
|
||||
return e2;
|
||||
}
|
||||
|
||||
if (PR_Check ("("))
|
||||
{
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (")");
|
||||
return e;
|
||||
}
|
||||
|
||||
return PR_ParseValue ();
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_Expression
|
||||
==============
|
||||
*/
|
||||
|
||||
def_t *PR_Expression (int priority)
|
||||
{
|
||||
opcode_t *op, *oldop;
|
||||
def_t *e, *e2;
|
||||
etype_t type_a, type_b, type_c;
|
||||
|
||||
if (priority == 0)
|
||||
return PR_Term ();
|
||||
|
||||
e = PR_Expression (priority-1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (priority == 1 && PR_Check ("(") )
|
||||
return PR_ParseFunctionCall (e);
|
||||
|
||||
for (op=pr_opcodes ; op->name ; op++)
|
||||
{
|
||||
if (op->priority != priority)
|
||||
continue;
|
||||
if (!PR_Check (op->name))
|
||||
continue;
|
||||
if ( op->right_associative )
|
||||
{
|
||||
// if last statement is an indirect, change it to an address of
|
||||
if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 )
|
||||
{
|
||||
statements[numstatements-1].op = OP_ADDRESS;
|
||||
def_pointer.type->aux_type = e->type;
|
||||
e->type = def_pointer.type;
|
||||
}
|
||||
e2 = PR_Expression (priority);
|
||||
}
|
||||
else
|
||||
e2 = PR_Expression (priority-1);
|
||||
|
||||
// type check
|
||||
type_a = e->type->type;
|
||||
type_b = e2->type->type;
|
||||
|
||||
if (op->name[0] == '.')// field access gets type from field
|
||||
{
|
||||
if (e2->type->aux_type)
|
||||
type_c = e2->type->aux_type->type;
|
||||
else
|
||||
type_c = -1; // not a field
|
||||
}
|
||||
else
|
||||
type_c = ev_void;
|
||||
|
||||
oldop = op;
|
||||
while (type_a != op->type_a->type->type
|
||||
|| type_b != op->type_b->type->type
|
||||
|| (type_c != ev_void && type_c != op->type_c->type->type) )
|
||||
{
|
||||
op++;
|
||||
if (!op->name || strcmp (op->name , oldop->name))
|
||||
PR_ParseError ("type mismatch for %s", oldop->name);
|
||||
}
|
||||
|
||||
if (type_a == ev_pointer && type_b != e->type->aux_type->type)
|
||||
PR_ParseError ("type mismatch for %s", op->name);
|
||||
|
||||
|
||||
if (op->right_associative)
|
||||
e = PR_Statement (op, e2, e);
|
||||
else
|
||||
e = PR_Statement (op, e, e2);
|
||||
|
||||
if (type_c != ev_void) // field access gets type from field
|
||||
e->type = e2->type->aux_type;
|
||||
|
||||
break;
|
||||
}
|
||||
if (!op->name)
|
||||
break; // next token isn't at this priority level
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseStatement
|
||||
|
||||
============
|
||||
*/
|
||||
void PR_ParseStatement (void)
|
||||
{
|
||||
def_t *e;
|
||||
dstatement_t *patch1, *patch2;
|
||||
|
||||
if (PR_Check ("{"))
|
||||
{
|
||||
do
|
||||
{
|
||||
PR_ParseStatement ();
|
||||
} while (!PR_Check ("}"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (PR_Check("return"))
|
||||
{
|
||||
if (PR_Check (";"))
|
||||
{
|
||||
PR_Statement (&pr_opcodes[OP_RETURN], 0, 0);
|
||||
return;
|
||||
}
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (";");
|
||||
PR_Statement (&pr_opcodes[OP_RETURN], e, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PR_Check("while"))
|
||||
{
|
||||
PR_Expect ("(");
|
||||
patch2 = &statements[numstatements];
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (")");
|
||||
patch1 = &statements[numstatements];
|
||||
PR_Statement (&pr_opcodes[OP_IFNOT], e, 0);
|
||||
PR_ParseStatement ();
|
||||
junkdef.ofs = patch2 - &statements[numstatements];
|
||||
PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0);
|
||||
patch1->b = &statements[numstatements] - patch1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PR_Check("do"))
|
||||
{
|
||||
patch1 = &statements[numstatements];
|
||||
PR_ParseStatement ();
|
||||
PR_Expect ("while");
|
||||
PR_Expect ("(");
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (")");
|
||||
PR_Expect (";");
|
||||
junkdef.ofs = patch1 - &statements[numstatements];
|
||||
PR_Statement (&pr_opcodes[OP_IF], e, &junkdef);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PR_Check("local"))
|
||||
{
|
||||
PR_ParseDefs ();
|
||||
locals_end = numpr_globals;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PR_Check("if"))
|
||||
{
|
||||
PR_Expect ("(");
|
||||
e = PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (")");
|
||||
|
||||
patch1 = &statements[numstatements];
|
||||
PR_Statement (&pr_opcodes[OP_IFNOT], e, 0);
|
||||
|
||||
PR_ParseStatement ();
|
||||
|
||||
if (PR_Check ("else"))
|
||||
{
|
||||
patch2 = &statements[numstatements];
|
||||
PR_Statement (&pr_opcodes[OP_GOTO], 0, 0);
|
||||
patch1->b = &statements[numstatements] - patch1;
|
||||
PR_ParseStatement ();
|
||||
patch2->a = &statements[numstatements] - patch2;
|
||||
}
|
||||
else
|
||||
patch1->b = &statements[numstatements] - patch1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PR_Expression (TOP_PRIORITY);
|
||||
PR_Expect (";");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_ParseState
|
||||
|
||||
States are special functions made for convenience. They automatically
|
||||
set frame, nextthink (implicitly), and think (allowing forward definitions).
|
||||
|
||||
// void() name = [framenum, nextthink] {code}
|
||||
// expands to:
|
||||
// function void name ()
|
||||
// {
|
||||
// self.frame=framenum;
|
||||
// self.nextthink = time + 0.1;
|
||||
// self.think = nextthink
|
||||
// <code>
|
||||
// };
|
||||
==============
|
||||
*/
|
||||
void PR_ParseState (void)
|
||||
{
|
||||
char *name;
|
||||
def_t *s1, *def;
|
||||
|
||||
if (pr_token_type != tt_immediate || pr_immediate_type != &type_float)
|
||||
PR_ParseError ("state frame must be a number");
|
||||
s1 = PR_ParseImmediate ();
|
||||
|
||||
PR_Expect (",");
|
||||
|
||||
name = PR_ParseName ();
|
||||
def = PR_GetDef (&type_function, name,0, true);
|
||||
|
||||
PR_Expect ("]");
|
||||
|
||||
PR_Statement (&pr_opcodes[OP_STATE], s1, def);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseImmediateStatements
|
||||
|
||||
Parse a function body
|
||||
============
|
||||
*/
|
||||
function_t *PR_ParseImmediateStatements (type_t *type)
|
||||
{
|
||||
int i;
|
||||
function_t *f;
|
||||
def_t *defs[MAX_PARMS];
|
||||
|
||||
f = malloc (sizeof(function_t));
|
||||
|
||||
//
|
||||
// check for builtin function definition #1, #2, etc
|
||||
//
|
||||
if (PR_Check ("#"))
|
||||
{
|
||||
if (pr_token_type != tt_immediate
|
||||
|| pr_immediate_type != &type_float
|
||||
|| pr_immediate._float != (int)pr_immediate._float)
|
||||
PR_ParseError ("Bad builtin immediate");
|
||||
f->builtin = (int)pr_immediate._float;
|
||||
PR_Lex ();
|
||||
return f;
|
||||
}
|
||||
|
||||
f->builtin = 0;
|
||||
//
|
||||
// define the parms
|
||||
//
|
||||
for (i=0 ; i<type->num_parms ; i++)
|
||||
{
|
||||
defs[i] = PR_GetDef (type->parm_types[i], pr_parm_names[i], pr_scope, true);
|
||||
f->parm_ofs[i] = defs[i]->ofs;
|
||||
if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1])
|
||||
Error ("bad parm order");
|
||||
}
|
||||
|
||||
f->code = numstatements;
|
||||
|
||||
//
|
||||
// check for a state opcode
|
||||
//
|
||||
if (PR_Check ("["))
|
||||
PR_ParseState ();
|
||||
|
||||
//
|
||||
// parse regular statements
|
||||
//
|
||||
PR_Expect ("{");
|
||||
|
||||
while (!PR_Check("}"))
|
||||
PR_ParseStatement ();
|
||||
|
||||
// emit an end of statements opcode
|
||||
PR_Statement (pr_opcodes, 0,0);
|
||||
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_GetDef
|
||||
|
||||
If type is NULL, it will match any type
|
||||
If allocate is true, a new def will be allocated if it can't be found
|
||||
============
|
||||
*/
|
||||
def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate)
|
||||
{
|
||||
def_t *def, **old;
|
||||
char element[MAX_NAME];
|
||||
|
||||
// see if the name is already in use
|
||||
old = &pr.search;
|
||||
for (def = *old ; def ; old=&def->search_next,def = *old)
|
||||
if (!strcmp(def->name,name) )
|
||||
{
|
||||
if ( def->scope && def->scope != scope)
|
||||
continue; // in a different function
|
||||
|
||||
if (type && def->type != type)
|
||||
PR_ParseError ("Type mismatch on redeclaration of %s",name);
|
||||
|
||||
// move to head of list to find fast next time
|
||||
*old = def->search_next;
|
||||
def->search_next = pr.search;
|
||||
pr.search = def;
|
||||
return def;
|
||||
}
|
||||
|
||||
if (!allocate)
|
||||
return NULL;
|
||||
|
||||
// allocate a new def
|
||||
def = malloc (sizeof(def_t));
|
||||
memset (def, 0, sizeof(*def));
|
||||
def->next = NULL;
|
||||
pr.def_tail->next = def;
|
||||
pr.def_tail = def;
|
||||
|
||||
def->search_next = pr.search;
|
||||
pr.search = def;
|
||||
|
||||
def->name = malloc (strlen(name)+1);
|
||||
strcpy (def->name, name);
|
||||
def->type = type;
|
||||
|
||||
def->scope = scope;
|
||||
|
||||
def->ofs = numpr_globals;
|
||||
pr_global_defs[numpr_globals] = def;
|
||||
|
||||
//
|
||||
// make automatic defs for the vectors elements
|
||||
// .origin can be accessed as .origin_x, .origin_y, and .origin_z
|
||||
//
|
||||
if (type->type == ev_vector)
|
||||
{
|
||||
sprintf (element, "%s_x",name);
|
||||
PR_GetDef (&type_float, element, scope, true);
|
||||
|
||||
sprintf (element, "%s_y",name);
|
||||
PR_GetDef (&type_float, element, scope, true);
|
||||
|
||||
sprintf (element, "%s_z",name);
|
||||
PR_GetDef (&type_float, element, scope, true);
|
||||
}
|
||||
else
|
||||
numpr_globals += type_size[type->type];
|
||||
|
||||
if (type->type == ev_field)
|
||||
{
|
||||
*(int *)&pr_globals[def->ofs] = pr.size_fields;
|
||||
|
||||
if (type->aux_type->type == ev_vector)
|
||||
{
|
||||
sprintf (element, "%s_x",name);
|
||||
PR_GetDef (&type_floatfield, element, scope, true);
|
||||
|
||||
sprintf (element, "%s_y",name);
|
||||
PR_GetDef (&type_floatfield, element, scope, true);
|
||||
|
||||
sprintf (element, "%s_z",name);
|
||||
PR_GetDef (&type_floatfield, element, scope, true);
|
||||
}
|
||||
else
|
||||
pr.size_fields += type_size[type->aux_type->type];
|
||||
}
|
||||
|
||||
// if (pr_dumpasm)
|
||||
// PR_PrintOfs (def->ofs);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PR_ParseDefs
|
||||
|
||||
Called at the outer layer and when a local statement is hit
|
||||
================
|
||||
*/
|
||||
void PR_ParseDefs (void)
|
||||
{
|
||||
char *name;
|
||||
type_t *type;
|
||||
def_t *def;
|
||||
function_t *f;
|
||||
dfunction_t *df;
|
||||
int i;
|
||||
int locals_start;
|
||||
|
||||
type = PR_ParseType ();
|
||||
|
||||
if (pr_scope && (type->type == ev_field || type->type == ev_function) )
|
||||
PR_ParseError ("Fields and functions must be global");
|
||||
|
||||
do
|
||||
{
|
||||
name = PR_ParseName ();
|
||||
|
||||
def = PR_GetDef (type, name, pr_scope, true);
|
||||
|
||||
// check for an initialization
|
||||
if ( PR_Check ("=") )
|
||||
{
|
||||
if (def->initialized)
|
||||
PR_ParseError ("%s redeclared", name);
|
||||
|
||||
if (type->type == ev_function)
|
||||
{
|
||||
locals_start = locals_end = numpr_globals;
|
||||
pr_scope = def;
|
||||
f = PR_ParseImmediateStatements (type);
|
||||
pr_scope = NULL;
|
||||
def->initialized = 1;
|
||||
G_FUNCTION(def->ofs) = numfunctions;
|
||||
f->def = def;
|
||||
// if (pr_dumpasm)
|
||||
// PR_PrintFunction (def);
|
||||
|
||||
// fill in the dfunction
|
||||
df = &functions[numfunctions];
|
||||
numfunctions++;
|
||||
if (f->builtin)
|
||||
df->first_statement = -f->builtin;
|
||||
else
|
||||
df->first_statement = f->code;
|
||||
df->s_name = CopyString (f->def->name);
|
||||
df->s_file = s_file;
|
||||
df->numparms = f->def->type->num_parms;
|
||||
df->locals = locals_end - locals_start;
|
||||
df->parm_start = locals_start;
|
||||
for (i=0 ; i<df->numparms ; i++)
|
||||
df->parm_size[i] = type_size[f->def->type->parm_types[i]->type];
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (pr_immediate_type != type)
|
||||
PR_ParseError ("wrong immediate type for %s", name);
|
||||
|
||||
def->initialized = 1;
|
||||
memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]);
|
||||
PR_Lex ();
|
||||
}
|
||||
|
||||
} while (PR_Check (","));
|
||||
|
||||
PR_Expect (";");
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_CompileFile
|
||||
|
||||
compiles the 0 terminated text, adding defintions to the pr structure
|
||||
============
|
||||
*/
|
||||
qboolean PR_CompileFile (char *string, char *filename)
|
||||
{
|
||||
if (!pr.memory)
|
||||
Error ("PR_CompileFile: Didn't clear");
|
||||
|
||||
PR_ClearGrabMacros (); // clear the frame macros
|
||||
|
||||
pr_file_p = string;
|
||||
s_file = CopyString (filename);
|
||||
|
||||
pr_source_line = 0;
|
||||
|
||||
PR_NewLine ();
|
||||
|
||||
PR_Lex (); // read first token
|
||||
|
||||
while (pr_token_type != tt_eof)
|
||||
{
|
||||
if (setjmp(pr_parse_abort))
|
||||
{
|
||||
if (++pr_error_count > MAX_ERRORS)
|
||||
return false;
|
||||
PR_SkipToSemicolon ();
|
||||
if (pr_token_type == tt_eof)
|
||||
return false;
|
||||
}
|
||||
|
||||
pr_scope = NULL; // outside all functions
|
||||
|
||||
PR_ParseDefs ();
|
||||
}
|
||||
|
||||
return (pr_error_count == 0);
|
||||
}
|
||||
|
||||
161
qutils/QCC/PR_COMP.H
Normal file
161
qutils/QCC/PR_COMP.H
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
// this file is shared by quake and qcc
|
||||
|
||||
typedef int func_t;
|
||||
typedef int string_t;
|
||||
|
||||
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t;
|
||||
|
||||
|
||||
#define OFS_NULL 0
|
||||
#define OFS_RETURN 1
|
||||
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
|
||||
#define OFS_PARM1 7
|
||||
#define OFS_PARM2 10
|
||||
#define OFS_PARM3 13
|
||||
#define OFS_PARM4 16
|
||||
#define OFS_PARM5 19
|
||||
#define OFS_PARM6 22
|
||||
#define OFS_PARM7 25
|
||||
#define RESERVED_OFS 28
|
||||
|
||||
|
||||
enum {
|
||||
OP_DONE,
|
||||
OP_MUL_F,
|
||||
OP_MUL_V,
|
||||
OP_MUL_FV,
|
||||
OP_MUL_VF,
|
||||
OP_DIV_F,
|
||||
OP_ADD_F,
|
||||
OP_ADD_V,
|
||||
OP_SUB_F,
|
||||
OP_SUB_V,
|
||||
|
||||
OP_EQ_F,
|
||||
OP_EQ_V,
|
||||
OP_EQ_S,
|
||||
OP_EQ_E,
|
||||
OP_EQ_FNC,
|
||||
|
||||
OP_NE_F,
|
||||
OP_NE_V,
|
||||
OP_NE_S,
|
||||
OP_NE_E,
|
||||
OP_NE_FNC,
|
||||
|
||||
OP_LE,
|
||||
OP_GE,
|
||||
OP_LT,
|
||||
OP_GT,
|
||||
|
||||
OP_LOAD_F,
|
||||
OP_LOAD_V,
|
||||
OP_LOAD_S,
|
||||
OP_LOAD_ENT,
|
||||
OP_LOAD_FLD,
|
||||
OP_LOAD_FNC,
|
||||
|
||||
OP_ADDRESS,
|
||||
|
||||
OP_STORE_F,
|
||||
OP_STORE_V,
|
||||
OP_STORE_S,
|
||||
OP_STORE_ENT,
|
||||
OP_STORE_FLD,
|
||||
OP_STORE_FNC,
|
||||
|
||||
OP_STOREP_F,
|
||||
OP_STOREP_V,
|
||||
OP_STOREP_S,
|
||||
OP_STOREP_ENT,
|
||||
OP_STOREP_FLD,
|
||||
OP_STOREP_FNC,
|
||||
|
||||
OP_RETURN,
|
||||
OP_NOT_F,
|
||||
OP_NOT_V,
|
||||
OP_NOT_S,
|
||||
OP_NOT_ENT,
|
||||
OP_NOT_FNC,
|
||||
OP_IF,
|
||||
OP_IFNOT,
|
||||
OP_CALL0,
|
||||
OP_CALL1,
|
||||
OP_CALL2,
|
||||
OP_CALL3,
|
||||
OP_CALL4,
|
||||
OP_CALL5,
|
||||
OP_CALL6,
|
||||
OP_CALL7,
|
||||
OP_CALL8,
|
||||
OP_STATE,
|
||||
OP_GOTO,
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
|
||||
OP_BITAND,
|
||||
OP_BITOR
|
||||
};
|
||||
|
||||
|
||||
typedef struct statement_s
|
||||
{
|
||||
unsigned short op;
|
||||
short a,b,c;
|
||||
} dstatement_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short type; // if DEF_SAVEGLOBGAL bit is set
|
||||
// the variable needs to be saved in savegames
|
||||
unsigned short ofs;
|
||||
int s_name;
|
||||
} ddef_t;
|
||||
#define DEF_SAVEGLOBGAL (1<<15)
|
||||
|
||||
#define MAX_PARMS 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int first_statement; // negative numbers are builtins
|
||||
int parm_start;
|
||||
int locals; // total ints of parms + locals
|
||||
|
||||
int profile; // runtime
|
||||
|
||||
int s_name;
|
||||
int s_file; // source file defined in
|
||||
|
||||
int numparms;
|
||||
byte parm_size[MAX_PARMS];
|
||||
} dfunction_t;
|
||||
|
||||
|
||||
#define PROG_VERSION 6
|
||||
typedef struct
|
||||
{
|
||||
int version;
|
||||
int crc; // check of header file
|
||||
|
||||
int ofs_statements;
|
||||
int numstatements; // statement 0 is an error
|
||||
|
||||
int ofs_globaldefs;
|
||||
int numglobaldefs;
|
||||
|
||||
int ofs_fielddefs;
|
||||
int numfielddefs;
|
||||
|
||||
int ofs_functions;
|
||||
int numfunctions; // function 0 is an empty
|
||||
|
||||
int ofs_strings;
|
||||
int numstrings; // first string is a null string
|
||||
|
||||
int ofs_globals;
|
||||
int numglobals;
|
||||
|
||||
int entityfields;
|
||||
} dprograms_t;
|
||||
|
||||
677
qutils/QCC/PR_LEX.C
Normal file
677
qutils/QCC/PR_LEX.C
Normal file
@@ -0,0 +1,677 @@
|
||||
|
||||
#include "qcc.h"
|
||||
|
||||
int pr_source_line;
|
||||
|
||||
char *pr_file_p;
|
||||
char *pr_line_start; // start of current source line
|
||||
|
||||
int pr_bracelevel;
|
||||
|
||||
char pr_token[2048];
|
||||
token_type_t pr_token_type;
|
||||
type_t *pr_immediate_type;
|
||||
eval_t pr_immediate;
|
||||
|
||||
char pr_immediate_string[2048];
|
||||
|
||||
int pr_error_count;
|
||||
|
||||
char *pr_punctuation[] =
|
||||
// longer symbols must be before a shorter partial match
|
||||
{"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
|
||||
|
||||
// simple types. function types are dynamically allocated
|
||||
type_t type_void = {ev_void, &def_void};
|
||||
type_t type_string = {ev_string, &def_string};
|
||||
type_t type_float = {ev_float, &def_float};
|
||||
type_t type_vector = {ev_vector, &def_vector};
|
||||
type_t type_entity = {ev_entity, &def_entity};
|
||||
type_t type_field = {ev_field, &def_field};
|
||||
type_t type_function = {ev_function, &def_function,NULL,&type_void};
|
||||
// type_function is a void() function used for state defs
|
||||
type_t type_pointer = {ev_pointer, &def_pointer};
|
||||
|
||||
type_t type_floatfield = {ev_field, &def_field, NULL, &type_float};
|
||||
|
||||
int type_size[8] = {1,1,1,3,1,1,1,1};
|
||||
|
||||
def_t def_void = {&type_void, "temp"};
|
||||
def_t def_string = {&type_string, "temp"};
|
||||
def_t def_float = {&type_float, "temp"};
|
||||
def_t def_vector = {&type_vector, "temp"};
|
||||
def_t def_entity = {&type_entity, "temp"};
|
||||
def_t def_field = {&type_field, "temp"};
|
||||
def_t def_function = {&type_function, "temp"};
|
||||
def_t def_pointer = {&type_pointer, "temp"};
|
||||
|
||||
def_t def_ret, def_parms[MAX_PARMS];
|
||||
|
||||
def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
|
||||
|
||||
void PR_LexWhitespace (void);
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_PrintNextLine
|
||||
==============
|
||||
*/
|
||||
void PR_PrintNextLine (void)
|
||||
{
|
||||
char *t;
|
||||
|
||||
printf ("%3i:",pr_source_line);
|
||||
for (t=pr_line_start ; *t && *t != '\n' ; t++)
|
||||
printf ("%c",*t);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_NewLine
|
||||
|
||||
Call at start of file and when *pr_file_p == '\n'
|
||||
==============
|
||||
*/
|
||||
void PR_NewLine (void)
|
||||
{
|
||||
qboolean m;
|
||||
|
||||
if (*pr_file_p == '\n')
|
||||
{
|
||||
pr_file_p++;
|
||||
m = true;
|
||||
}
|
||||
else
|
||||
m = false;
|
||||
|
||||
pr_source_line++;
|
||||
pr_line_start = pr_file_p;
|
||||
|
||||
// if (pr_dumpasm)
|
||||
// PR_PrintNextLine ();
|
||||
if (m)
|
||||
pr_file_p--;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexString
|
||||
|
||||
Parses a quoted string
|
||||
==============
|
||||
*/
|
||||
void PR_LexString (void)
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
pr_file_p++;
|
||||
do
|
||||
{
|
||||
c = *pr_file_p++;
|
||||
if (!c)
|
||||
PR_ParseError ("EOF inside quote");
|
||||
if (c=='\n')
|
||||
PR_ParseError ("newline inside quote");
|
||||
if (c=='\\')
|
||||
{ // escape char
|
||||
c = *pr_file_p++;
|
||||
if (!c)
|
||||
PR_ParseError ("EOF inside quote");
|
||||
if (c == 'n')
|
||||
c = '\n';
|
||||
else if (c == '"')
|
||||
c = '"';
|
||||
else
|
||||
PR_ParseError ("Unknown escape char");
|
||||
}
|
||||
else if (c=='\"')
|
||||
{
|
||||
pr_token[len] = 0;
|
||||
pr_token_type = tt_immediate;
|
||||
pr_immediate_type = &type_string;
|
||||
strcpy (pr_immediate_string, pr_token);
|
||||
return;
|
||||
}
|
||||
pr_token[len] = c;
|
||||
len++;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexNumber
|
||||
==============
|
||||
*/
|
||||
float PR_LexNumber (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_token[len] = 0;
|
||||
return atof (pr_token);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexVector
|
||||
|
||||
Parses a single quoted vector
|
||||
==============
|
||||
*/
|
||||
void PR_LexVector (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_file_p++;
|
||||
pr_token_type = tt_immediate;
|
||||
pr_immediate_type = &type_vector;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
pr_immediate.vector[i] = PR_LexNumber ();
|
||||
PR_LexWhitespace ();
|
||||
}
|
||||
if (*pr_file_p != '\'')
|
||||
PR_ParseError ("Bad vector");
|
||||
pr_file_p++;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexName
|
||||
|
||||
Parses an identifier
|
||||
==============
|
||||
*/
|
||||
void 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 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, p);
|
||||
if (p[0] == '{')
|
||||
pr_bracelevel++;
|
||||
else if (p[0] == '}')
|
||||
pr_bracelevel--;
|
||||
pr_file_p += len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PR_ParseError ("Unknown punctuation");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexWhitespace
|
||||
==============
|
||||
*/
|
||||
void PR_LexWhitespace (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// skip whitespace
|
||||
while ( (c = *pr_file_p) <= ' ')
|
||||
{
|
||||
if (c=='\n')
|
||||
PR_NewLine ();
|
||||
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++;
|
||||
PR_NewLine();
|
||||
pr_file_p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip /* */ comments
|
||||
if (c=='/' && pr_file_p[1] == '*')
|
||||
{
|
||||
do
|
||||
{
|
||||
pr_file_p++;
|
||||
if (pr_file_p[0]=='\n')
|
||||
PR_NewLine();
|
||||
if (pr_file_p[1] == 0)
|
||||
return;
|
||||
} while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
|
||||
pr_file_p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break; // a real character has been found
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define MAX_FRAMES 256
|
||||
|
||||
char pr_framemacros[MAX_FRAMES][16];
|
||||
int pr_nummacros;
|
||||
|
||||
void PR_ClearGrabMacros (void)
|
||||
{
|
||||
pr_nummacros = 0;
|
||||
}
|
||||
|
||||
void PR_FindMacro (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<pr_nummacros ; i++)
|
||||
if (!strcmp (pr_token, pr_framemacros[i]))
|
||||
{
|
||||
sprintf (pr_token,"%d", i);
|
||||
pr_token_type = tt_immediate;
|
||||
pr_immediate_type = &type_float;
|
||||
pr_immediate._float = i;
|
||||
return;
|
||||
}
|
||||
PR_ParseError ("Unknown frame macro $%s", pr_token);
|
||||
}
|
||||
|
||||
// just parses text, returning false if an eol is reached
|
||||
qboolean PR_SimpleGetToken (void)
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
|
||||
// skip whitespace
|
||||
while ( (c = *pr_file_p) <= ' ')
|
||||
{
|
||||
if (c=='\n' || c == 0)
|
||||
return false;
|
||||
pr_file_p++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
|
||||
{
|
||||
pr_token[i] = c;
|
||||
i++;
|
||||
pr_file_p++;
|
||||
}
|
||||
pr_token[i] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PR_ParseFrame (void)
|
||||
{
|
||||
while (PR_SimpleGetToken ())
|
||||
{
|
||||
strcpy (pr_framemacros[pr_nummacros], pr_token);
|
||||
pr_nummacros++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_LexGrab
|
||||
|
||||
Deals with counting sequence numbers and replacing frame macros
|
||||
==============
|
||||
*/
|
||||
void PR_LexGrab (void)
|
||||
{
|
||||
pr_file_p++; // skip the $
|
||||
if (!PR_SimpleGetToken ())
|
||||
PR_ParseError ("hanging $");
|
||||
|
||||
// check for $frame
|
||||
if (!strcmp (pr_token, "frame"))
|
||||
{
|
||||
PR_ParseFrame ();
|
||||
PR_Lex ();
|
||||
}
|
||||
// ignore other known $commands
|
||||
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 (PR_SimpleGetToken ())
|
||||
;
|
||||
PR_Lex ();
|
||||
}
|
||||
// look for a frame name macro
|
||||
else
|
||||
PR_FindMacro ();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_Lex
|
||||
|
||||
Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
|
||||
==============
|
||||
*/
|
||||
void PR_Lex (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
pr_token[0] = 0;
|
||||
|
||||
if (!pr_file_p)
|
||||
{
|
||||
pr_token_type = tt_eof;
|
||||
return;
|
||||
}
|
||||
|
||||
PR_LexWhitespace ();
|
||||
|
||||
c = *pr_file_p;
|
||||
|
||||
if (!c)
|
||||
{
|
||||
pr_token_type = tt_eof;
|
||||
return;
|
||||
}
|
||||
|
||||
// handle quoted strings as a unit
|
||||
if (c == '\"')
|
||||
{
|
||||
PR_LexString ();
|
||||
return;
|
||||
}
|
||||
|
||||
// handle quoted vectors as a unit
|
||||
if (c == '\'')
|
||||
{
|
||||
PR_LexVector ();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the first character is a valid identifier, parse until a non-id
|
||||
// character is reached
|
||||
if ( (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 = PR_LexNumber ();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
|
||||
{
|
||||
PR_LexName ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == '$')
|
||||
{
|
||||
PR_LexGrab ();
|
||||
return;
|
||||
}
|
||||
|
||||
// parse symbol strings until a non-symbol is found
|
||||
PR_LexPunctuation ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseError
|
||||
|
||||
Aborts the current file load
|
||||
============
|
||||
*/
|
||||
void PR_ParseError (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start (argptr,error);
|
||||
vsprintf (string,error,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
|
||||
|
||||
longjmp (pr_parse_abort, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
PR_Expect
|
||||
|
||||
Issues an error if the current token isn't equal to string
|
||||
Gets the next token
|
||||
=============
|
||||
*/
|
||||
void PR_Expect (char *string)
|
||||
{
|
||||
if (strcmp (string, pr_token))
|
||||
PR_ParseError ("expected %s, found %s",string, pr_token);
|
||||
PR_Lex ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
PR_Check
|
||||
|
||||
Returns true and gets the next token if the current token equals string
|
||||
Returns false and does nothing otherwise
|
||||
=============
|
||||
*/
|
||||
qboolean PR_Check (char *string)
|
||||
{
|
||||
if (strcmp (string, pr_token))
|
||||
return false;
|
||||
|
||||
PR_Lex ();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseName
|
||||
|
||||
Checks to see if the current token is a valid name
|
||||
============
|
||||
*/
|
||||
char *PR_ParseName (void)
|
||||
{
|
||||
static char ident[MAX_NAME];
|
||||
|
||||
if (pr_token_type != tt_name)
|
||||
PR_ParseError ("not a name");
|
||||
if (strlen(pr_token) >= MAX_NAME-1)
|
||||
PR_ParseError ("name too long");
|
||||
strcpy (ident, pr_token);
|
||||
PR_Lex ();
|
||||
|
||||
return ident;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_FindType
|
||||
|
||||
Returns a preexisting complex type that matches the parm, or allocates
|
||||
a new one and copies it out.
|
||||
============
|
||||
*/
|
||||
type_t *PR_FindType (type_t *type)
|
||||
{
|
||||
def_t *def;
|
||||
type_t *check;
|
||||
int i;
|
||||
|
||||
for (check = pr.types ; check ; check = check->next)
|
||||
{
|
||||
if (check->type != type->type
|
||||
|| check->aux_type != type->aux_type
|
||||
|| check->num_parms != type->num_parms)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i< type->num_parms ; i++)
|
||||
if (check->parm_types[i] != type->parm_types[i])
|
||||
break;
|
||||
|
||||
if (i == type->num_parms)
|
||||
return check;
|
||||
}
|
||||
|
||||
// allocate a new one
|
||||
check = malloc (sizeof (*check));
|
||||
*check = *type;
|
||||
check->next = pr.types;
|
||||
pr.types = check;
|
||||
|
||||
// allocate a generic def for the type, so fields can reference it
|
||||
def = malloc (sizeof(def_t));
|
||||
def->name = "COMPLEX TYPE";
|
||||
def->type = check;
|
||||
check->def = def;
|
||||
return check;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_SkipToSemicolon
|
||||
|
||||
For error recovery, also pops out of nested braces
|
||||
============
|
||||
*/
|
||||
void PR_SkipToSemicolon (void)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!pr_bracelevel && PR_Check (";"))
|
||||
return;
|
||||
PR_Lex ();
|
||||
} while (pr_token[0]); // eof will return a null token
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ParseType
|
||||
|
||||
Parses a variable type, including field and functions types
|
||||
============
|
||||
*/
|
||||
char pr_parm_names[MAX_PARMS][MAX_NAME];
|
||||
|
||||
type_t *PR_ParseType (void)
|
||||
{
|
||||
type_t new;
|
||||
type_t *type;
|
||||
char *name;
|
||||
|
||||
if (PR_Check ("."))
|
||||
{
|
||||
memset (&new, 0, sizeof(new));
|
||||
new.type = ev_field;
|
||||
new.aux_type = PR_ParseType ();
|
||||
return PR_FindType (&new);
|
||||
}
|
||||
|
||||
if (!strcmp (pr_token, "float") )
|
||||
type = &type_float;
|
||||
else if (!strcmp (pr_token, "vector") )
|
||||
type = &type_vector;
|
||||
else if (!strcmp (pr_token, "float") )
|
||||
type = &type_float;
|
||||
else if (!strcmp (pr_token, "entity") )
|
||||
type = &type_entity;
|
||||
else if (!strcmp (pr_token, "string") )
|
||||
type = &type_string;
|
||||
else if (!strcmp (pr_token, "void") )
|
||||
type = &type_void;
|
||||
else
|
||||
{
|
||||
PR_ParseError ("\"%s\" is not a type", pr_token);
|
||||
type = &type_float; // shut up compiler warning
|
||||
}
|
||||
PR_Lex ();
|
||||
|
||||
if (!PR_Check ("("))
|
||||
return type;
|
||||
|
||||
// function type
|
||||
memset (&new, 0, sizeof(new));
|
||||
new.type = ev_function;
|
||||
new.aux_type = type; // return type
|
||||
new.num_parms = 0;
|
||||
if (!PR_Check (")"))
|
||||
{
|
||||
if (PR_Check ("..."))
|
||||
new.num_parms = -1; // variable args
|
||||
else
|
||||
do
|
||||
{
|
||||
type = PR_ParseType ();
|
||||
name = PR_ParseName ();
|
||||
strcpy (pr_parm_names[new.num_parms], name);
|
||||
new.parm_types[new.num_parms] = type;
|
||||
new.num_parms++;
|
||||
} while (PR_Check (","));
|
||||
|
||||
PR_Expect (")");
|
||||
}
|
||||
|
||||
return PR_FindType (&new);
|
||||
}
|
||||
|
||||
BIN
qutils/QCC/QCC
Normal file
BIN
qutils/QCC/QCC
Normal file
Binary file not shown.
808
qutils/QCC/QCC.C
Normal file
808
qutils/QCC/QCC.C
Normal file
@@ -0,0 +1,808 @@
|
||||
|
||||
#include "qcc.h"
|
||||
|
||||
char sourcedir[1024];
|
||||
char destfile[1024];
|
||||
|
||||
float pr_globals[MAX_REGS];
|
||||
int numpr_globals;
|
||||
|
||||
char strings[MAX_STRINGS];
|
||||
int strofs;
|
||||
|
||||
dstatement_t statements[MAX_STATEMENTS];
|
||||
int numstatements;
|
||||
int statement_linenums[MAX_STATEMENTS];
|
||||
|
||||
dfunction_t functions[MAX_FUNCTIONS];
|
||||
int numfunctions;
|
||||
|
||||
ddef_t globals[MAX_GLOBALS];
|
||||
int numglobaldefs;
|
||||
|
||||
ddef_t fields[MAX_FIELDS];
|
||||
int numfielddefs;
|
||||
|
||||
char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
|
||||
int precache_sounds_block[MAX_SOUNDS];
|
||||
int numsounds;
|
||||
|
||||
char precache_models[MAX_MODELS][MAX_DATA_PATH];
|
||||
int precache_models_block[MAX_SOUNDS];
|
||||
int nummodels;
|
||||
|
||||
char precache_files[MAX_FILES][MAX_DATA_PATH];
|
||||
int precache_files_block[MAX_SOUNDS];
|
||||
int numfiles;
|
||||
|
||||
/*
|
||||
============
|
||||
WriteFiles
|
||||
|
||||
Generates files.dat, which contains all of the
|
||||
data files actually used by the game, to be
|
||||
processed by qfiles.exe
|
||||
============
|
||||
*/
|
||||
void WriteFiles (void)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
char filename[1024];
|
||||
|
||||
sprintf (filename, "%sfiles.dat", sourcedir);
|
||||
f = fopen (filename, "w");
|
||||
if (!f)
|
||||
Error ("Couldn't open %s", filename);
|
||||
|
||||
fprintf (f, "%i\n", numsounds);
|
||||
for (i=0 ; i<numsounds ; i++)
|
||||
fprintf (f, "%i %s\n", precache_sounds_block[i],
|
||||
precache_sounds[i]);
|
||||
|
||||
fprintf (f, "%i\n", nummodels);
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
fprintf (f, "%i %s\n", precache_models_block[i],
|
||||
precache_models[i]);
|
||||
|
||||
fprintf (f, "%i\n", numfiles);
|
||||
for (i=0 ; i<numfiles ; i++)
|
||||
fprintf (f, "%i %s\n", precache_files_block[i],
|
||||
precache_files[i]);
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
// CopyString returns an offset from the string heap
|
||||
int CopyString (char *str)
|
||||
{
|
||||
int old;
|
||||
|
||||
old = strofs;
|
||||
strcpy (strings+strofs, str);
|
||||
strofs += strlen(str)+1;
|
||||
return old;
|
||||
}
|
||||
|
||||
void PrintStrings (void)
|
||||
{
|
||||
int i, l, j;
|
||||
|
||||
for (i=0 ; i<strofs ; i += l)
|
||||
{
|
||||
l = strlen(strings+i) + 1;
|
||||
printf ("%5i : ",i);
|
||||
for (j=0 ; j<l ; j++)
|
||||
{
|
||||
if (strings[i+j] == '\n')
|
||||
{
|
||||
putchar ('\\');
|
||||
putchar ('n');
|
||||
}
|
||||
else
|
||||
putchar (strings[i+j]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrintFunctions (void)
|
||||
{
|
||||
int i,j;
|
||||
dfunction_t *d;
|
||||
|
||||
for (i=0 ; i<numfunctions ; i++)
|
||||
{
|
||||
d = &functions[i];
|
||||
printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
|
||||
for (j=0 ; j<d->numparms ; j++)
|
||||
printf ("%i ",d->parm_size[j]);
|
||||
printf (")\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PrintFields (void)
|
||||
{
|
||||
int i;
|
||||
ddef_t *d;
|
||||
|
||||
for (i=0 ; i<numfielddefs ; i++)
|
||||
{
|
||||
d = &fields[i];
|
||||
printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintGlobals (void)
|
||||
{
|
||||
int i;
|
||||
ddef_t *d;
|
||||
|
||||
for (i=0 ; i<numglobaldefs ; i++)
|
||||
{
|
||||
d = &globals[i];
|
||||
printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InitData (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
numstatements = 1;
|
||||
strofs = 1;
|
||||
numfunctions = 1;
|
||||
numglobaldefs = 1;
|
||||
numfielddefs = 1;
|
||||
|
||||
def_ret.ofs = OFS_RETURN;
|
||||
for (i=0 ; i<MAX_PARMS ; i++)
|
||||
def_parms[i].ofs = OFS_PARM0 + 3*i;
|
||||
}
|
||||
|
||||
|
||||
void WriteData (int crc)
|
||||
{
|
||||
def_t *def;
|
||||
ddef_t *dd;
|
||||
dprograms_t progs;
|
||||
FILE *h;
|
||||
int i;
|
||||
|
||||
for (def = pr.def_head.next ; def ; def = def->next)
|
||||
{
|
||||
if (def->type->type == ev_function)
|
||||
{
|
||||
// df = &functions[numfunctions];
|
||||
// numfunctions++;
|
||||
|
||||
}
|
||||
else if (def->type->type == ev_field)
|
||||
{
|
||||
dd = &fields[numfielddefs];
|
||||
numfielddefs++;
|
||||
dd->type = def->type->aux_type->type;
|
||||
dd->s_name = CopyString (def->name);
|
||||
dd->ofs = G_INT(def->ofs);
|
||||
}
|
||||
dd = &globals[numglobaldefs];
|
||||
numglobaldefs++;
|
||||
dd->type = def->type->type;
|
||||
if ( !def->initialized
|
||||
&& def->type->type != ev_function
|
||||
&& def->type->type != ev_field
|
||||
&& def->scope == NULL)
|
||||
dd->type |= DEF_SAVEGLOBGAL;
|
||||
dd->s_name = CopyString (def->name);
|
||||
dd->ofs = def->ofs;
|
||||
}
|
||||
|
||||
//PrintStrings ();
|
||||
//PrintFunctions ();
|
||||
//PrintFields ();
|
||||
//PrintGlobals ();
|
||||
strofs = (strofs+3)&~3;
|
||||
|
||||
printf ("%6i strofs\n", strofs);
|
||||
printf ("%6i numstatements\n", numstatements);
|
||||
printf ("%6i numfunctions\n", numfunctions);
|
||||
printf ("%6i numglobaldefs\n", numglobaldefs);
|
||||
printf ("%6i numfielddefs\n", numfielddefs);
|
||||
printf ("%6i numpr_globals\n", numpr_globals);
|
||||
|
||||
h = SafeOpenWrite (destfile);
|
||||
SafeWrite (h, &progs, sizeof(progs));
|
||||
|
||||
progs.ofs_strings = ftell (h);
|
||||
progs.numstrings = strofs;
|
||||
SafeWrite (h, strings, strofs);
|
||||
|
||||
progs.ofs_statements = ftell (h);
|
||||
progs.numstatements = numstatements;
|
||||
for (i=0 ; i<numstatements ; i++)
|
||||
{
|
||||
statements[i].op = LittleShort(statements[i].op);
|
||||
statements[i].a = LittleShort(statements[i].a);
|
||||
statements[i].b = LittleShort(statements[i].b);
|
||||
statements[i].c = LittleShort(statements[i].c);
|
||||
}
|
||||
SafeWrite (h, statements, numstatements*sizeof(dstatement_t));
|
||||
|
||||
progs.ofs_functions = ftell (h);
|
||||
progs.numfunctions = numfunctions;
|
||||
for (i=0 ; i<numfunctions ; i++)
|
||||
{
|
||||
functions[i].first_statement = LittleLong (functions[i].first_statement);
|
||||
functions[i].parm_start = LittleLong (functions[i].parm_start);
|
||||
functions[i].s_name = LittleLong (functions[i].s_name);
|
||||
functions[i].s_file = LittleLong (functions[i].s_file);
|
||||
functions[i].numparms = LittleLong (functions[i].numparms);
|
||||
functions[i].locals = LittleLong (functions[i].locals);
|
||||
}
|
||||
SafeWrite (h, functions, numfunctions*sizeof(dfunction_t));
|
||||
|
||||
progs.ofs_globaldefs = ftell (h);
|
||||
progs.numglobaldefs = numglobaldefs;
|
||||
for (i=0 ; i<numglobaldefs ; i++)
|
||||
{
|
||||
globals[i].type = LittleShort (globals[i].type);
|
||||
globals[i].ofs = LittleShort (globals[i].ofs);
|
||||
globals[i].s_name = LittleLong (globals[i].s_name);
|
||||
}
|
||||
SafeWrite (h, globals, numglobaldefs*sizeof(ddef_t));
|
||||
|
||||
progs.ofs_fielddefs = ftell (h);
|
||||
progs.numfielddefs = numfielddefs;
|
||||
for (i=0 ; i<numfielddefs ; i++)
|
||||
{
|
||||
fields[i].type = LittleShort (fields[i].type);
|
||||
fields[i].ofs = LittleShort (fields[i].ofs);
|
||||
fields[i].s_name = LittleLong (fields[i].s_name);
|
||||
}
|
||||
SafeWrite (h, fields, numfielddefs*sizeof(ddef_t));
|
||||
|
||||
progs.ofs_globals = ftell (h);
|
||||
progs.numglobals = numpr_globals;
|
||||
for (i=0 ; i<numpr_globals ; i++)
|
||||
((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
|
||||
SafeWrite (h, pr_globals, numpr_globals*4);
|
||||
|
||||
printf ("%6i TOTAL SIZE\n", (int)ftell (h));
|
||||
|
||||
progs.entityfields = pr.size_fields;
|
||||
|
||||
progs.version = PROG_VERSION;
|
||||
progs.crc = crc;
|
||||
|
||||
// byte swap the header and write it out
|
||||
for (i=0 ; i<sizeof(progs)/4 ; i++)
|
||||
((int *)&progs)[i] = LittleLong ( ((int *)&progs)[i] );
|
||||
fseek (h, 0, SEEK_SET);
|
||||
SafeWrite (h, &progs, sizeof(progs));
|
||||
fclose (h);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PR_String
|
||||
|
||||
Returns a string suitable for printing (no newlines, max 60 chars length)
|
||||
===============
|
||||
*/
|
||||
char *PR_String (char *string)
|
||||
{
|
||||
static char buf[80];
|
||||
char *s;
|
||||
|
||||
s = buf;
|
||||
*s++ = '"';
|
||||
while (string && *string)
|
||||
{
|
||||
if (s == buf + sizeof(buf) - 2)
|
||||
break;
|
||||
if (*string == '\n')
|
||||
{
|
||||
*s++ = '\\';
|
||||
*s++ = 'n';
|
||||
}
|
||||
else if (*string == '"')
|
||||
{
|
||||
*s++ = '\\';
|
||||
*s++ = '"';
|
||||
}
|
||||
else
|
||||
*s++ = *string;
|
||||
string++;
|
||||
if (s - buf > 60)
|
||||
{
|
||||
*s++ = '.';
|
||||
*s++ = '.';
|
||||
*s++ = '.';
|
||||
break;
|
||||
}
|
||||
}
|
||||
*s++ = '"';
|
||||
*s++ = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
def_t *PR_DefForFieldOfs (gofs_t ofs)
|
||||
{
|
||||
def_t *d;
|
||||
|
||||
for (d=pr.def_head.next ; d ; d=d->next)
|
||||
{
|
||||
if (d->type->type != ev_field)
|
||||
continue;
|
||||
if (*((int *)&pr_globals[d->ofs]) == ofs)
|
||||
return d;
|
||||
}
|
||||
Error ("PR_DefForFieldOfs: couldn't find %i",ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_ValueString
|
||||
|
||||
Returns a string describing *data in a type specific manner
|
||||
=============
|
||||
*/
|
||||
char *PR_ValueString (etype_t type, void *val)
|
||||
{
|
||||
static char line[256];
|
||||
def_t *def;
|
||||
dfunction_t *f;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ev_string:
|
||||
sprintf (line, "%s", PR_String(strings + *(int *)val));
|
||||
break;
|
||||
case ev_entity:
|
||||
sprintf (line, "entity %i", *(int *)val);
|
||||
break;
|
||||
case ev_function:
|
||||
f = functions + *(int *)val;
|
||||
if (!f)
|
||||
sprintf (line, "undefined function");
|
||||
else
|
||||
sprintf (line, "%s()", strings + f->s_name);
|
||||
break;
|
||||
case ev_field:
|
||||
def = PR_DefForFieldOfs ( *(int *)val );
|
||||
sprintf (line, ".%s", def->name);
|
||||
break;
|
||||
case ev_void:
|
||||
sprintf (line, "void");
|
||||
break;
|
||||
case ev_float:
|
||||
sprintf (line, "%5.1f", *(float *)val);
|
||||
break;
|
||||
case ev_vector:
|
||||
sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]);
|
||||
break;
|
||||
case ev_pointer:
|
||||
sprintf (line, "pointer");
|
||||
break;
|
||||
default:
|
||||
sprintf (line, "bad type %i", type);
|
||||
break;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_GlobalString
|
||||
|
||||
Returns a string with a description and the contents of a global,
|
||||
padded to 20 field width
|
||||
============
|
||||
*/
|
||||
char *PR_GlobalStringNoContents (gofs_t ofs)
|
||||
{
|
||||
int i;
|
||||
def_t *def;
|
||||
void *val;
|
||||
static char line[128];
|
||||
|
||||
val = (void *)&pr_globals[ofs];
|
||||
def = pr_global_defs[ofs];
|
||||
if (!def)
|
||||
// Error ("PR_GlobalString: no def for %i", ofs);
|
||||
sprintf (line,"%i(???)", ofs);
|
||||
else
|
||||
sprintf (line,"%i(%s)", ofs, def->name);
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<16 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
char *PR_GlobalString (gofs_t ofs)
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
def_t *def;
|
||||
void *val;
|
||||
static char line[128];
|
||||
|
||||
val = (void *)&pr_globals[ofs];
|
||||
def = pr_global_defs[ofs];
|
||||
if (!def)
|
||||
return PR_GlobalStringNoContents(ofs);
|
||||
if (def->initialized && def->type->type != ev_function)
|
||||
{
|
||||
s = PR_ValueString (def->type->type, &pr_globals[ofs]);
|
||||
sprintf (line,"%i(%s)", ofs, s);
|
||||
}
|
||||
else
|
||||
sprintf (line,"%i(%s)", ofs, def->name);
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<16 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_PrintOfs
|
||||
============
|
||||
*/
|
||||
void PR_PrintOfs (gofs_t ofs)
|
||||
{
|
||||
printf ("%s\n",PR_GlobalString(ofs));
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
PR_PrintStatement
|
||||
=================
|
||||
*/
|
||||
void PR_PrintStatement (dstatement_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname);
|
||||
i = strlen(pr_opcodes[s->op].opname);
|
||||
for ( ; i<10 ; i++)
|
||||
printf (" ");
|
||||
|
||||
if (s->op == OP_IF || s->op == OP_IFNOT)
|
||||
printf ("%sbranch %i",PR_GlobalString(s->a),s->b);
|
||||
else if (s->op == OP_GOTO)
|
||||
{
|
||||
printf ("branch %i",s->a);
|
||||
}
|
||||
else if ( (unsigned)(s->op - OP_STORE_F) < 6)
|
||||
{
|
||||
printf ("%s",PR_GlobalString(s->a));
|
||||
printf ("%s", PR_GlobalStringNoContents(s->b));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->a)
|
||||
printf ("%s",PR_GlobalString(s->a));
|
||||
if (s->b)
|
||||
printf ("%s",PR_GlobalString(s->b));
|
||||
if (s->c)
|
||||
printf ("%s", PR_GlobalStringNoContents(s->c));
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_PrintDefs
|
||||
============
|
||||
*/
|
||||
void PR_PrintDefs (void)
|
||||
{
|
||||
def_t *d;
|
||||
|
||||
for (d=pr.def_head.next ; d ; d=d->next)
|
||||
PR_PrintOfs (d->ofs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_BeginCompilation
|
||||
|
||||
called before compiling a batch of files, clears the pr struct
|
||||
==============
|
||||
*/
|
||||
void PR_BeginCompilation (void *memory, int memsize)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr.memory = memory;
|
||||
pr.max_memory = memsize;
|
||||
|
||||
numpr_globals = RESERVED_OFS;
|
||||
pr.def_tail = &pr.def_head;
|
||||
|
||||
for (i=0 ; i<RESERVED_OFS ; i++)
|
||||
pr_global_defs[i] = &def_void;
|
||||
|
||||
// link the function type in so state forward declarations match proper type
|
||||
pr.types = &type_function;
|
||||
type_function.next = NULL;
|
||||
pr_error_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
PR_FinishCompilation
|
||||
|
||||
called after all files are compiled to check for errors
|
||||
Returns false if errors were detected.
|
||||
==============
|
||||
*/
|
||||
qboolean PR_FinishCompilation (void)
|
||||
{
|
||||
def_t *d;
|
||||
qboolean errors;
|
||||
|
||||
errors = false;
|
||||
|
||||
// check to make sure all functions prototyped have code
|
||||
for (d=pr.def_head.next ; d ; d=d->next)
|
||||
{
|
||||
if (d->type->type == ev_function && !d->scope)// function parms are ok
|
||||
{
|
||||
// f = G_FUNCTION(d->ofs);
|
||||
// if (!f || (!f->code && !f->builtin) )
|
||||
if (!d->initialized)
|
||||
{
|
||||
printf ("function %s was not defined\n",d->name);
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !errors;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
PR_WriteProgdefs
|
||||
|
||||
Writes the global and entity structures out
|
||||
Returns a crc of the header, to be stored in the progs file for comparison
|
||||
at load time.
|
||||
============
|
||||
*/
|
||||
int PR_WriteProgdefs (char *filename)
|
||||
{
|
||||
def_t *d;
|
||||
FILE *f;
|
||||
unsigned short crc;
|
||||
int c;
|
||||
|
||||
printf ("writing %s\n", filename);
|
||||
f = fopen (filename, "w");
|
||||
|
||||
// print global vars until the first field is defined
|
||||
fprintf (f,"\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[%i];\n", RESERVED_OFS);
|
||||
for (d=pr.def_head.next ; d ; d=d->next)
|
||||
{
|
||||
if (!strcmp (d->name, "end_sys_globals"))
|
||||
break;
|
||||
|
||||
switch (d->type->type)
|
||||
{
|
||||
case ev_float:
|
||||
fprintf (f, "\tfloat\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_vector:
|
||||
fprintf (f, "\tvec3_t\t%s;\n",d->name);
|
||||
d=d->next->next->next; // skip the elements
|
||||
break;
|
||||
case ev_string:
|
||||
fprintf (f,"\tstring_t\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_function:
|
||||
fprintf (f,"\tfunc_t\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_entity:
|
||||
fprintf (f,"\tint\t%s;\n",d->name);
|
||||
break;
|
||||
default:
|
||||
fprintf (f,"\tint\t%s;\n",d->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf (f,"} globalvars_t;\n\n");
|
||||
|
||||
// print all fields
|
||||
fprintf (f,"typedef struct\n{\n");
|
||||
for (d=pr.def_head.next ; d ; d=d->next)
|
||||
{
|
||||
if (!strcmp (d->name, "end_sys_fields"))
|
||||
break;
|
||||
|
||||
if (d->type->type != ev_field)
|
||||
continue;
|
||||
|
||||
switch (d->type->aux_type->type)
|
||||
{
|
||||
case ev_float:
|
||||
fprintf (f,"\tfloat\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_vector:
|
||||
fprintf (f,"\tvec3_t\t%s;\n",d->name);
|
||||
d=d->next->next->next; // skip the elements
|
||||
break;
|
||||
case ev_string:
|
||||
fprintf (f,"\tstring_t\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_function:
|
||||
fprintf (f,"\tfunc_t\t%s;\n",d->name);
|
||||
break;
|
||||
case ev_entity:
|
||||
fprintf (f,"\tint\t%s;\n",d->name);
|
||||
break;
|
||||
default:
|
||||
fprintf (f,"\tint\t%s;\n",d->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf (f,"} entvars_t;\n\n");
|
||||
|
||||
fclose (f);
|
||||
|
||||
// do a crc of the file
|
||||
CRC_Init (&crc);
|
||||
f = fopen (filename, "r+");
|
||||
while ((c = fgetc(f)) != EOF)
|
||||
CRC_ProcessByte (&crc, (byte)c);
|
||||
|
||||
fprintf (f,"#define PROGHEADER_CRC %i\n", crc);
|
||||
fclose (f);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
void PrintFunction (char *name)
|
||||
{
|
||||
int i;
|
||||
dstatement_t *ds;
|
||||
dfunction_t *df;
|
||||
|
||||
for (i=0 ; i<numfunctions ; i++)
|
||||
if (!strcmp (name, strings + functions[i].s_name))
|
||||
break;
|
||||
if (i==numfunctions)
|
||||
Error ("No function names \"%s\"", name);
|
||||
df = functions + i;
|
||||
|
||||
printf ("Statements for %s:\n", name);
|
||||
ds = statements + df->first_statement;
|
||||
while (1)
|
||||
{
|
||||
PR_PrintStatement (ds);
|
||||
if (!ds->op)
|
||||
break;
|
||||
ds++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
main
|
||||
============
|
||||
*/
|
||||
void main (int argc, char **argv)
|
||||
{
|
||||
char *src;
|
||||
char *src2;
|
||||
char filename[1024];
|
||||
int p, crc;
|
||||
double start, stop;
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
myargc = argc;
|
||||
myargv = argv;
|
||||
|
||||
if ( CheckParm ("-?") || CheckParm ("-help"))
|
||||
{
|
||||
printf ("qcc looks for progs.src in the current directory.\n");
|
||||
printf ("to look in a different directory: qcc -src <directory>\n");
|
||||
printf ("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
|
||||
printf ("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
|
||||
printf ("to bsp all bmodels: qcc -bspmodels <gamedir>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
p = CheckParm ("-src");
|
||||
if (p && p < argc-1 )
|
||||
{
|
||||
strcpy (sourcedir, argv[p+1]);
|
||||
strcat (sourcedir, "/");
|
||||
printf ("Source directory: %s\n", sourcedir);
|
||||
}
|
||||
else
|
||||
strcpy (sourcedir, "");
|
||||
|
||||
InitData ();
|
||||
|
||||
sprintf (filename, "%sprogs.src", sourcedir);
|
||||
LoadFile (filename, (void *)&src);
|
||||
|
||||
src = COM_Parse (src);
|
||||
if (!src)
|
||||
Error ("No destination filename. qcc -help for info.\n");
|
||||
strcpy (destfile, com_token);
|
||||
printf ("outputfile: %s\n", destfile);
|
||||
|
||||
pr_dumpasm = false;
|
||||
|
||||
PR_BeginCompilation (malloc (0x100000), 0x100000);
|
||||
|
||||
// compile all the files
|
||||
do
|
||||
{
|
||||
src = COM_Parse(src);
|
||||
if (!src)
|
||||
break;
|
||||
sprintf (filename, "%s%s", sourcedir, com_token);
|
||||
printf ("compiling %s\n", filename);
|
||||
LoadFile (filename, (void *)&src2);
|
||||
|
||||
if (!PR_CompileFile (src2, filename) )
|
||||
exit (1);
|
||||
|
||||
} while (1);
|
||||
|
||||
if (!PR_FinishCompilation ())
|
||||
Error ("compilation errors");
|
||||
|
||||
p = CheckParm ("-asm");
|
||||
if (p)
|
||||
{
|
||||
for (p++ ; p<argc ; p++)
|
||||
{
|
||||
if (argv[p][0] == '-')
|
||||
break;
|
||||
PrintFunction (argv[p]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// write progdefs.h
|
||||
crc = PR_WriteProgdefs ("progdefs.h");
|
||||
|
||||
// write data file
|
||||
WriteData (crc);
|
||||
|
||||
// write files.dat
|
||||
WriteFiles ();
|
||||
|
||||
stop = I_FloatTime ();
|
||||
printf ("%i seconds elapsed.\n", (int)(stop-start));
|
||||
}
|
||||
436
qutils/QCC/QCC.H
Normal file
436
qutils/QCC/QCC.H
Normal file
@@ -0,0 +1,436 @@
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "pr_comp.h"
|
||||
|
||||
/*
|
||||
|
||||
TODO:
|
||||
|
||||
"stopped at 10 errors"
|
||||
|
||||
other pointer types for models and clients?
|
||||
|
||||
compact string heap?
|
||||
|
||||
allways initialize all variables to something safe
|
||||
|
||||
the def->type->type arrangement is really silly.
|
||||
|
||||
return type checking
|
||||
|
||||
parm count type checking
|
||||
|
||||
immediate overflow checking
|
||||
|
||||
pass the first two parms in call->b and call->c
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
comments
|
||||
--------
|
||||
// comments discard text until the end of line
|
||||
/ * * / comments discard all enclosed text (spaced out on this line because this documentation is in a regular C comment block, and typing them in normally causes a parse error)
|
||||
|
||||
code structure
|
||||
--------------
|
||||
A definition is:
|
||||
<type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
|
||||
|
||||
|
||||
types
|
||||
-----
|
||||
simple types: void, float, vector, string, or entity
|
||||
float width, height;
|
||||
string name;
|
||||
entity self, other;
|
||||
|
||||
vector types:
|
||||
vector org; // also creates org_x, org_y, and org_z float defs
|
||||
|
||||
|
||||
A function type is specified as: simpletype ( type name {,type name} )
|
||||
The names are ignored except when the function is initialized.
|
||||
void() think;
|
||||
entity() FindTarget;
|
||||
void(vector destination, float speed, void() callback) SUB_CalcMove;
|
||||
void(...) dprint; // variable argument builtin
|
||||
|
||||
A field type is specified as: .type
|
||||
.vector origin;
|
||||
.string netname;
|
||||
.void() think, touch, use;
|
||||
|
||||
|
||||
names
|
||||
-----
|
||||
Names are a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9.
|
||||
|
||||
There are two levels of scoping: global, and function. The parameter list of a function and any vars declared inside a function with the "local" statement are only visible within that function,
|
||||
|
||||
|
||||
immediates
|
||||
----------
|
||||
Float immediates must begin with 0-9 or minus sign. .5 is illegal.
|
||||
|
||||
A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Seperate the - from the digits with a space "a - 5" to get the proper behavior.
|
||||
12
|
||||
1.6
|
||||
0.5
|
||||
-100
|
||||
|
||||
Vector immediates are three float immediates enclosed in single quotes.
|
||||
'0 0 0'
|
||||
'20.5 -10 0.00001'
|
||||
|
||||
String immediates are characters enclosed in double quotes. The string cannot contain explicit newlines, but the escape character \n can embed one. The \" escape can be used to include a quote in the string.
|
||||
"maps/jrwiz1.bsp"
|
||||
"sound/nin/pain.wav"
|
||||
"ouch!\n"
|
||||
|
||||
Code immediates are statements enclosed in {} braces.
|
||||
statement:
|
||||
{ <multiple statements> }
|
||||
<expression>;
|
||||
local <type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
|
||||
return <expression>;
|
||||
if ( <expression> ) <statement> [ else <statement> ];
|
||||
while ( <expression> ) <statement>;
|
||||
do <statement> while ( <expression> );
|
||||
<function name> ( <function parms> );
|
||||
|
||||
expression:
|
||||
combiations of names and these operators with standard C precedence:
|
||||
"&&", "||", "<=", ">=","==", "!=", "!", "*", "/", "-", "+", "=", ".", "<", ">", "&", "|"
|
||||
Parenthesis can be used to alter order of operation.
|
||||
The & and | operations perform integral bit ops on floats
|
||||
|
||||
A built in function immediate is a number sign followed by an integer.
|
||||
#1
|
||||
#12
|
||||
|
||||
|
||||
compilation
|
||||
-----------
|
||||
Source files are processed sequentially without dumping any state, so if a defs file is the first one processed, the definitions will be available to all other files.
|
||||
|
||||
The language is strongly typed and there are no casts.
|
||||
|
||||
Anything that is initialized is assumed to be constant, and will have immediates folded into it. If you change the value, your program will malfunction. All uninitialized globals will be saved to savegame files.
|
||||
|
||||
Functions cannot have more than eight parameters.
|
||||
|
||||
Error recovery during compilation is minimal. It will skip to the next global definition, so you will never see more than one error at a time in a given function. All compilation aborts after ten error messages.
|
||||
|
||||
Names can be defined multiple times until they are defined with an initialization, allowing functions to be prototyped before their definition.
|
||||
|
||||
void() MyFunction; // the prototype
|
||||
|
||||
void() MyFunction = // the initialization
|
||||
{
|
||||
dprint ("we're here\n");
|
||||
};
|
||||
|
||||
|
||||
entities and fields
|
||||
-------------------
|
||||
|
||||
|
||||
execution
|
||||
---------
|
||||
Code execution is initiated by C code in quake from two main places: the timed think routines for periodic control, and the touch function when two objects impact each other.
|
||||
|
||||
There are three global variables that are set before beginning code execution:
|
||||
entity world; // the server's world object, which holds all global
|
||||
// state for the server, like the deathmatch flags
|
||||
// and the body ques.
|
||||
entity self; // the entity the function is executing for
|
||||
entity other; // the other object in an impact, not used for thinks
|
||||
float time; // the current game time. Note that because the
|
||||
// entities in the world are simulated sequentially,
|
||||
// time is NOT strictly increasing. An impact late
|
||||
// in one entity's time slice may set time higher
|
||||
// than the think function of the next entity.
|
||||
// The difference is limited to 0.1 seconds.
|
||||
Execution is also caused by a few uncommon events, like the addition of a new client to an existing server.
|
||||
|
||||
There is a runnaway counter that stops a program if 100000 statements are executed, assuming it is in an infinite loop.
|
||||
|
||||
It is acceptable to change the system set global variables. This is usually done to pose as another entity by changing self and calling a function.
|
||||
|
||||
The interpretation is fairly efficient, but it is still over an order of magnitude slower than compiled C code. All time consuming operations should be made into built in functions.
|
||||
|
||||
A profile counter is kept for each function, and incremented for each interpreted instruction inside that function. The "profile" console command in Quake will dump out the top 10 functions, then clear all the counters. The "profile all" command will dump sorted stats for every function that has been executed.
|
||||
|
||||
|
||||
afunc ( 4, bfunc(1,2,3));
|
||||
will fail because there is a shared parameter marshaling area, which will cause the 1 from bfunc to overwrite the 4 allready placed in parm0. When a function is called, it copies the parms from the globals into it's privately scoped variables, so there is no collision when calling another function.
|
||||
|
||||
total = factorial(3) + factorial(4);
|
||||
Will fail because the return value from functions is held in a single global area. If this really gets on your nerves, tell me and I can work around it at a slight performance and space penalty by allocating a new register for the function call and copying it out.
|
||||
|
||||
|
||||
built in functions
|
||||
------------------
|
||||
void(string text) dprint;
|
||||
Prints the string to the server console.
|
||||
|
||||
void(entity client, string text) cprint;
|
||||
Prints a message to a specific client.
|
||||
|
||||
void(string text) bprint;
|
||||
Broadcast prints a message to all clients on the current server.
|
||||
|
||||
entity() spawn;
|
||||
Returns a totally empty entity. You can manually set everything up, or just set the origin and call one of the existing entity setup functions.
|
||||
|
||||
entity(entity start, .string field, string match) find;
|
||||
Searches the server entity list beginning at start, looking for an entity that has entity.field = match. To start at the beginning of the list, pass world. World is returned when the end of the list is reached.
|
||||
|
||||
<FIXME: define all the other functions...>
|
||||
|
||||
|
||||
gotchas
|
||||
-------
|
||||
|
||||
The && and || operators DO NOT EARLY OUT like C!
|
||||
|
||||
Don't confuse single quoted vectors with double quoted strings
|
||||
|
||||
The function declaration syntax takes a little getting used to.
|
||||
|
||||
Don't forget the ; after the trailing brace of a function initialization.
|
||||
|
||||
Don't forget the "local" before defining local variables.
|
||||
|
||||
There are no ++ / -- operators, or operate/assign operators.
|
||||
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// offsets are allways multiplied by 4 before using
|
||||
typedef int gofs_t; // offset in global data block
|
||||
typedef struct function_s function_t;
|
||||
|
||||
#define MAX_PARMS 8
|
||||
|
||||
typedef struct type_s
|
||||
{
|
||||
etype_t type;
|
||||
struct def_s *def; // a def that points to this type
|
||||
struct type_s *next;
|
||||
// function types are more complex
|
||||
struct type_s *aux_type; // return type or field type
|
||||
int num_parms; // -1 = variable args
|
||||
struct type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated
|
||||
} type_t;
|
||||
|
||||
typedef struct def_s
|
||||
{
|
||||
type_t *type;
|
||||
char *name;
|
||||
struct def_s *next;
|
||||
struct def_s *search_next; // for finding faster
|
||||
gofs_t ofs;
|
||||
struct def_s *scope; // function the var was defined in, or NULL
|
||||
int initialized; // 1 when a declaration included "= immediate"
|
||||
} def_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
// pr_loc.h -- program local defs
|
||||
|
||||
#define MAX_ERRORS 10
|
||||
|
||||
#define MAX_NAME 64 // chars long
|
||||
|
||||
#define MAX_REGS 16384
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef union eval_s
|
||||
{
|
||||
string_t string;
|
||||
float _float;
|
||||
float vector[3];
|
||||
func_t function;
|
||||
int _int;
|
||||
union eval_s *ptr;
|
||||
} eval_t;
|
||||
|
||||
extern int type_size[8];
|
||||
extern def_t *def_for_type[8];
|
||||
|
||||
extern type_t type_void, type_string, type_float, type_vector, type_entity, type_field, type_function, type_pointer, type_floatfield;
|
||||
|
||||
extern def_t def_void, def_string, def_float, def_vector, def_entity, def_field, def_function, def_pointer;
|
||||
|
||||
struct function_s
|
||||
{
|
||||
int builtin; // if non 0, call an internal function
|
||||
int code; // first statement
|
||||
char *file; // source file with definition
|
||||
int file_line;
|
||||
struct def_s *def;
|
||||
int parm_ofs[MAX_PARMS]; // allways contiguous, right?
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// output generated by prog parsing
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
char *memory;
|
||||
int max_memory;
|
||||
int current_memory;
|
||||
type_t *types;
|
||||
|
||||
def_t def_head; // unused head of linked list
|
||||
def_t *def_tail; // add new defs after this and move it
|
||||
def_t *search; // search chain through defs
|
||||
|
||||
int size_fields;
|
||||
} pr_info_t;
|
||||
|
||||
extern pr_info_t pr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *opname;
|
||||
float priority;
|
||||
qboolean right_associative;
|
||||
def_t *type_a, *type_b, *type_c;
|
||||
} opcode_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
extern opcode_t pr_opcodes[99]; // sized by initialization
|
||||
|
||||
extern qboolean pr_dumpasm;
|
||||
|
||||
extern def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable
|
||||
|
||||
typedef enum {
|
||||
tt_eof, // end of file reached
|
||||
tt_name, // an alphanumeric name token
|
||||
tt_punct, // code punctuation
|
||||
tt_immediate, // string, float, vector
|
||||
} token_type_t;
|
||||
|
||||
extern char pr_token[2048];
|
||||
extern token_type_t pr_token_type;
|
||||
extern type_t *pr_immediate_type;
|
||||
extern eval_t pr_immediate;
|
||||
|
||||
void PR_PrintStatement (dstatement_t *s);
|
||||
|
||||
void PR_Lex (void);
|
||||
// reads the next token into pr_token and classifies its type
|
||||
|
||||
type_t *PR_ParseType (void);
|
||||
char *PR_ParseName (void);
|
||||
|
||||
qboolean PR_Check (char *string);
|
||||
void PR_Expect (char *string);
|
||||
void PR_ParseError (char *error, ...);
|
||||
|
||||
|
||||
extern jmp_buf pr_parse_abort; // longjump with this on parse error
|
||||
extern int pr_source_line;
|
||||
extern char *pr_file_p;
|
||||
|
||||
void *PR_Malloc (int size);
|
||||
|
||||
|
||||
#define OFS_NULL 0
|
||||
#define OFS_RETURN 1
|
||||
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
|
||||
#define OFS_PARM1 7
|
||||
#define OFS_PARM2 10
|
||||
#define OFS_PARM3 13
|
||||
#define OFS_PARM4 16
|
||||
#define RESERVED_OFS 28
|
||||
|
||||
|
||||
extern def_t *pr_scope;
|
||||
extern int pr_error_count;
|
||||
|
||||
void PR_NewLine (void);
|
||||
def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate);
|
||||
|
||||
void PR_PrintDefs (void);
|
||||
|
||||
void PR_SkipToSemicolon (void);
|
||||
|
||||
extern char pr_parm_names[MAX_PARMS][MAX_NAME];
|
||||
extern qboolean pr_trace;
|
||||
|
||||
#define G_FLOAT(o) (pr_globals[o])
|
||||
#define G_INT(o) (*(int *)&pr_globals[o])
|
||||
#define G_VECTOR(o) (&pr_globals[o])
|
||||
#define G_STRING(o) (strings + *(string_t *)&pr_globals[o])
|
||||
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
|
||||
|
||||
char *PR_ValueString (etype_t type, void *val);
|
||||
|
||||
void PR_ClearGrabMacros (void);
|
||||
|
||||
qboolean PR_CompileFile (char *string, char *filename);
|
||||
|
||||
extern qboolean pr_dumpasm;
|
||||
|
||||
extern string_t s_file; // filename for function definition
|
||||
|
||||
extern def_t def_ret, def_parms[MAX_PARMS];
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#define MAX_STRINGS 500000
|
||||
#define MAX_GLOBALS 16384
|
||||
#define MAX_FIELDS 1024
|
||||
#define MAX_STATEMENTS 65536
|
||||
#define MAX_FUNCTIONS 8192
|
||||
|
||||
#define MAX_SOUNDS 1024
|
||||
#define MAX_MODELS 1024
|
||||
#define MAX_FILES 1024
|
||||
#define MAX_DATA_PATH 64
|
||||
|
||||
extern char strings[MAX_STRINGS];
|
||||
extern int strofs;
|
||||
|
||||
extern dstatement_t statements[MAX_STATEMENTS];
|
||||
extern int numstatements;
|
||||
extern int statement_linenums[MAX_STATEMENTS];
|
||||
|
||||
extern dfunction_t functions[MAX_FUNCTIONS];
|
||||
extern int numfunctions;
|
||||
|
||||
extern float pr_globals[MAX_REGS];
|
||||
extern int numpr_globals;
|
||||
|
||||
extern char pr_immediate_string[2048];
|
||||
|
||||
extern char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
|
||||
extern int precache_sounds_block[MAX_SOUNDS];
|
||||
extern int numsounds;
|
||||
|
||||
extern char precache_models[MAX_MODELS][MAX_DATA_PATH];
|
||||
extern int precache_models_block[MAX_SOUNDS];
|
||||
extern int nummodels;
|
||||
|
||||
extern char precache_files[MAX_FILES][MAX_DATA_PATH];
|
||||
extern int precache_files_block[MAX_SOUNDS];
|
||||
extern int numfiles;
|
||||
|
||||
int CopyString (char *str);
|
||||
|
||||
|
||||
249
qutils/QCC/QCC.MAK
Normal file
249
qutils/QCC/QCC.MAK
Normal file
@@ -0,0 +1,249 @@
|
||||
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=qcc - Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to qcc - Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "qcc - Win32 Release" && "$(CFG)" != "qcc - Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "qcc.mak" CFG="qcc - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "qcc - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "qcc - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(OS)" == "Windows_NT"
|
||||
NULL=
|
||||
!ELSE
|
||||
NULL=nul
|
||||
!ENDIF
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "qcc - Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "qcc - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
OUTDIR=.\Release
|
||||
INTDIR=.\Release
|
||||
|
||||
ALL : "$(OUTDIR)\qcc.exe"
|
||||
|
||||
CLEAN :
|
||||
-@erase ".\Release\qcc.exe"
|
||||
-@erase ".\Release\qcc.obj"
|
||||
-@erase ".\Release\pr_comp.obj"
|
||||
-@erase ".\Release\pr_lex.obj"
|
||||
-@erase ".\Release\cmdlib.obj"
|
||||
-@erase ".\Release\vc40.pdb"
|
||||
-@erase ".\Release\qcc.map"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
|
||||
CPP_PROJ=/nologo /ML /GX /Zi /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\
|
||||
"_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Release/
|
||||
CPP_SBRS=
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc"
|
||||
BSC32_SBRS=
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /machine:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
||||
odbccp32.lib /nologo /subsystem:console /profile /map:"$(INTDIR)/qcc.map"\
|
||||
/machine:I386 /out:"$(OUTDIR)/qcc.exe"
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)/qcc.obj" \
|
||||
"$(INTDIR)/pr_comp.obj" \
|
||||
"$(INTDIR)/pr_lex.obj" \
|
||||
"$(INTDIR)/cmdlib.obj"
|
||||
|
||||
"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "qcc - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
OUTDIR=.\Debug
|
||||
INTDIR=.\Debug
|
||||
|
||||
ALL : "$(OUTDIR)\qcc.exe"
|
||||
|
||||
CLEAN :
|
||||
-@erase ".\Debug\vc40.pdb"
|
||||
-@erase ".\Debug\vc40.idb"
|
||||
-@erase ".\Debug\qcc.exe"
|
||||
-@erase ".\Debug\pr_lex.obj"
|
||||
-@erase ".\Debug\qcc.obj"
|
||||
-@erase ".\Debug\cmdlib.obj"
|
||||
-@erase ".\Debug\pr_comp.obj"
|
||||
-@erase ".\Debug\qcc.map"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
|
||||
CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\
|
||||
"_CONSOLE" /Fp"$(INTDIR)/qcc.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Debug/
|
||||
CPP_SBRS=
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qcc.bsc"
|
||||
BSC32_SBRS=
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
||||
odbccp32.lib /nologo /subsystem:console /profile /map:"$(INTDIR)/qcc.map"\
|
||||
/debug /machine:I386 /out:"$(OUTDIR)/qcc.exe"
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)/pr_lex.obj" \
|
||||
"$(INTDIR)/qcc.obj" \
|
||||
"$(INTDIR)/cmdlib.obj" \
|
||||
"$(INTDIR)/pr_comp.obj"
|
||||
|
||||
"$(OUTDIR)\qcc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.c{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Target
|
||||
|
||||
# Name "qcc - Win32 Release"
|
||||
# Name "qcc - Win32 Debug"
|
||||
|
||||
!IF "$(CFG)" == "qcc - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qcc - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pr_comp.c
|
||||
DEP_CPP_PR_CO=\
|
||||
".\qcc.h"\
|
||||
".\..\common\cmdlib.h"\
|
||||
".\pr_comp.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\pr_comp.obj" : $(SOURCE) $(DEP_CPP_PR_CO) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\qcc.c
|
||||
DEP_CPP_QCC_C=\
|
||||
".\qcc.h"\
|
||||
".\..\common\cmdlib.h"\
|
||||
".\pr_comp.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\qcc.obj" : $(SOURCE) $(DEP_CPP_QCC_C) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pr_lex.c
|
||||
DEP_CPP_PR_LE=\
|
||||
".\qcc.h"\
|
||||
".\..\common\cmdlib.h"\
|
||||
".\pr_comp.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\pr_lex.obj" : $(SOURCE) $(DEP_CPP_PR_LE) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\quake\utils2\common\cmdlib.c
|
||||
DEP_CPP_CMDLI=\
|
||||
".\..\common\cmdlib.h"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
################################################################################
|
||||
BIN
qutils/QCC/QCC.MDP
Normal file
BIN
qutils/QCC/QCC.MDP
Normal file
Binary file not shown.
BIN
qutils/QCC/QCC.NCB
Normal file
BIN
qutils/QCC/QCC.NCB
Normal file
Binary file not shown.
BIN
qutils/QCC/QCC.PDB
Normal file
BIN
qutils/QCC/QCC.PDB
Normal file
Binary file not shown.
BIN
qutils/QCC/VC40.PDB
Normal file
BIN
qutils/QCC/VC40.PDB
Normal file
Binary file not shown.
Reference in New Issue
Block a user