2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
24
/*****************************************************************************
29
* $Archive: /MissionPack/code/botlib/l_precomp.c $
31
*****************************************************************************/
33
//Notes: fix: PC_StringizeTokens
50
#include "l_precomp.h"
52
typedef enum {qfalse, qtrue} qboolean;
56
#include "../qcommon/q_shared.h"
58
#include "be_interface.h"
61
#include "l_precomp.h"
67
#include "time.h" //time & ctime
68
#include "math.h" //fabs
71
#include "l_precomp.h"
79
//include files for usage in the BSP Converter
80
#include "../bspc/qbsp.h"
81
#include "../bspc/l_log.h"
82
#include "../bspc/l_mem.h"
83
#include "l_precomp.h"
87
#define Q_stricmp stricmp
91
#if defined(QUAKE) && !defined(BSPC)
97
#define MAX_DEFINEPARMS 128
99
#define DEFINEHASHING 1
101
//directive name with parse function
102
typedef struct directive_s
105
int (*func)(source_t *source);
108
#define DEFINEHASHSIZE 1024
110
#define TOKEN_HEAP_SIZE 4096
114
int tokenheapinitialized; //true when the token heap is initialized
115
token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens
116
token_t *freetokens; //free tokens from the heap
119
//list with global defines added to every source loaded
120
define_t *globaldefines;
122
//============================================================================
126
// Changes Globals: -
127
//============================================================================
128
void QDECL SourceError(source_t *source, char *str, ...)
134
vsprintf(text, str, ap);
137
botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
140
printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
143
Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
145
} //end of the function SourceError
146
//===========================================================================
150
// Changes Globals: -
151
//===========================================================================
152
void QDECL SourceWarning(source_t *source, char *str, ...)
158
vsprintf(text, str, ap);
161
botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
164
printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
167
Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
169
} //end of the function ScriptWarning
170
//============================================================================
174
// Changes Globals: -
175
//============================================================================
176
void PC_PushIndent(source_t *source, int type, int skip)
180
indent = (indent_t *) GetMemory(sizeof(indent_t));
182
indent->script = source->scriptstack;
183
indent->skip = (skip != 0);
184
source->skip += indent->skip;
185
indent->next = source->indentstack;
186
source->indentstack = indent;
187
} //end of the function PC_PushIndent
188
//============================================================================
192
// Changes Globals: -
193
//============================================================================
194
void PC_PopIndent(source_t *source, int *type, int *skip)
201
indent = source->indentstack;
204
//must be an indent from the current script
205
if (source->indentstack->script != source->scriptstack) return;
207
*type = indent->type;
208
*skip = indent->skip;
209
source->indentstack = source->indentstack->next;
210
source->skip -= indent->skip;
212
} //end of the function PC_PopIndent
213
//============================================================================
217
// Changes Globals: -
218
//============================================================================
219
void PC_PushScript(source_t *source, script_t *script)
223
for (s = source->scriptstack; s; s = s->next)
225
if (!Q_stricmp(s->filename, script->filename))
227
SourceError(source, "%s recursively included", script->filename);
231
//push the script on the script stack
232
script->next = source->scriptstack;
233
source->scriptstack = script;
234
} //end of the function PC_PushScript
235
//============================================================================
239
// Changes Globals: -
240
//============================================================================
241
void PC_InitTokenHeap(void)
246
if (tokenheapinitialized) return;
248
for (i = 0; i < TOKEN_HEAP_SIZE; i++)
250
token_heap[i].next = freetokens;
251
freetokens = &token_heap[i];
253
tokenheapinitialized = qtrue;
255
} //end of the function PC_InitTokenHeap
256
//============================================================================
260
// Changes Globals: -
261
//============================================================================
262
token_t *PC_CopyToken(token_t *token)
266
// t = (token_t *) malloc(sizeof(token_t));
267
t = (token_t *) GetMemory(sizeof(token_t));
272
Error("out of token space\n");
274
Com_Error(ERR_FATAL, "out of token space\n");
278
// freetokens = freetokens->next;
279
Com_Memcpy(t, token, sizeof(token_t));
283
} //end of the function PC_CopyToken
284
//============================================================================
288
// Changes Globals: -
289
//============================================================================
290
void PC_FreeToken(token_t *token)
294
// token->next = freetokens;
295
// freetokens = token;
297
} //end of the function PC_FreeToken
298
//============================================================================
302
// Changes Globals: -
303
//============================================================================
304
int PC_ReadSourceToken(source_t *source, token_t *token)
310
//if there's no token already available
311
while(!source->tokens)
313
//if there's a token to read from the script
314
if (PS_ReadToken(source->scriptstack, token)) return qtrue;
315
//if at the end of the script
316
if (EndOfScript(source->scriptstack))
318
//remove all indents of the script
319
while(source->indentstack &&
320
source->indentstack->script == source->scriptstack)
322
SourceWarning(source, "missing #endif");
323
PC_PopIndent(source, &type, &skip);
326
//if this was the initial script
327
if (!source->scriptstack->next) return qfalse;
328
//remove the script and return to the last one
329
script = source->scriptstack;
330
source->scriptstack = source->scriptstack->next;
333
//copy the already available token
334
Com_Memcpy(token, source->tokens, sizeof(token_t));
335
//free the read token
337
source->tokens = source->tokens->next;
340
} //end of the function PC_ReadSourceToken
341
//============================================================================
345
// Changes Globals: -
346
//============================================================================
347
int PC_UnreadSourceToken(source_t *source, token_t *token)
351
t = PC_CopyToken(token);
352
t->next = source->tokens;
355
} //end of the function PC_UnreadSourceToken
356
//============================================================================
360
// Changes Globals: -
361
//============================================================================
362
int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)
364
token_t token, *t, *last;
365
int i, done, lastcomma, numparms, indent;
367
if (!PC_ReadSourceToken(source, &token))
369
SourceError(source, "define %s missing parms", define->name);
373
if (define->numparms > maxparms)
375
SourceError(source, "define with more than %d parameters", maxparms);
379
for (i = 0; i < define->numparms; i++) parms[i] = NULL;
381
if (strcmp(token.string, "("))
383
PC_UnreadSourceToken(source, &token);
384
SourceError(source, "define %s missing parms", define->name);
387
//read the define parameters
388
for (done = 0, numparms = 0, indent = 0; !done;)
390
if (numparms >= maxparms)
392
SourceError(source, "define %s with too many parms", define->name);
395
if (numparms >= define->numparms)
397
SourceWarning(source, "define %s has too many parms", define->name);
400
parms[numparms] = NULL;
406
if (!PC_ReadSourceToken(source, &token))
408
SourceError(source, "define %s incomplete", define->name);
412
if (!strcmp(token.string, ","))
416
if (lastcomma) SourceWarning(source, "too many comma's");
423
if (!strcmp(token.string, "("))
428
else if (!strcmp(token.string, ")"))
432
if (!parms[define->numparms-1])
434
SourceWarning(source, "too few define parms");
441
if (numparms < define->numparms)
444
t = PC_CopyToken(&token);
446
if (last) last->next = t;
447
else parms[numparms] = t;
454
} //end of the function PC_ReadDefineParms
455
//============================================================================
459
// Changes Globals: -
460
//============================================================================
461
int PC_StringizeTokens(token_t *tokens, token_t *token)
465
token->type = TT_STRING;
466
token->whitespace_p = NULL;
467
token->endwhitespace_p = NULL;
468
token->string[0] = '\0';
469
strcat(token->string, "\"");
470
for (t = tokens; t; t = t->next)
472
strncat(token->string, t->string, MAX_TOKEN - strlen(token->string));
474
strncat(token->string, "\"", MAX_TOKEN - strlen(token->string));
476
} //end of the function PC_StringizeTokens
477
//============================================================================
481
// Changes Globals: -
482
//============================================================================
483
int PC_MergeTokens(token_t *t1, token_t *t2)
485
//merging of a name with a name or number
486
if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))
488
strcat(t1->string, t2->string);
491
//merging of two strings
492
if (t1->type == TT_STRING && t2->type == TT_STRING)
494
//remove trailing double quote
495
t1->string[strlen(t1->string)-1] = '\0';
496
//concat without leading double quote
497
strcat(t1->string, &t2->string[1]);
500
//FIXME: merging of two number of the same sub type
502
} //end of the function PC_MergeTokens
503
//============================================================================
507
// Changes Globals: -
508
//============================================================================
510
void PC_PrintDefine(define_t *define)
512
printf("define->name = %s\n", define->name);
513
printf("define->flags = %d\n", define->flags);
514
printf("define->builtin = %d\n", define->builtin);
515
printf("define->numparms = %d\n", define->numparms);
516
// token_t *parms; //define parameters
517
// token_t *tokens; //macro tokens (possibly containing parm tokens)
518
// struct define_s *next; //next defined macro in a list
519
} //end of the function PC_PrintDefine*/
521
//============================================================================
525
// Changes Globals: -
526
//============================================================================
527
void PC_PrintDefineHashTable(define_t **definehash)
532
for (i = 0; i < DEFINEHASHSIZE; i++)
534
Log_Write("%4d:", i);
535
for (d = definehash[i]; d; d = d->hashnext)
537
Log_Write(" %s", d->name);
541
} //end of the function PC_PrintDefineHashTable
542
//============================================================================
546
// Changes Globals: -
547
//============================================================================
548
//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47};
550
int PC_NameHash(char *name)
552
int register hash, i;
555
for (i = 0; name[i] != '\0'; i++)
557
hash += name[i] * (119 + i);
558
//hash += (name[i] << 7) + i;
559
//hash += (name[i] << (i&15));
561
hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
563
} //end of the function PC_NameHash
564
//============================================================================
568
// Changes Globals: -
569
//============================================================================
570
void PC_AddDefineToHash(define_t *define, define_t **definehash)
574
hash = PC_NameHash(define->name);
575
define->hashnext = definehash[hash];
576
definehash[hash] = define;
577
} //end of the function PC_AddDefineToHash
578
//============================================================================
582
// Changes Globals: -
583
//============================================================================
584
define_t *PC_FindHashedDefine(define_t **definehash, char *name)
589
hash = PC_NameHash(name);
590
for (d = definehash[hash]; d; d = d->hashnext)
592
if (!strcmp(d->name, name)) return d;
595
} //end of the function PC_FindHashedDefine
596
#endif //DEFINEHASHING
597
//============================================================================
601
// Changes Globals: -
602
//============================================================================
603
define_t *PC_FindDefine(define_t *defines, char *name)
607
for (d = defines; d; d = d->next)
609
if (!strcmp(d->name, name)) return d;
612
} //end of the function PC_FindDefine
613
//============================================================================
616
// Returns: number of the parm
617
// if no parm found with the given name -1 is returned
618
// Changes Globals: -
619
//============================================================================
620
int PC_FindDefineParm(define_t *define, char *name)
626
for (p = define->parms; p; p = p->next)
628
if (!strcmp(p->string, name)) return i;
632
} //end of the function PC_FindDefineParm
633
//============================================================================
637
// Changes Globals: -
638
//============================================================================
639
void PC_FreeDefine(define_t *define)
643
//free the define parameters
644
for (t = define->parms; t; t = next)
649
//free the define tokens
650
for (t = define->tokens; t; t = next)
657
} //end of the function PC_FreeDefine
658
//============================================================================
662
// Changes Globals: -
663
//============================================================================
664
void PC_AddBuiltinDefines(source_t *source)
672
} builtin[] = { // bk001204 - brackets
673
{ "__LINE__", BUILTIN_LINE },
674
{ "__FILE__", BUILTIN_FILE },
675
{ "__DATE__", BUILTIN_DATE },
676
{ "__TIME__", BUILTIN_TIME },
677
// { "__STDC__", BUILTIN_STDC },
681
for (i = 0; builtin[i].string; i++)
683
define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1);
684
Com_Memset(define, 0, sizeof(define_t));
685
define->name = (char *) define + sizeof(define_t);
686
strcpy(define->name, builtin[i].string);
687
define->flags |= DEFINE_FIXED;
688
define->builtin = builtin[i].builtin;
689
//add the define to the source
691
PC_AddDefineToHash(define, source->definehash);
693
define->next = source->defines;
694
source->defines = define;
695
#endif //DEFINEHASHING
697
} //end of the function PC_AddBuiltinDefines
698
//============================================================================
702
// Changes Globals: -
703
//============================================================================
704
int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,
705
token_t **firsttoken, token_t **lasttoken)
709
unsigned long t; // time_t t; //to prevent LCC warning
716
token = PC_CopyToken(deftoken);
717
switch(define->builtin)
721
sprintf(token->string, "%d", deftoken->line);
723
token->intvalue = deftoken->line;
724
token->floatvalue = deftoken->line;
726
token->type = TT_NUMBER;
727
token->subtype = TT_DECIMAL | TT_INTEGER;
734
strcpy(token->string, source->scriptstack->filename);
735
token->type = TT_NAME;
736
token->subtype = strlen(token->string);
745
strcpy(token->string, "\"");
746
strncat(token->string, curtime+4, 7);
747
strncat(token->string+7, curtime+20, 4);
748
strcat(token->string, "\"");
750
token->type = TT_NAME;
751
token->subtype = strlen(token->string);
760
strcpy(token->string, "\"");
761
strncat(token->string, curtime+11, 8);
762
strcat(token->string, "\"");
764
token->type = TT_NAME;
765
token->subtype = strlen(token->string);
779
} //end of the function PC_ExpandBuiltinDefine
780
//============================================================================
784
// Changes Globals: -
785
//============================================================================
786
int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,
787
token_t **firsttoken, token_t **lasttoken)
789
token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
790
token_t *t1, *t2, *first, *last, *nextpt, token;
793
//if it is a builtin define
796
return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);
798
//if the define has parameters
799
if (define->numparms)
801
if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse;
803
for (i = 0; i < define->numparms; i++)
805
Log_Write("define parms %d:", i);
806
for (pt = parms[i]; pt; pt = pt->next)
808
Log_Write("%s", pt->string);
813
//empty list at first
816
//create a list with tokens of the expanded define
817
for (dt = define->tokens; dt; dt = dt->next)
820
//if the token is a name, it could be a define parameter
821
if (dt->type == TT_NAME)
823
parmnum = PC_FindDefineParm(define, dt->string);
825
//if it is a define parameter
828
for (pt = parms[parmnum]; pt; pt = pt->next)
830
t = PC_CopyToken(pt);
831
//add the token to the list
833
if (last) last->next = t;
840
//if stringizing operator
841
if (dt->string[0] == '#' && dt->string[1] == '\0')
843
//the stringizing operator must be followed by a define parameter
844
if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string);
849
//step over the stringizing operator
851
//stringize the define parameter tokens
852
if (!PC_StringizeTokens(parms[parmnum], &token))
854
SourceError(source, "can't stringize tokens");
857
t = PC_CopyToken(&token);
861
SourceWarning(source, "stringizing operator without define parameter");
867
t = PC_CopyToken(dt);
869
//add the token to the list
871
if (last) last->next = t;
876
//check for the merging operator
881
//if the merging operator
882
if (t->next->string[0] == '#' && t->next->string[1] == '#')
888
if (!PC_MergeTokens(t1, t2))
890
SourceError(source, "can't merge %s with %s", t1->string, t2->string);
893
PC_FreeToken(t1->next);
895
if (t2 == last) last = t1;
903
//store the first and last token of the list
906
//free all the parameter tokens
907
for (i = 0; i < define->numparms; i++)
909
for (pt = parms[i]; pt; pt = nextpt)
917
} //end of the function PC_ExpandDefine
918
//============================================================================
922
// Changes Globals: -
923
//============================================================================
924
int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)
926
token_t *firsttoken, *lasttoken;
928
if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse;
930
if (firsttoken && lasttoken)
932
lasttoken->next = source->tokens;
933
source->tokens = firsttoken;
937
} //end of the function PC_ExpandDefineIntoSource
938
//============================================================================
942
// Changes Globals: -
943
//============================================================================
944
void PC_ConvertPath(char *path)
948
//remove double path seperators
949
for (ptr = path; *ptr;)
951
if ((*ptr == '\\' || *ptr == '/') &&
952
(*(ptr+1) == '\\' || *(ptr+1) == '/'))
961
//set OS dependent path seperators
962
for (ptr = path; *ptr;)
964
if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR;
967
} //end of the function PC_ConvertPath
968
//============================================================================
972
// Changes Globals: -
973
//============================================================================
974
int PC_Directive_include(source_t *source)
983
if (source->skip > 0) return qtrue;
985
if (!PC_ReadSourceToken(source, &token))
987
SourceError(source, "#include without file name");
990
if (token.linescrossed > 0)
992
SourceError(source, "#include without file name");
995
if (token.type == TT_STRING)
997
StripDoubleQuotes(token.string);
998
PC_ConvertPath(token.string);
999
script = LoadScriptFile(token.string);
1002
strcpy(path, source->includepath);
1003
strcat(path, token.string);
1004
script = LoadScriptFile(path);
1007
else if (token.type == TT_PUNCTUATION && *token.string == '<')
1009
strcpy(path, source->includepath);
1010
while(PC_ReadSourceToken(source, &token))
1012
if (token.linescrossed > 0)
1014
PC_UnreadSourceToken(source, &token);
1017
if (token.type == TT_PUNCTUATION && *token.string == '>') break;
1018
strncat(path, token.string, MAX_PATH);
1020
if (*token.string != '>')
1022
SourceWarning(source, "#include missing trailing >");
1026
SourceError(source, "#include without file name between < >");
1029
PC_ConvertPath(path);
1030
script = LoadScriptFile(path);
1034
SourceError(source, "#include without file name");
1040
Com_Memset(&file, 0, sizeof(foundfile_t));
1041
script = LoadScriptFile(path);
1042
if (script) strncpy(script->filename, path, MAX_PATH);
1048
SourceWarning(source, "file %s not found", path);
1051
SourceError(source, "file %s not found", path);
1055
PC_PushScript(source, script);
1057
} //end of the function PC_Directive_include
1058
//============================================================================
1059
// reads a token from the current line, continues reading on the next
1060
// line only if a backslash '\' is encountered.
1064
// Changes Globals: -
1065
//============================================================================
1066
int PC_ReadLine(source_t *source, token_t *token)
1073
if (!PC_ReadSourceToken(source, token)) return qfalse;
1075
if (token->linescrossed > crossline)
1077
PC_UnreadSourceToken(source, token);
1081
} while(!strcmp(token->string, "\\"));
1083
} //end of the function PC_ReadLine
1084
//============================================================================
1088
// Changes Globals: -
1089
//============================================================================
1090
int PC_WhiteSpaceBeforeToken(token_t *token)
1092
return token->endwhitespace_p - token->whitespace_p > 0;
1093
} //end of the function PC_WhiteSpaceBeforeToken
1094
//============================================================================
1098
// Changes Globals: -
1099
//============================================================================
1100
void PC_ClearTokenWhiteSpace(token_t *token)
1102
token->whitespace_p = NULL;
1103
token->endwhitespace_p = NULL;
1104
token->linescrossed = 0;
1105
} //end of the function PC_ClearTokenWhiteSpace
1106
//============================================================================
1110
// Changes Globals: -
1111
//============================================================================
1112
int PC_Directive_undef(source_t *source)
1115
define_t *define, *lastdefine;
1118
if (source->skip > 0) return qtrue;
1120
if (!PC_ReadLine(source, &token))
1122
SourceError(source, "undef without name");
1125
if (token.type != TT_NAME)
1127
PC_UnreadSourceToken(source, &token);
1128
SourceError(source, "expected name, found %s", token.string);
1133
hash = PC_NameHash(token.string);
1134
for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)
1136
if (!strcmp(define->name, token.string))
1138
if (define->flags & DEFINE_FIXED)
1140
SourceWarning(source, "can't undef %s", token.string);
1144
if (lastdefine) lastdefine->hashnext = define->hashnext;
1145
else source->definehash[hash] = define->hashnext;
1146
PC_FreeDefine(define);
1150
lastdefine = define;
1152
#else //DEFINEHASHING
1153
for (lastdefine = NULL, define = source->defines; define; define = define->next)
1155
if (!strcmp(define->name, token.string))
1157
if (define->flags & DEFINE_FIXED)
1159
SourceWarning(source, "can't undef %s", token.string);
1163
if (lastdefine) lastdefine->next = define->next;
1164
else source->defines = define->next;
1165
PC_FreeDefine(define);
1169
lastdefine = define;
1171
#endif //DEFINEHASHING
1173
} //end of the function PC_Directive_undef
1174
//============================================================================
1178
// Changes Globals: -
1179
//============================================================================
1180
int PC_Directive_define(source_t *source)
1182
token_t token, *t, *last;
1185
if (source->skip > 0) return qtrue;
1187
if (!PC_ReadLine(source, &token))
1189
SourceError(source, "#define without name");
1192
if (token.type != TT_NAME)
1194
PC_UnreadSourceToken(source, &token);
1195
SourceError(source, "expected name after #define, found %s", token.string);
1198
//check if the define already exists
1200
define = PC_FindHashedDefine(source->definehash, token.string);
1202
define = PC_FindDefine(source->defines, token.string);
1203
#endif //DEFINEHASHING
1206
if (define->flags & DEFINE_FIXED)
1208
SourceError(source, "can't redefine %s", token.string);
1211
SourceWarning(source, "redefinition of %s", token.string);
1212
//unread the define name before executing the #undef directive
1213
PC_UnreadSourceToken(source, &token);
1214
if (!PC_Directive_undef(source)) return qfalse;
1215
//if the define was not removed (define->flags & DEFINE_FIXED)
1217
define = PC_FindHashedDefine(source->definehash, token.string);
1219
define = PC_FindDefine(source->defines, token.string);
1220
#endif //DEFINEHASHING
1223
define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1);
1224
Com_Memset(define, 0, sizeof(define_t));
1225
define->name = (char *) define + sizeof(define_t);
1226
strcpy(define->name, token.string);
1227
//add the define to the source
1229
PC_AddDefineToHash(define, source->definehash);
1230
#else //DEFINEHASHING
1231
define->next = source->defines;
1232
source->defines = define;
1233
#endif //DEFINEHASHING
1234
//if nothing is defined, just return
1235
if (!PC_ReadLine(source, &token)) return qtrue;
1236
//if it is a define with parameters
1237
if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "("))
1239
//read the define parameters
1241
if (!PC_CheckTokenString(source, ")"))
1245
if (!PC_ReadLine(source, &token))
1247
SourceError(source, "expected define parameter");
1250
//if it isn't a name
1251
if (token.type != TT_NAME)
1253
SourceError(source, "invalid define parameter");
1257
if (PC_FindDefineParm(define, token.string) >= 0)
1259
SourceError(source, "two the same define parameters");
1262
//add the define parm
1263
t = PC_CopyToken(&token);
1264
PC_ClearTokenWhiteSpace(t);
1266
if (last) last->next = t;
1267
else define->parms = t;
1271
if (!PC_ReadLine(source, &token))
1273
SourceError(source, "define parameters not terminated");
1277
if (!strcmp(token.string, ")")) break;
1278
//then it must be a comma
1279
if (strcmp(token.string, ","))
1281
SourceError(source, "define not terminated");
1286
if (!PC_ReadLine(source, &token)) return qtrue;
1288
//read the defined stuff
1292
t = PC_CopyToken(&token);
1293
if (t->type == TT_NAME && !strcmp(t->string, define->name))
1295
SourceError(source, "recursive define (removed recursion)");
1298
PC_ClearTokenWhiteSpace(t);
1300
if (last) last->next = t;
1301
else define->tokens = t;
1303
} while(PC_ReadLine(source, &token));
1307
//check for merge operators at the beginning or end
1308
if (!strcmp(define->tokens->string, "##") ||
1309
!strcmp(last->string, "##"))
1311
SourceError(source, "define with misplaced ##");
1316
} //end of the function PC_Directive_define
1317
//============================================================================
1321
// Changes Globals: -
1322
//============================================================================
1323
define_t *PC_DefineFromString(char *string)
1333
script = LoadScriptMemory(string, strlen(string), "*extern");
1334
//create a new source
1335
Com_Memset(&src, 0, sizeof(source_t));
1336
strncpy(src.filename, "*extern", MAX_PATH);
1337
src.scriptstack = script;
1339
src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
1340
#endif //DEFINEHASHING
1341
//create a define from the source
1342
res = PC_Directive_define(&src);
1343
//free any tokens if left
1344
for (t = src.tokens; t; t = src.tokens)
1346
src.tokens = src.tokens->next;
1349
#ifdef DEFINEHASHING
1351
for (i = 0; i < DEFINEHASHSIZE; i++)
1353
if (src.definehash[i])
1355
def = src.definehash[i];
1361
#endif //DEFINEHASHING
1364
FreeMemory(src.definehash);
1365
#endif //DEFINEHASHING
1368
//if the define was created succesfully
1369
if (res > 0) return def;
1370
//free the define is created
1371
if (src.defines) PC_FreeDefine(def);
1374
} //end of the function PC_DefineFromString
1375
//============================================================================
1379
// Changes Globals: -
1380
//============================================================================
1381
int PC_AddDefine(source_t *source, char *string)
1385
define = PC_DefineFromString(string);
1386
if (!define) return qfalse;
1388
PC_AddDefineToHash(define, source->definehash);
1389
#else //DEFINEHASHING
1390
define->next = source->defines;
1391
source->defines = define;
1392
#endif //DEFINEHASHING
1394
} //end of the function PC_AddDefine
1395
//============================================================================
1396
// add a globals define that will be added to all opened sources
1400
// Changes Globals: -
1401
//============================================================================
1402
int PC_AddGlobalDefine(char *string)
1406
define = PC_DefineFromString(string);
1407
if (!define) return qfalse;
1408
define->next = globaldefines;
1409
globaldefines = define;
1411
} //end of the function PC_AddGlobalDefine
1412
//============================================================================
1413
// remove the given global define
1417
// Changes Globals: -
1418
//============================================================================
1419
int PC_RemoveGlobalDefine(char *name)
1423
define = PC_FindDefine(globaldefines, name);
1426
PC_FreeDefine(define);
1430
} //end of the function PC_RemoveGlobalDefine
1431
//============================================================================
1432
// remove all globals defines
1436
// Changes Globals: -
1437
//============================================================================
1438
void PC_RemoveAllGlobalDefines(void)
1442
for (define = globaldefines; define; define = globaldefines)
1444
globaldefines = globaldefines->next;
1445
PC_FreeDefine(define);
1447
} //end of the function PC_RemoveAllGlobalDefines
1448
//============================================================================
1452
// Changes Globals: -
1453
//============================================================================
1454
define_t *PC_CopyDefine(source_t *source, define_t *define)
1456
define_t *newdefine;
1457
token_t *token, *newtoken, *lasttoken;
1459
newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1);
1460
//copy the define name
1461
newdefine->name = (char *) newdefine + sizeof(define_t);
1462
strcpy(newdefine->name, define->name);
1463
newdefine->flags = define->flags;
1464
newdefine->builtin = define->builtin;
1465
newdefine->numparms = define->numparms;
1466
//the define is not linked
1467
newdefine->next = NULL;
1468
newdefine->hashnext = NULL;
1469
//copy the define tokens
1470
newdefine->tokens = NULL;
1471
for (lasttoken = NULL, token = define->tokens; token; token = token->next)
1473
newtoken = PC_CopyToken(token);
1474
newtoken->next = NULL;
1475
if (lasttoken) lasttoken->next = newtoken;
1476
else newdefine->tokens = newtoken;
1477
lasttoken = newtoken;
1479
//copy the define parameters
1480
newdefine->parms = NULL;
1481
for (lasttoken = NULL, token = define->parms; token; token = token->next)
1483
newtoken = PC_CopyToken(token);
1484
newtoken->next = NULL;
1485
if (lasttoken) lasttoken->next = newtoken;
1486
else newdefine->parms = newtoken;
1487
lasttoken = newtoken;
1490
} //end of the function PC_CopyDefine
1491
//============================================================================
1495
// Changes Globals: -
1496
//============================================================================
1497
void PC_AddGlobalDefinesToSource(source_t *source)
1499
define_t *define, *newdefine;
1501
for (define = globaldefines; define; define = define->next)
1503
newdefine = PC_CopyDefine(source, define);
1505
PC_AddDefineToHash(newdefine, source->definehash);
1506
#else //DEFINEHASHING
1507
newdefine->next = source->defines;
1508
source->defines = newdefine;
1509
#endif //DEFINEHASHING
1511
} //end of the function PC_AddGlobalDefinesToSource
1512
//============================================================================
1516
// Changes Globals: -
1517
//============================================================================
1518
int PC_Directive_if_def(source_t *source, int type)
1524
if (!PC_ReadLine(source, &token))
1526
SourceError(source, "#ifdef without name");
1529
if (token.type != TT_NAME)
1531
PC_UnreadSourceToken(source, &token);
1532
SourceError(source, "expected name after #ifdef, found %s", token.string);
1536
d = PC_FindHashedDefine(source->definehash, token.string);
1538
d = PC_FindDefine(source->defines, token.string);
1539
#endif //DEFINEHASHING
1540
skip = (type == INDENT_IFDEF) == (d == NULL);
1541
PC_PushIndent(source, type, skip);
1543
} //end of the function PC_Directiveif_def
1544
//============================================================================
1548
// Changes Globals: -
1549
//============================================================================
1550
int PC_Directive_ifdef(source_t *source)
1552
return PC_Directive_if_def(source, INDENT_IFDEF);
1553
} //end of the function PC_Directive_ifdef
1554
//============================================================================
1558
// Changes Globals: -
1559
//============================================================================
1560
int PC_Directive_ifndef(source_t *source)
1562
return PC_Directive_if_def(source, INDENT_IFNDEF);
1563
} //end of the function PC_Directive_ifndef
1564
//============================================================================
1568
// Changes Globals: -
1569
//============================================================================
1570
int PC_Directive_else(source_t *source)
1574
PC_PopIndent(source, &type, &skip);
1577
SourceError(source, "misplaced #else");
1580
if (type == INDENT_ELSE)
1582
SourceError(source, "#else after #else");
1585
PC_PushIndent(source, INDENT_ELSE, !skip);
1587
} //end of the function PC_Directive_else
1588
//============================================================================
1592
// Changes Globals: -
1593
//============================================================================
1594
int PC_Directive_endif(source_t *source)
1598
PC_PopIndent(source, &type, &skip);
1601
SourceError(source, "misplaced #endif");
1605
} //end of the function PC_Directive_endif
1606
//============================================================================
1610
// Changes Globals: -
1611
//============================================================================
1612
typedef struct operator_s
1617
struct operator_s *prev, *next;
1620
typedef struct value_s
1622
signed long int intvalue;
1625
struct value_s *prev, *next;
1628
int PC_OperatorPriority(int op)
1632
case P_MUL: return 15;
1633
case P_DIV: return 15;
1634
case P_MOD: return 15;
1635
case P_ADD: return 14;
1636
case P_SUB: return 14;
1638
case P_LOGIC_AND: return 7;
1639
case P_LOGIC_OR: return 6;
1640
case P_LOGIC_GEQ: return 12;
1641
case P_LOGIC_LEQ: return 12;
1642
case P_LOGIC_EQ: return 11;
1643
case P_LOGIC_UNEQ: return 11;
1645
case P_LOGIC_NOT: return 16;
1646
case P_LOGIC_GREATER: return 12;
1647
case P_LOGIC_LESS: return 12;
1649
case P_RSHIFT: return 13;
1650
case P_LSHIFT: return 13;
1652
case P_BIN_AND: return 10;
1653
case P_BIN_OR: return 8;
1654
case P_BIN_XOR: return 9;
1655
case P_BIN_NOT: return 16;
1657
case P_COLON: return 5;
1658
case P_QUESTIONMARK: return 5;
1661
} //end of the function PC_OperatorPriority
1663
//#define AllocValue() GetClearedMemory(sizeof(value_t));
1664
//#define FreeValue(val) FreeMemory(val)
1665
//#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t));
1666
//#define FreeOperator(op) FreeMemory(op);
1668
#define MAX_VALUES 64
1669
#define MAX_OPERATORS 64
1670
#define AllocValue(val) \
1671
if (numvalues >= MAX_VALUES) { \
1672
SourceError(source, "out of value space\n"); \
1677
val = &value_heap[numvalues++];
1678
#define FreeValue(val)
1680
#define AllocOperator(op) \
1681
if (numoperators >= MAX_OPERATORS) { \
1682
SourceError(source, "out of operator space\n"); \
1687
op = &operator_heap[numoperators++];
1688
#define FreeOperator(op)
1690
int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,
1691
double *floatvalue, int integer)
1693
operator_t *o, *firstoperator, *lastoperator;
1694
value_t *v, *firstvalue, *lastvalue, *v1, *v2;
1697
int parentheses = 0;
1699
int lastwasvalue = 0;
1700
int negativevalue = 0;
1701
int questmarkintvalue = 0;
1702
double questmarkfloatvalue = 0;
1703
int gotquestmarkvalue = qfalse;
1704
int lastoperatortype = 0;
1706
operator_t operator_heap[MAX_OPERATORS];
1707
int numoperators = 0;
1708
value_t value_heap[MAX_VALUES];
1711
firstoperator = lastoperator = NULL;
1712
firstvalue = lastvalue = NULL;
1713
if (intvalue) *intvalue = 0;
1714
if (floatvalue) *floatvalue = 0;
1715
for (t = tokens; t; t = t->next)
1721
if (lastwasvalue || negativevalue)
1723
SourceError(source, "syntax error in #if/#elif");
1727
if (strcmp(t->string, "defined"))
1729
SourceError(source, "undefined name %s in #if/#elif", t->string);
1734
if (!strcmp(t->string, "("))
1739
if (!t || t->type != TT_NAME)
1741
SourceError(source, "defined without name in #if/#elif");
1745
//v = (value_t *) GetClearedMemory(sizeof(value_t));
1748
if (PC_FindHashedDefine(source->definehash, t->string))
1750
if (PC_FindDefine(source->defines, t->string))
1751
#endif //DEFINEHASHING
1761
v->parentheses = parentheses;
1763
v->prev = lastvalue;
1764
if (lastvalue) lastvalue->next = v;
1765
else firstvalue = v;
1770
if (!t || strcmp(t->string, ")"))
1772
SourceError(source, "defined without ) in #if/#elif");
1778
// defined() creates a value
1786
SourceError(source, "syntax error in #if/#elif");
1790
//v = (value_t *) GetClearedMemory(sizeof(value_t));
1794
v->intvalue = - (signed int) t->intvalue;
1795
v->floatvalue = - t->floatvalue;
1799
v->intvalue = t->intvalue;
1800
v->floatvalue = t->floatvalue;
1802
v->parentheses = parentheses;
1804
v->prev = lastvalue;
1805
if (lastvalue) lastvalue->next = v;
1806
else firstvalue = v;
1808
//last token was a value
1814
case TT_PUNCTUATION:
1818
SourceError(source, "misplaced minus sign in #if/#elif");
1822
if (t->subtype == P_PARENTHESESOPEN)
1827
else if (t->subtype == P_PARENTHESESCLOSE)
1830
if (parentheses < 0)
1832
SourceError(source, "too many ) in #if/#elsif");
1837
//check for invalid operators on floating point values
1840
if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
1841
t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
1842
t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
1843
t->subtype == P_BIN_XOR)
1845
SourceError(source, "illigal operator %s on floating point operands\n", t->string);
1857
SourceError(source, "! or ~ after value in #if/#elif");
1866
SourceError(source, "++ or -- used in #if/#elif");
1890
case P_LOGIC_GREATER:
1901
case P_QUESTIONMARK:
1905
SourceError(source, "operator %s after operator in #if/#elif", t->string);
1913
SourceError(source, "invalid operator %s in #if/#elif", t->string);
1918
if (!error && !negativevalue)
1920
//o = (operator_t *) GetClearedMemory(sizeof(operator_t));
1922
o->operator = t->subtype;
1923
o->priority = PC_OperatorPriority(t->subtype);
1924
o->parentheses = parentheses;
1926
o->prev = lastoperator;
1927
if (lastoperator) lastoperator->next = o;
1928
else firstoperator = o;
1936
SourceError(source, "unknown %s in #if/#elif", t->string);
1947
SourceError(source, "trailing operator in #if/#elif");
1950
else if (parentheses)
1952
SourceError(source, "too many ( in #if/#elif");
1957
gotquestmarkvalue = qfalse;
1958
questmarkintvalue = 0;
1959
questmarkfloatvalue = 0;
1960
//while there are operators
1961
while(!error && firstoperator)
1964
for (o = firstoperator; o->next; o = o->next)
1966
//if the current operator is nested deeper in parentheses
1967
//than the next operator
1968
if (o->parentheses > o->next->parentheses) break;
1969
//if the current and next operator are nested equally deep in parentheses
1970
if (o->parentheses == o->next->parentheses)
1972
//if the priority of the current operator is equal or higher
1973
//than the priority of the next operator
1974
if (o->priority >= o->next->priority) break;
1976
//if the arity of the operator isn't equal to 1
1977
if (o->operator != P_LOGIC_NOT
1978
&& o->operator != P_BIN_NOT) v = v->next;
1979
//if there's no value or no next value
1982
SourceError(source, "mising values in #if/#elif");
1993
Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue);
1994
if (v2) Log_Write("value2 = %d", v2->intvalue);
1998
Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue);
1999
if (v2) Log_Write("value2 = %f", v2->floatvalue);
2004
case P_LOGIC_NOT: v1->intvalue = !v1->intvalue;
2005
v1->floatvalue = !v1->floatvalue; break;
2006
case P_BIN_NOT: v1->intvalue = ~v1->intvalue;
2008
case P_MUL: v1->intvalue *= v2->intvalue;
2009
v1->floatvalue *= v2->floatvalue; break;
2010
case P_DIV: if (!v2->intvalue || !v2->floatvalue)
2012
SourceError(source, "divide by zero in #if/#elif\n");
2016
v1->intvalue /= v2->intvalue;
2017
v1->floatvalue /= v2->floatvalue; break;
2018
case P_MOD: if (!v2->intvalue)
2020
SourceError(source, "divide by zero in #if/#elif\n");
2024
v1->intvalue %= v2->intvalue; break;
2025
case P_ADD: v1->intvalue += v2->intvalue;
2026
v1->floatvalue += v2->floatvalue; break;
2027
case P_SUB: v1->intvalue -= v2->intvalue;
2028
v1->floatvalue -= v2->floatvalue; break;
2029
case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue;
2030
v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
2031
case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue;
2032
v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
2033
case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue;
2034
v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
2035
case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue;
2036
v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
2037
case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue;
2038
v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
2039
case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue;
2040
v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
2041
case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue;
2042
v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
2043
case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue;
2044
v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
2045
case P_RSHIFT: v1->intvalue >>= v2->intvalue;
2047
case P_LSHIFT: v1->intvalue <<= v2->intvalue;
2049
case P_BIN_AND: v1->intvalue &= v2->intvalue;
2051
case P_BIN_OR: v1->intvalue |= v2->intvalue;
2053
case P_BIN_XOR: v1->intvalue ^= v2->intvalue;
2057
if (!gotquestmarkvalue)
2059
SourceError(source, ": without ? in #if/#elif");
2065
if (!questmarkintvalue) v1->intvalue = v2->intvalue;
2069
if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;
2071
gotquestmarkvalue = qfalse;
2074
case P_QUESTIONMARK:
2076
if (gotquestmarkvalue)
2078
SourceError(source, "? after ? in #if/#elif");
2082
questmarkintvalue = v1->intvalue;
2083
questmarkfloatvalue = v1->floatvalue;
2084
gotquestmarkvalue = qtrue;
2089
if (integer) Log_Write("result value = %d", v1->intvalue);
2090
else Log_Write("result value = %f", v1->floatvalue);
2093
lastoperatortype = o->operator;
2094
//if not an operator with arity 1
2095
if (o->operator != P_LOGIC_NOT
2096
&& o->operator != P_BIN_NOT)
2098
//remove the second value if not question mark operator
2099
if (o->operator != P_QUESTIONMARK) v = v->next;
2101
if (v->prev) v->prev->next = v->next;
2102
else firstvalue = v->next;
2103
if (v->next) v->next->prev = v->prev;
2104
else lastvalue = v->prev;
2108
//remove the operator
2109
if (o->prev) o->prev->next = o->next;
2110
else firstoperator = o->next;
2111
if (o->next) o->next->prev = o->prev;
2112
else lastoperator = o->prev;
2118
if (intvalue) *intvalue = firstvalue->intvalue;
2119
if (floatvalue) *floatvalue = firstvalue->floatvalue;
2121
for (o = firstoperator; o; o = lastoperator)
2123
lastoperator = o->next;
2127
for (v = firstvalue; v; v = lastvalue)
2129
lastvalue = v->next;
2133
if (!error) return qtrue;
2134
if (intvalue) *intvalue = 0;
2135
if (floatvalue) *floatvalue = 0;
2137
} //end of the function PC_EvaluateTokens
2138
//============================================================================
2142
// Changes Globals: -
2143
//============================================================================
2144
int PC_Evaluate(source_t *source, signed long int *intvalue,
2145
double *floatvalue, int integer)
2147
token_t token, *firsttoken, *lasttoken;
2148
token_t *t, *nexttoken;
2150
int defined = qfalse;
2152
if (intvalue) *intvalue = 0;
2153
if (floatvalue) *floatvalue = 0;
2155
if (!PC_ReadLine(source, &token))
2157
SourceError(source, "no value after #if/#elif");
2164
//if the token is a name
2165
if (token.type == TT_NAME)
2170
t = PC_CopyToken(&token);
2172
if (lasttoken) lasttoken->next = t;
2173
else firsttoken = t;
2176
else if (!strcmp(token.string, "defined"))
2179
t = PC_CopyToken(&token);
2181
if (lasttoken) lasttoken->next = t;
2182
else firsttoken = t;
2187
//then it must be a define
2189
define = PC_FindHashedDefine(source->definehash, token.string);
2191
define = PC_FindDefine(source->defines, token.string);
2192
#endif //DEFINEHASHING
2195
SourceError(source, "can't evaluate %s, not defined", token.string);
2198
if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
2201
//if the token is a number or a punctuation
2202
else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
2204
t = PC_CopyToken(&token);
2206
if (lasttoken) lasttoken->next = t;
2207
else firsttoken = t;
2210
else //can't evaluate the token
2212
SourceError(source, "can't evaluate %s", token.string);
2215
} while(PC_ReadLine(source, &token));
2217
if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
2222
for (t = firsttoken; t; t = nexttoken)
2225
Log_Write(" %s", t->string);
2227
nexttoken = t->next;
2231
if (integer) Log_Write("eval result: %d", *intvalue);
2232
else Log_Write("eval result: %f", *floatvalue);
2236
} //end of the function PC_Evaluate
2237
//============================================================================
2241
// Changes Globals: -
2242
//============================================================================
2243
int PC_DollarEvaluate(source_t *source, signed long int *intvalue,
2244
double *floatvalue, int integer)
2246
int indent, defined = qfalse;
2247
token_t token, *firsttoken, *lasttoken;
2248
token_t *t, *nexttoken;
2251
if (intvalue) *intvalue = 0;
2252
if (floatvalue) *floatvalue = 0;
2254
if (!PC_ReadSourceToken(source, &token))
2256
SourceError(source, "no leading ( after $evalint/$evalfloat");
2259
if (!PC_ReadSourceToken(source, &token))
2261
SourceError(source, "nothing to evaluate");
2269
//if the token is a name
2270
if (token.type == TT_NAME)
2275
t = PC_CopyToken(&token);
2277
if (lasttoken) lasttoken->next = t;
2278
else firsttoken = t;
2281
else if (!strcmp(token.string, "defined"))
2284
t = PC_CopyToken(&token);
2286
if (lasttoken) lasttoken->next = t;
2287
else firsttoken = t;
2292
//then it must be a define
2294
define = PC_FindHashedDefine(source->definehash, token.string);
2296
define = PC_FindDefine(source->defines, token.string);
2297
#endif //DEFINEHASHING
2300
SourceError(source, "can't evaluate %s, not defined", token.string);
2303
if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
2306
//if the token is a number or a punctuation
2307
else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
2309
if (*token.string == '(') indent++;
2310
else if (*token.string == ')') indent--;
2311
if (indent <= 0) break;
2312
t = PC_CopyToken(&token);
2314
if (lasttoken) lasttoken->next = t;
2315
else firsttoken = t;
2318
else //can't evaluate the token
2320
SourceError(source, "can't evaluate %s", token.string);
2323
} while(PC_ReadSourceToken(source, &token));
2325
if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
2328
Log_Write("$eval:");
2330
for (t = firsttoken; t; t = nexttoken)
2333
Log_Write(" %s", t->string);
2335
nexttoken = t->next;
2339
if (integer) Log_Write("$eval result: %d", *intvalue);
2340
else Log_Write("$eval result: %f", *floatvalue);
2344
} //end of the function PC_DollarEvaluate
2345
//============================================================================
2349
// Changes Globals: -
2350
//============================================================================
2351
int PC_Directive_elif(source_t *source)
2353
signed long int value;
2356
PC_PopIndent(source, &type, &skip);
2357
if (!type || type == INDENT_ELSE)
2359
SourceError(source, "misplaced #elif");
2362
if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
2363
skip = (value == 0);
2364
PC_PushIndent(source, INDENT_ELIF, skip);
2366
} //end of the function PC_Directive_elif
2367
//============================================================================
2371
// Changes Globals: -
2372
//============================================================================
2373
int PC_Directive_if(source_t *source)
2375
signed long int value;
2378
if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
2379
skip = (value == 0);
2380
PC_PushIndent(source, INDENT_IF, skip);
2382
} //end of the function PC_Directive
2383
//============================================================================
2387
// Changes Globals: -
2388
//============================================================================
2389
int PC_Directive_line(source_t *source)
2391
SourceError(source, "#line directive not supported");
2393
} //end of the function PC_Directive_line
2394
//============================================================================
2398
// Changes Globals: -
2399
//============================================================================
2400
int PC_Directive_error(source_t *source)
2404
strcpy(token.string, "");
2405
PC_ReadSourceToken(source, &token);
2406
SourceError(source, "#error directive: %s", token.string);
2408
} //end of the function PC_Directive_error
2409
//============================================================================
2413
// Changes Globals: -
2414
//============================================================================
2415
int PC_Directive_pragma(source_t *source)
2419
SourceWarning(source, "#pragma directive not supported");
2420
while(PC_ReadLine(source, &token)) ;
2422
} //end of the function PC_Directive_pragma
2423
//============================================================================
2427
// Changes Globals: -
2428
//============================================================================
2429
void UnreadSignToken(source_t *source)
2433
token.line = source->scriptstack->line;
2434
token.whitespace_p = source->scriptstack->script_p;
2435
token.endwhitespace_p = source->scriptstack->script_p;
2436
token.linescrossed = 0;
2437
strcpy(token.string, "-");
2438
token.type = TT_PUNCTUATION;
2439
token.subtype = P_SUB;
2440
PC_UnreadSourceToken(source, &token);
2441
} //end of the function UnreadSignToken
2442
//============================================================================
2446
// Changes Globals: -
2447
//============================================================================
2448
int PC_Directive_eval(source_t *source)
2450
signed long int value;
2453
if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
2455
token.line = source->scriptstack->line;
2456
token.whitespace_p = source->scriptstack->script_p;
2457
token.endwhitespace_p = source->scriptstack->script_p;
2458
token.linescrossed = 0;
2459
sprintf(token.string, "%d", abs(value));
2460
token.type = TT_NUMBER;
2461
token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
2462
PC_UnreadSourceToken(source, &token);
2463
if (value < 0) UnreadSignToken(source);
2465
} //end of the function PC_Directive_eval
2466
//============================================================================
2470
// Changes Globals: -
2471
//============================================================================
2472
int PC_Directive_evalfloat(source_t *source)
2477
if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse;
2478
token.line = source->scriptstack->line;
2479
token.whitespace_p = source->scriptstack->script_p;
2480
token.endwhitespace_p = source->scriptstack->script_p;
2481
token.linescrossed = 0;
2482
sprintf(token.string, "%1.2f", fabs(value));
2483
token.type = TT_NUMBER;
2484
token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
2485
PC_UnreadSourceToken(source, &token);
2486
if (value < 0) UnreadSignToken(source);
2488
} //end of the function PC_Directive_evalfloat
2489
//============================================================================
2493
// Changes Globals: -
2494
//============================================================================
2495
directive_t directives[20] =
2497
{"if", PC_Directive_if},
2498
{"ifdef", PC_Directive_ifdef},
2499
{"ifndef", PC_Directive_ifndef},
2500
{"elif", PC_Directive_elif},
2501
{"else", PC_Directive_else},
2502
{"endif", PC_Directive_endif},
2503
{"include", PC_Directive_include},
2504
{"define", PC_Directive_define},
2505
{"undef", PC_Directive_undef},
2506
{"line", PC_Directive_line},
2507
{"error", PC_Directive_error},
2508
{"pragma", PC_Directive_pragma},
2509
{"eval", PC_Directive_eval},
2510
{"evalfloat", PC_Directive_evalfloat},
2514
int PC_ReadDirective(source_t *source)
2519
//read the directive name
2520
if (!PC_ReadSourceToken(source, &token))
2522
SourceError(source, "found # without name");
2525
//directive name must be on the same line
2526
if (token.linescrossed > 0)
2528
PC_UnreadSourceToken(source, &token);
2529
SourceError(source, "found # at end of line");
2533
if (token.type == TT_NAME)
2535
//find the precompiler directive
2536
for (i = 0; directives[i].name; i++)
2538
if (!strcmp(directives[i].name, token.string))
2540
return directives[i].func(source);
2544
SourceError(source, "unknown precompiler directive %s", token.string);
2546
} //end of the function PC_ReadDirective
2547
//============================================================================
2551
// Changes Globals: -
2552
//============================================================================
2553
int PC_DollarDirective_evalint(source_t *source)
2555
signed long int value;
2558
if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse;
2560
token.line = source->scriptstack->line;
2561
token.whitespace_p = source->scriptstack->script_p;
2562
token.endwhitespace_p = source->scriptstack->script_p;
2563
token.linescrossed = 0;
2564
sprintf(token.string, "%d", abs(value));
2565
token.type = TT_NUMBER;
2566
token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
2568
token.intvalue = value;
2569
token.floatvalue = value;
2570
#endif //NUMBERVALUE
2571
PC_UnreadSourceToken(source, &token);
2572
if (value < 0) UnreadSignToken(source);
2574
} //end of the function PC_DollarDirective_evalint
2575
//============================================================================
2579
// Changes Globals: -
2580
//============================================================================
2581
int PC_DollarDirective_evalfloat(source_t *source)
2586
if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse;
2587
token.line = source->scriptstack->line;
2588
token.whitespace_p = source->scriptstack->script_p;
2589
token.endwhitespace_p = source->scriptstack->script_p;
2590
token.linescrossed = 0;
2591
sprintf(token.string, "%1.2f", fabs(value));
2592
token.type = TT_NUMBER;
2593
token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
2595
token.intvalue = (unsigned long) value;
2596
token.floatvalue = value;
2597
#endif //NUMBERVALUE
2598
PC_UnreadSourceToken(source, &token);
2599
if (value < 0) UnreadSignToken(source);
2601
} //end of the function PC_DollarDirective_evalfloat
2602
//============================================================================
2606
// Changes Globals: -
2607
//============================================================================
2608
directive_t dollardirectives[20] =
2610
{"evalint", PC_DollarDirective_evalint},
2611
{"evalfloat", PC_DollarDirective_evalfloat},
2615
int PC_ReadDollarDirective(source_t *source)
2620
//read the directive name
2621
if (!PC_ReadSourceToken(source, &token))
2623
SourceError(source, "found $ without name");
2626
//directive name must be on the same line
2627
if (token.linescrossed > 0)
2629
PC_UnreadSourceToken(source, &token);
2630
SourceError(source, "found $ at end of line");
2634
if (token.type == TT_NAME)
2636
//find the precompiler directive
2637
for (i = 0; dollardirectives[i].name; i++)
2639
if (!strcmp(dollardirectives[i].name, token.string))
2641
return dollardirectives[i].func(source);
2645
PC_UnreadSourceToken(source, &token);
2646
SourceError(source, "unknown precompiler directive %s", token.string);
2648
} //end of the function PC_ReadDirective
2651
//============================================================================
2655
// Changes Globals: -
2656
//============================================================================
2657
int BuiltinFunction(source_t *source)
2661
if (!PC_ReadSourceToken(source, &token)) return qfalse;
2662
if (token.type == TT_NUMBER)
2664
PC_UnreadSourceToken(source, &token);
2669
PC_UnreadSourceToken(source, &token);
2672
} //end of the function BuiltinFunction
2673
//============================================================================
2677
// Changes Globals: -
2678
//============================================================================
2679
int QuakeCMacro(source_t *source)
2684
if (!PC_ReadSourceToken(source, &token)) return qtrue;
2685
if (token.type != TT_NAME)
2687
PC_UnreadSourceToken(source, &token);
2690
//find the precompiler directive
2691
for (i = 0; dollardirectives[i].name; i++)
2693
if (!strcmp(dollardirectives[i].name, token.string))
2695
PC_UnreadSourceToken(source, &token);
2699
PC_UnreadSourceToken(source, &token);
2701
} //end of the function QuakeCMacro
2703
//============================================================================
2707
// Changes Globals: -
2708
//============================================================================
2709
int PC_ReadToken(source_t *source, token_t *token)
2715
if (!PC_ReadSourceToken(source, token)) return qfalse;
2716
//check for precompiler directives
2717
if (token->type == TT_PUNCTUATION && *token->string == '#')
2720
if (!BuiltinFunction(source))
2723
//read the precompiler directive
2724
if (!PC_ReadDirective(source)) return qfalse;
2728
if (token->type == TT_PUNCTUATION && *token->string == '$')
2731
if (!QuakeCMacro(source))
2734
//read the precompiler directive
2735
if (!PC_ReadDollarDirective(source)) return qfalse;
2739
// recursively concatenate strings that are behind each other still resolving defines
2740
if (token->type == TT_STRING)
2743
if (PC_ReadToken(source, &newtoken))
2745
if (newtoken.type == TT_STRING)
2747
token->string[strlen(token->string)-1] = '\0';
2748
if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN)
2750
SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN);
2753
strcat(token->string, newtoken.string+1);
2757
PC_UnreadToken(source, &newtoken);
2761
//if skipping source because of conditional compilation
2762
if (source->skip) continue;
2763
//if the token is a name
2764
if (token->type == TT_NAME)
2766
//check if the name is a define macro
2768
define = PC_FindHashedDefine(source->definehash, token->string);
2770
define = PC_FindDefine(source->defines, token->string);
2771
#endif //DEFINEHASHING
2772
//if it is a define macro
2775
//expand the defined macro
2776
if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse;
2780
//copy token for unreading
2781
Com_Memcpy(&source->token, token, sizeof(token_t));
2785
} //end of the function PC_ReadToken
2786
//============================================================================
2790
// Changes Globals: -
2791
//============================================================================
2792
int PC_ExpectTokenString(source_t *source, char *string)
2796
if (!PC_ReadToken(source, &token))
2798
SourceError(source, "couldn't find expected %s", string);
2802
if (strcmp(token.string, string))
2804
SourceError(source, "expected %s, found %s", string, token.string);
2808
} //end of the function PC_ExpectTokenString
2809
//============================================================================
2813
// Changes Globals: -
2814
//============================================================================
2815
int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token)
2817
char str[MAX_TOKEN];
2819
if (!PC_ReadToken(source, token))
2821
SourceError(source, "couldn't read expected token");
2825
if (token->type != type)
2828
if (type == TT_STRING) strcpy(str, "string");
2829
if (type == TT_LITERAL) strcpy(str, "literal");
2830
if (type == TT_NUMBER) strcpy(str, "number");
2831
if (type == TT_NAME) strcpy(str, "name");
2832
if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
2833
SourceError(source, "expected a %s, found %s", str, token->string);
2836
if (token->type == TT_NUMBER)
2838
if ((token->subtype & subtype) != subtype)
2840
if (subtype & TT_DECIMAL) strcpy(str, "decimal");
2841
if (subtype & TT_HEX) strcpy(str, "hex");
2842
if (subtype & TT_OCTAL) strcpy(str, "octal");
2843
if (subtype & TT_BINARY) strcpy(str, "binary");
2844
if (subtype & TT_LONG) strcat(str, " long");
2845
if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
2846
if (subtype & TT_FLOAT) strcat(str, " float");
2847
if (subtype & TT_INTEGER) strcat(str, " integer");
2848
SourceError(source, "expected %s, found %s", str, token->string);
2852
else if (token->type == TT_PUNCTUATION)
2854
if (token->subtype != subtype)
2856
SourceError(source, "found %s", token->string);
2861
} //end of the function PC_ExpectTokenType
2862
//============================================================================
2866
// Changes Globals: -
2867
//============================================================================
2868
int PC_ExpectAnyToken(source_t *source, token_t *token)
2870
if (!PC_ReadToken(source, token))
2872
SourceError(source, "couldn't read expected token");
2879
} //end of the function PC_ExpectAnyToken
2880
//============================================================================
2884
// Changes Globals: -
2885
//============================================================================
2886
int PC_CheckTokenString(source_t *source, char *string)
2890
if (!PC_ReadToken(source, &tok)) return qfalse;
2891
//if the token is available
2892
if (!strcmp(tok.string, string)) return qtrue;
2894
PC_UnreadSourceToken(source, &tok);
2896
} //end of the function PC_CheckTokenString
2897
//============================================================================
2901
// Changes Globals: -
2902
//============================================================================
2903
int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token)
2907
if (!PC_ReadToken(source, &tok)) return qfalse;
2908
//if the type matches
2909
if (tok.type == type &&
2910
(tok.subtype & subtype) == subtype)
2912
Com_Memcpy(token, &tok, sizeof(token_t));
2916
PC_UnreadSourceToken(source, &tok);
2918
} //end of the function PC_CheckTokenType
2919
//============================================================================
2923
// Changes Globals: -
2924
//============================================================================
2925
int PC_SkipUntilString(source_t *source, char *string)
2929
while(PC_ReadToken(source, &token))
2931
if (!strcmp(token.string, string)) return qtrue;
2934
} //end of the function PC_SkipUntilString
2935
//============================================================================
2939
// Changes Globals: -
2940
//============================================================================
2941
void PC_UnreadLastToken(source_t *source)
2943
PC_UnreadSourceToken(source, &source->token);
2944
} //end of the function PC_UnreadLastToken
2945
//============================================================================
2949
// Changes Globals: -
2950
//============================================================================
2951
void PC_UnreadToken(source_t *source, token_t *token)
2953
PC_UnreadSourceToken(source, token);
2954
} //end of the function PC_UnreadToken
2955
//============================================================================
2959
// Changes Globals: -
2960
//============================================================================
2961
void PC_SetIncludePath(source_t *source, char *path)
2963
strncpy(source->includepath, path, MAX_PATH);
2964
//add trailing path seperator
2965
if (source->includepath[strlen(source->includepath)-1] != '\\' &&
2966
source->includepath[strlen(source->includepath)-1] != '/')
2968
strcat(source->includepath, PATHSEPERATOR_STR);
2970
} //end of the function PC_SetIncludePath
2971
//============================================================================
2975
// Changes Globals: -
2976
//============================================================================
2977
void PC_SetPunctuations(source_t *source, punctuation_t *p)
2979
source->punctuations = p;
2980
} //end of the function PC_SetPunctuations
2981
//============================================================================
2985
// Changes Globals: -
2986
//============================================================================
2987
source_t *LoadSourceFile(const char *filename)
2994
script = LoadScriptFile(filename);
2995
if (!script) return NULL;
2997
script->next = NULL;
2999
source = (source_t *) GetMemory(sizeof(source_t));
3000
Com_Memset(source, 0, sizeof(source_t));
3002
strncpy(source->filename, filename, MAX_PATH);
3003
source->scriptstack = script;
3004
source->tokens = NULL;
3005
source->defines = NULL;
3006
source->indentstack = NULL;
3010
source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
3011
#endif //DEFINEHASHING
3012
PC_AddGlobalDefinesToSource(source);
3014
} //end of the function LoadSourceFile
3015
//============================================================================
3019
// Changes Globals: -
3020
//============================================================================
3021
source_t *LoadSourceMemory(char *ptr, int length, char *name)
3028
script = LoadScriptMemory(ptr, length, name);
3029
if (!script) return NULL;
3030
script->next = NULL;
3032
source = (source_t *) GetMemory(sizeof(source_t));
3033
Com_Memset(source, 0, sizeof(source_t));
3035
strncpy(source->filename, name, MAX_PATH);
3036
source->scriptstack = script;
3037
source->tokens = NULL;
3038
source->defines = NULL;
3039
source->indentstack = NULL;
3043
source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
3044
#endif //DEFINEHASHING
3045
PC_AddGlobalDefinesToSource(source);
3047
} //end of the function LoadSourceMemory
3048
//============================================================================
3052
// Changes Globals: -
3053
//============================================================================
3054
void FreeSource(source_t *source)
3062
//PC_PrintDefineHashTable(source->definehash);
3063
//free all the scripts
3064
while(source->scriptstack)
3066
script = source->scriptstack;
3067
source->scriptstack = source->scriptstack->next;
3070
//free all the tokens
3071
while(source->tokens)
3073
token = source->tokens;
3074
source->tokens = source->tokens->next;
3075
PC_FreeToken(token);
3078
for (i = 0; i < DEFINEHASHSIZE; i++)
3080
while(source->definehash[i])
3082
define = source->definehash[i];
3083
source->definehash[i] = source->definehash[i]->hashnext;
3084
PC_FreeDefine(define);
3087
#else //DEFINEHASHING
3089
while(source->defines)
3091
define = source->defines;
3092
source->defines = source->defines->next;
3093
PC_FreeDefine(define);
3095
#endif //DEFINEHASHING
3097
while(source->indentstack)
3099
indent = source->indentstack;
3100
source->indentstack = source->indentstack->next;
3105
if (source->definehash) FreeMemory(source->definehash);
3106
#endif //DEFINEHASHING
3107
//free the source itself
3109
} //end of the function FreeSource
3110
//============================================================================
3114
// Changes Globals: -
3115
//============================================================================
3117
#define MAX_SOURCEFILES 64
3119
source_t *sourceFiles[MAX_SOURCEFILES];
3121
int PC_LoadSourceHandle(const char *filename)
3126
for (i = 1; i < MAX_SOURCEFILES; i++)
3128
if (!sourceFiles[i])
3131
if (i >= MAX_SOURCEFILES)
3133
PS_SetBaseFolder("");
3134
source = LoadSourceFile(filename);
3137
sourceFiles[i] = source;
3139
} //end of the function PC_LoadSourceHandle
3140
//============================================================================
3144
// Changes Globals: -
3145
//============================================================================
3146
int PC_FreeSourceHandle(int handle)
3148
if (handle < 1 || handle >= MAX_SOURCEFILES)
3150
if (!sourceFiles[handle])
3153
FreeSource(sourceFiles[handle]);
3154
sourceFiles[handle] = NULL;
3156
} //end of the function PC_FreeSourceHandle
3157
//============================================================================
3161
// Changes Globals: -
3162
//============================================================================
3163
int PC_ReadTokenHandle(int handle, pc_token_t *pc_token)
3168
if (handle < 1 || handle >= MAX_SOURCEFILES)
3170
if (!sourceFiles[handle])
3173
ret = PC_ReadToken(sourceFiles[handle], &token);
3174
strcpy(pc_token->string, token.string);
3175
pc_token->type = token.type;
3176
pc_token->subtype = token.subtype;
3177
pc_token->intvalue = token.intvalue;
3178
pc_token->floatvalue = token.floatvalue;
3179
if (pc_token->type == TT_STRING)
3180
StripDoubleQuotes(pc_token->string);
3182
} //end of the function PC_ReadTokenHandle
3183
//============================================================================
3187
// Changes Globals: -
3188
//============================================================================
3189
int PC_SourceFileAndLine(int handle, char *filename, int *line)
3191
if (handle < 1 || handle >= MAX_SOURCEFILES)
3193
if (!sourceFiles[handle])
3196
strcpy(filename, sourceFiles[handle]->filename);
3197
if (sourceFiles[handle]->scriptstack)
3198
*line = sourceFiles[handle]->scriptstack->line;
3202
} //end of the function PC_SourceFileAndLine
3203
//============================================================================
3207
// Changes Globals: -
3208
//============================================================================
3209
void PC_SetBaseFolder(char *path)
3211
PS_SetBaseFolder(path);
3212
} //end of the function PC_SetBaseFolder
3213
//============================================================================
3217
// Changes Globals: -
3218
//============================================================================
3219
void PC_CheckOpenSourceHandles(void)
3223
for (i = 1; i < MAX_SOURCEFILES; i++)
3228
botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename);
3232
} //end of the function PC_CheckOpenSourceHandles