00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifdef SCREWUP
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <limits.h>
00045 #include <string.h>
00046 #include <stdarg.h>
00047 #include <time.h>
00048 #include "l_memory.h"
00049 #include "l_script.h"
00050 #include "l_precomp.h"
00051
00052 typedef enum {qfalse, qtrue} qboolean;
00053 #endif //SCREWUP
00054
00055 #ifdef BOTLIB
00056 #include "../game/q_shared.h"
00057 #include "../game/botlib.h"
00058 #include "be_interface.h"
00059 #include "l_memory.h"
00060 #include "l_script.h"
00061 #include "l_precomp.h"
00062 #include "l_log.h"
00063 #endif //BOTLIB
00064
00065 #ifdef MEQCC
00066 #include "qcc.h"
00067 #include "time.h"
00068 #include "math.h"
00069 #include "l_memory.h"
00070 #include "l_script.h"
00071 #include "l_precomp.h"
00072 #include "l_log.h"
00073
00074 #define qtrue true
00075 #define qfalse false
00076 #endif //MEQCC
00077
00078 #ifdef BSPC
00079
00080 #include "../bspc/qbsp.h"
00081 #include "../bspc/l_log.h"
00082 #include "../bspc/l_mem.h"
00083 #include "l_precomp.h"
00084
00085 #define qtrue true
00086 #define qfalse false
00087 #define Q_stricmp stricmp
00088
00089 #endif //BSPC
00090
00091 #if defined(QUAKE) && !defined(BSPC)
00092 #include "l_utils.h"
00093 #endif //QUAKE
00094
00095
00096
00097 #define MAX_DEFINEPARMS 128
00098
00099 #define DEFINEHASHING 1
00100
00101
00102 typedef struct directive_s
00103 {
00104 char *name;
00105 int (*func)(source_t *source);
00106 } directive_t;
00107
00108 #define DEFINEHASHSIZE 1024
00109
00110 #define TOKEN_HEAP_SIZE 4096
00111
00112 int numtokens;
00113
00114
00115
00116
00117
00118
00119
00120 define_t *globaldefines;
00121
00122
00123
00124
00125
00126
00127
00128 void QDECL SourceError(source_t *source, char *str, ...)
00129 {
00130 char text[1024];
00131 va_list ap;
00132
00133 va_start(ap, str);
00134 vsprintf(text, str, ap);
00135 va_end(ap);
00136 #ifdef BOTLIB
00137 botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00138 #endif //BOTLIB
00139 #ifdef MEQCC
00140 printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00141 #endif //MEQCC
00142 #ifdef BSPC
00143 Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00144 #endif //BSPC
00145 }
00146
00147
00148
00149
00150
00151
00152 void QDECL SourceWarning(source_t *source, char *str, ...)
00153 {
00154 char text[1024];
00155 va_list ap;
00156
00157 va_start(ap, str);
00158 vsprintf(text, str, ap);
00159 va_end(ap);
00160 #ifdef BOTLIB
00161 botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00162 #endif //BOTLIB
00163 #ifdef MEQCC
00164 printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00165 #endif //MEQCC
00166 #ifdef BSPC
00167 Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00168 #endif //BSPC
00169 }
00170
00171
00172
00173
00174
00175
00176 void PC_PushIndent(source_t *source, int type, int skip)
00177 {
00178 indent_t *indent;
00179
00180 indent = (indent_t *) GetMemory(sizeof(indent_t));
00181 indent->type = type;
00182 indent->script = source->scriptstack;
00183 indent->skip = (skip != 0);
00184 source->skip += indent->skip;
00185 indent->next = source->indentstack;
00186 source->indentstack = indent;
00187 }
00188
00189
00190
00191
00192
00193
00194 void PC_PopIndent(source_t *source, int *type, int *skip)
00195 {
00196 indent_t *indent;
00197
00198 *type = 0;
00199 *skip = 0;
00200
00201 indent = source->indentstack;
00202 if (!indent) return;
00203
00204
00205 if (source->indentstack->script != source->scriptstack) return;
00206
00207 *type = indent->type;
00208 *skip = indent->skip;
00209 source->indentstack = source->indentstack->next;
00210 source->skip -= indent->skip;
00211 FreeMemory(indent);
00212 }
00213
00214
00215
00216
00217
00218
00219 void PC_PushScript(source_t *source, script_t *script)
00220 {
00221 script_t *s;
00222
00223 for (s = source->scriptstack; s; s = s->next)
00224 {
00225 if (!Q_stricmp(s->filename, script->filename))
00226 {
00227 SourceError(source, "%s recursively included", script->filename);
00228 return;
00229 }
00230 }
00231
00232 script->next = source->scriptstack;
00233 source->scriptstack = script;
00234 }
00235
00236
00237
00238
00239
00240
00241 void PC_InitTokenHeap(void)
00242 {
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 }
00256
00257
00258
00259
00260
00261
00262 token_t *PC_CopyToken(token_t *token)
00263 {
00264 token_t *t;
00265
00266
00267 t = (token_t *) GetMemory(sizeof(token_t));
00268
00269 if (!t)
00270 {
00271 #ifdef BSPC
00272 Error("out of token space\n");
00273 #else
00274 Com_Error(ERR_FATAL, "out of token space\n");
00275 #endif
00276 return NULL;
00277 }
00278
00279 Com_Memcpy(t, token, sizeof(token_t));
00280 t->next = NULL;
00281 numtokens++;
00282 return t;
00283 }
00284
00285
00286
00287
00288
00289
00290 void PC_FreeToken(token_t *token)
00291 {
00292
00293 FreeMemory(token);
00294
00295
00296 numtokens--;
00297 }
00298
00299
00300
00301
00302
00303
00304 int PC_ReadSourceToken(source_t *source, token_t *token)
00305 {
00306 token_t *t;
00307 script_t *script;
00308 int type, skip;
00309
00310
00311 while(!source->tokens)
00312 {
00313
00314 if (PS_ReadToken(source->scriptstack, token)) return qtrue;
00315
00316 if (EndOfScript(source->scriptstack))
00317 {
00318
00319 while(source->indentstack &&
00320 source->indentstack->script == source->scriptstack)
00321 {
00322 SourceWarning(source, "missing #endif");
00323 PC_PopIndent(source, &type, &skip);
00324 }
00325 }
00326
00327 if (!source->scriptstack->next) return qfalse;
00328
00329 script = source->scriptstack;
00330 source->scriptstack = source->scriptstack->next;
00331 FreeScript(script);
00332 }
00333
00334 Com_Memcpy(token, source->tokens, sizeof(token_t));
00335
00336 t = source->tokens;
00337 source->tokens = source->tokens->next;
00338 PC_FreeToken(t);
00339 return qtrue;
00340 }
00341
00342
00343
00344
00345
00346
00347 int PC_UnreadSourceToken(source_t *source, token_t *token)
00348 {
00349 token_t *t;
00350
00351 t = PC_CopyToken(token);
00352 t->next = source->tokens;
00353 source->tokens = t;
00354 return qtrue;
00355 }
00356
00357
00358
00359
00360
00361
00362 int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)
00363 {
00364 token_t token, *t, *last;
00365 int i, done, lastcomma, numparms, indent;
00366
00367 if (!PC_ReadSourceToken(source, &token))
00368 {
00369 SourceError(source, "define %s missing parms", define->name);
00370 return qfalse;
00371 }
00372
00373 if (define->numparms > maxparms)
00374 {
00375 SourceError(source, "define with more than %d parameters", maxparms);
00376 return qfalse;
00377 }
00378
00379 for (i = 0; i < define->numparms; i++) parms[i] = NULL;
00380
00381 if (strcmp(token.string, "("))
00382 {
00383 PC_UnreadSourceToken(source, &token);
00384 SourceError(source, "define %s missing parms", define->name);
00385 return qfalse;
00386 }
00387
00388 for (done = 0, numparms = 0, indent = 0; !done;)
00389 {
00390 if (numparms >= maxparms)
00391 {
00392 SourceError(source, "define %s with too many parms", define->name);
00393 return qfalse;
00394 }
00395 if (numparms >= define->numparms)
00396 {
00397 SourceWarning(source, "define %s has too many parms", define->name);
00398 return qfalse;
00399 }
00400 parms[numparms] = NULL;
00401 lastcomma = 1;
00402 last = NULL;
00403 while(!done)
00404 {
00405
00406 if (!PC_ReadSourceToken(source, &token))
00407 {
00408 SourceError(source, "define %s incomplete", define->name);
00409 return qfalse;
00410 }
00411
00412 if (!strcmp(token.string, ","))
00413 {
00414 if (indent <= 0)
00415 {
00416 if (lastcomma) SourceWarning(source, "too many comma's");
00417 lastcomma = 1;
00418 break;
00419 }
00420 }
00421 lastcomma = 0;
00422
00423 if (!strcmp(token.string, "("))
00424 {
00425 indent++;
00426 continue;
00427 }
00428 else if (!strcmp(token.string, ")"))
00429 {
00430 if (--indent <= 0)
00431 {
00432 if (!parms[define->numparms-1])
00433 {
00434 SourceWarning(source, "too few define parms");
00435 }
00436 done = 1;
00437 break;
00438 }
00439 }
00440
00441 if (numparms < define->numparms)
00442 {
00443
00444 t = PC_CopyToken(&token);
00445 t->next = NULL;
00446 if (last) last->next = t;
00447 else parms[numparms] = t;
00448 last = t;
00449 }
00450 }
00451 numparms++;
00452 }
00453 return qtrue;
00454 }
00455
00456
00457
00458
00459
00460
00461 int PC_StringizeTokens(token_t *tokens, token_t *token)
00462 {
00463 token_t *t;
00464
00465 token->type = TT_STRING;
00466 token->whitespace_p = NULL;
00467 token->endwhitespace_p = NULL;
00468 token->string[0] = '\0';
00469 strcat(token->string, "\"");
00470 for (t = tokens; t; t = t->next)
00471 {
00472 strncat(token->string, t->string, MAX_TOKEN - strlen(token->string));
00473 }
00474 strncat(token->string, "\"", MAX_TOKEN - strlen(token->string));
00475 return qtrue;
00476 }
00477
00478
00479
00480
00481
00482
00483 int PC_MergeTokens(token_t *t1, token_t *t2)
00484 {
00485
00486 if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))
00487 {
00488 strcat(t1->string, t2->string);
00489 return qtrue;
00490 }
00491
00492 if (t1->type == TT_STRING && t2->type == TT_STRING)
00493 {
00494
00495 t1->string[strlen(t1->string)-1] = '\0';
00496
00497 strcat(t1->string, &t2->string[1]);
00498 return qtrue;
00499 }
00500
00501 return qfalse;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 #if DEFINEHASHING
00521
00522
00523
00524
00525
00526
00527 void PC_PrintDefineHashTable(define_t **definehash)
00528 {
00529 int i;
00530 define_t *d;
00531
00532 for (i = 0; i < DEFINEHASHSIZE; i++)
00533 {
00534 Log_Write("%4d:", i);
00535 for (d = definehash[i]; d; d = d->hashnext)
00536 {
00537 Log_Write(" %s", d->name);
00538 }
00539 Log_Write("\n");
00540 }
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550 int PC_NameHash(char *name)
00551 {
00552 int register hash, i;
00553
00554 hash = 0;
00555 for (i = 0; name[i] != '\0'; i++)
00556 {
00557 hash += name[i] * (119 + i);
00558
00559
00560 }
00561 hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
00562 return hash;
00563 }
00564
00565
00566
00567
00568
00569
00570 void PC_AddDefineToHash(define_t *define, define_t **definehash)
00571 {
00572 int hash;
00573
00574 hash = PC_NameHash(define->name);
00575 define->hashnext = definehash[hash];
00576 definehash[hash] = define;
00577 }
00578
00579
00580
00581
00582
00583
00584 define_t *PC_FindHashedDefine(define_t **definehash, char *name)
00585 {
00586 define_t *d;
00587 int hash;
00588
00589 hash = PC_NameHash(name);
00590 for (d = definehash[hash]; d; d = d->hashnext)
00591 {
00592 if (!strcmp(d->name, name)) return d;
00593 }
00594 return NULL;
00595 }
00596 #endif //DEFINEHASHING
00597
00598
00599
00600
00601
00602
00603 define_t *PC_FindDefine(define_t *defines, char *name)
00604 {
00605 define_t *d;
00606
00607 for (d = defines; d; d = d->next)
00608 {
00609 if (!strcmp(d->name, name)) return d;
00610 }
00611 return NULL;
00612 }
00613
00614
00615
00616
00617
00618
00619
00620 int PC_FindDefineParm(define_t *define, char *name)
00621 {
00622 token_t *p;
00623 int i;
00624
00625 i = 0;
00626 for (p = define->parms; p; p = p->next)
00627 {
00628 if (!strcmp(p->string, name)) return i;
00629 i++;
00630 }
00631 return -1;
00632 }
00633
00634
00635
00636
00637
00638
00639 void PC_FreeDefine(define_t *define)
00640 {
00641 token_t *t, *next;
00642
00643
00644 for (t = define->parms; t; t = next)
00645 {
00646 next = t->next;
00647 PC_FreeToken(t);
00648 }
00649
00650 for (t = define->tokens; t; t = next)
00651 {
00652 next = t->next;
00653 PC_FreeToken(t);
00654 }
00655
00656 FreeMemory(define);
00657 }
00658
00659
00660
00661
00662
00663
00664 void PC_AddBuiltinDefines(source_t *source)
00665 {
00666 int i;
00667 define_t *define;
00668 struct builtin
00669 {
00670 char *string;
00671 int builtin;
00672 } builtin[] = {
00673 { "__LINE__", BUILTIN_LINE },
00674 { "__FILE__", BUILTIN_FILE },
00675 { "__DATE__", BUILTIN_DATE },
00676 { "__TIME__", BUILTIN_TIME },
00677
00678 { NULL, 0 }
00679 };
00680
00681 for (i = 0; builtin[i].string; i++)
00682 {
00683 define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1);
00684 Com_Memset(define, 0, sizeof(define_t));
00685 define->name = (char *) define + sizeof(define_t);
00686 strcpy(define->name, builtin[i].string);
00687 define->flags |= DEFINE_FIXED;
00688 define->builtin = builtin[i].builtin;
00689
00690 #if DEFINEHASHING
00691 PC_AddDefineToHash(define, source->definehash);
00692 #else
00693 define->next = source->defines;
00694 source->defines = define;
00695 #endif //DEFINEHASHING
00696 }
00697 }
00698
00699
00700
00701
00702
00703
00704 int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,
00705 token_t **firsttoken, token_t **lasttoken)
00706 {
00707 token_t *token;
00708 unsigned long t;
00709 char *curtime;
00710
00711 token = PC_CopyToken(deftoken);
00712 switch(define->builtin)
00713 {
00714 case BUILTIN_LINE:
00715 {
00716 sprintf(token->string, "%d", deftoken->line);
00717 #ifdef NUMBERVALUE
00718 token->intvalue = deftoken->line;
00719 token->floatvalue = deftoken->line;
00720 #endif //NUMBERVALUE
00721 token->type = TT_NUMBER;
00722 token->subtype = TT_DECIMAL | TT_INTEGER;
00723 *firsttoken = token;
00724 *lasttoken = token;
00725 break;
00726 }
00727 case BUILTIN_FILE:
00728 {
00729 strcpy(token->string, source->scriptstack->filename);
00730 token->type = TT_NAME;
00731 token->subtype = strlen(token->string);
00732 *firsttoken = token;
00733 *lasttoken = token;
00734 break;
00735 }
00736 case BUILTIN_DATE:
00737 {
00738 t = time(NULL);
00739 curtime = ctime(&t);
00740 strcpy(token->string, "\"");
00741 strncat(token->string, curtime+4, 7);
00742 strncat(token->string+7, curtime+20, 4);
00743 strcat(token->string, "\"");
00744 free(curtime);
00745 token->type = TT_NAME;
00746 token->subtype = strlen(token->string);
00747 *firsttoken = token;
00748 *lasttoken = token;
00749 break;
00750 }
00751 case BUILTIN_TIME:
00752 {
00753 t = time(NULL);
00754 curtime = ctime(&t);
00755 strcpy(token->string, "\"");
00756 strncat(token->string, curtime+11, 8);
00757 strcat(token->string, "\"");
00758 free(curtime);
00759 token->type = TT_NAME;
00760 token->subtype = strlen(token->string);
00761 *firsttoken = token;
00762 *lasttoken = token;
00763 break;
00764 }
00765 case BUILTIN_STDC:
00766 default:
00767 {
00768 *firsttoken = NULL;
00769 *lasttoken = NULL;
00770 break;
00771 }
00772 }
00773 return qtrue;
00774 }
00775
00776
00777
00778
00779
00780
00781 int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,
00782 token_t **firsttoken, token_t **lasttoken)
00783 {
00784 token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
00785 token_t *t1, *t2, *first, *last, *nextpt, token;
00786 int parmnum, i;
00787
00788
00789 if (define->builtin)
00790 {
00791 return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);
00792 }
00793
00794 if (define->numparms)
00795 {
00796 if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse;
00797 #ifdef DEBUG_EVAL
00798 for (i = 0; i < define->numparms; i++)
00799 {
00800 Log_Write("define parms %d:", i);
00801 for (pt = parms[i]; pt; pt = pt->next)
00802 {
00803 Log_Write("%s", pt->string);
00804 }
00805 }
00806 #endif //DEBUG_EVAL
00807 }
00808
00809 first = NULL;
00810 last = NULL;
00811
00812 for (dt = define->tokens; dt; dt = dt->next)
00813 {
00814 parmnum = -1;
00815
00816 if (dt->type == TT_NAME)
00817 {
00818 parmnum = PC_FindDefineParm(define, dt->string);
00819 }
00820
00821 if (parmnum >= 0)
00822 {
00823 for (pt = parms[parmnum]; pt; pt = pt->next)
00824 {
00825 t = PC_CopyToken(pt);
00826
00827 t->next = NULL;
00828 if (last) last->next = t;
00829 else first = t;
00830 last = t;
00831 }
00832 }
00833 else
00834 {
00835
00836 if (dt->string[0] == '#' && dt->string[1] == '\0')
00837 {
00838
00839 if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string);
00840 else parmnum = -1;
00841
00842 if (parmnum >= 0)
00843 {
00844
00845 dt = dt->next;
00846
00847 if (!PC_StringizeTokens(parms[parmnum], &token))
00848 {
00849 SourceError(source, "can't stringize tokens");
00850 return qfalse;
00851 }
00852 t = PC_CopyToken(&token);
00853 }
00854 else
00855 {
00856 SourceWarning(source, "stringizing operator without define parameter");
00857 continue;
00858 }
00859 }
00860 else
00861 {
00862 t = PC_CopyToken(dt);
00863 }
00864
00865 t->next = NULL;
00866 if (last) last->next = t;
00867 else first = t;
00868 last = t;
00869 }
00870 }
00871
00872 for (t = first; t; )
00873 {
00874 if (t->next)
00875 {
00876
00877 if (t->next->string[0] == '#' && t->next->string[1] == '#')
00878 {
00879 t1 = t;
00880 t2 = t->next->next;
00881 if (t2)
00882 {
00883 if (!PC_MergeTokens(t1, t2))
00884 {
00885 SourceError(source, "can't merge %s with %s", t1->string, t2->string);
00886 return qfalse;
00887 }
00888 PC_FreeToken(t1->next);
00889 t1->next = t2->next;
00890 if (t2 == last) last = t1;
00891 PC_FreeToken(t2);
00892 continue;
00893 }
00894 }
00895 }
00896 t = t->next;
00897 }
00898
00899 *firsttoken = first;
00900 *lasttoken = last;
00901
00902 for (i = 0; i < define->numparms; i++)
00903 {
00904 for (pt = parms[i]; pt; pt = nextpt)
00905 {
00906 nextpt = pt->next;
00907 PC_FreeToken(pt);
00908 }
00909 }
00910
00911 return qtrue;
00912 }
00913
00914
00915
00916
00917
00918
00919 int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)
00920 {
00921 token_t *firsttoken, *lasttoken;
00922
00923 if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse;
00924
00925 if (firsttoken && lasttoken)
00926 {
00927 lasttoken->next = source->tokens;
00928 source->tokens = firsttoken;
00929 return qtrue;
00930 }
00931 return qfalse;
00932 }
00933
00934
00935
00936
00937
00938
00939 void PC_ConvertPath(char *path)
00940 {
00941 char *ptr;
00942
00943
00944 for (ptr = path; *ptr;)
00945 {
00946 if ((*ptr == '\\' || *ptr == '/') &&
00947 (*(ptr+1) == '\\' || *(ptr+1) == '/'))
00948 {
00949 strcpy(ptr, ptr+1);
00950 }
00951 else
00952 {
00953 ptr++;
00954 }
00955 }
00956
00957 for (ptr = path; *ptr;)
00958 {
00959 if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR;
00960 ptr++;
00961 }
00962 }
00963
00964
00965
00966
00967
00968
00969 int PC_Directive_include(source_t *source)
00970 {
00971 script_t *script;
00972 token_t token;
00973 char path[MAX_PATH];
00974 #ifdef QUAKE
00975 foundfile_t file;
00976 #endif //QUAKE
00977
00978 if (source->skip > 0) return qtrue;
00979
00980 if (!PC_ReadSourceToken(source, &token))
00981 {
00982 SourceError(source, "#include without file name");
00983 return qfalse;
00984 }
00985 if (token.linescrossed > 0)
00986 {
00987 SourceError(source, "#include without file name");
00988 return qfalse;
00989 }
00990 if (token.type == TT_STRING)
00991 {
00992 StripDoubleQuotes(token.string);
00993 PC_ConvertPath(token.string);
00994 script = LoadScriptFile(token.string);
00995 if (!script)
00996 {
00997 strcpy(path, source->includepath);
00998 strcat(path, token.string);
00999 script = LoadScriptFile(path);
01000 }
01001 }
01002 else if (token.type == TT_PUNCTUATION && *token.string == '<')
01003 {
01004 strcpy(path, source->includepath);
01005 while(PC_ReadSourceToken(source, &token))
01006 {
01007 if (token.linescrossed > 0)
01008 {
01009 PC_UnreadSourceToken(source, &token);
01010 break;
01011 }
01012 if (token.type == TT_PUNCTUATION && *token.string == '>') break;
01013 strncat(path, token.string, MAX_PATH);
01014 }
01015 if (*token.string != '>')
01016 {
01017 SourceWarning(source, "#include missing trailing >");
01018 }
01019 if (!strlen(path))
01020 {
01021 SourceError(source, "#include without file name between < >");
01022 return qfalse;
01023 }
01024 PC_ConvertPath(path);
01025 script = LoadScriptFile(path);
01026 }
01027 else
01028 {
01029 SourceError(source, "#include without file name");
01030 return qfalse;
01031 }
01032 #ifdef QUAKE
01033 if (!script)
01034 {
01035 Com_Memset(&file, 0, sizeof(foundfile_t));
01036 script = LoadScriptFile(path);
01037 if (script) strncpy(script->filename, path, MAX_PATH);
01038 }
01039 #endif //QUAKE
01040 if (!script)
01041 {
01042 #ifdef SCREWUP
01043 SourceWarning(source, "file %s not found", path);
01044 return qtrue;
01045 #else
01046 SourceError(source, "file %s not found", path);
01047 return qfalse;
01048 #endif //SCREWUP
01049 }
01050 PC_PushScript(source, script);
01051 return qtrue;
01052 }
01053
01054
01055
01056
01057
01058
01059
01060
01061 int PC_ReadLine(source_t *source, token_t *token)
01062 {
01063 int crossline;
01064
01065 crossline = 0;
01066 do
01067 {
01068 if (!PC_ReadSourceToken(source, token)) return qfalse;
01069
01070 if (token->linescrossed > crossline)
01071 {
01072 PC_UnreadSourceToken(source, token);
01073 return qfalse;
01074 }
01075 crossline = 1;
01076 } while(!strcmp(token->string, "\\"));
01077 return qtrue;
01078 }
01079
01080
01081
01082
01083
01084
01085 int PC_WhiteSpaceBeforeToken(token_t *token)
01086 {
01087 return token->endwhitespace_p - token->whitespace_p > 0;
01088 }
01089
01090
01091
01092
01093
01094
01095 void PC_ClearTokenWhiteSpace(token_t *token)
01096 {
01097 token->whitespace_p = NULL;
01098 token->endwhitespace_p = NULL;
01099 token->linescrossed = 0;
01100 }
01101
01102
01103
01104
01105
01106
01107 int PC_Directive_undef(source_t *source)
01108 {
01109 token_t token;
01110 define_t *define, *lastdefine;
01111 int hash;
01112
01113 if (source->skip > 0) return qtrue;
01114
01115 if (!PC_ReadLine(source, &token))
01116 {
01117 SourceError(source, "undef without name");
01118 return qfalse;
01119 }
01120 if (token.type != TT_NAME)
01121 {
01122 PC_UnreadSourceToken(source, &token);
01123 SourceError(source, "expected name, found %s", token.string);
01124 return qfalse;
01125 }
01126 #if DEFINEHASHING
01127
01128 hash = PC_NameHash(token.string);
01129 for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)
01130 {
01131 if (!strcmp(define->name, token.string))
01132 {
01133 if (define->flags & DEFINE_FIXED)
01134 {
01135 SourceWarning(source, "can't undef %s", token.string);
01136 }
01137 else
01138 {
01139 if (lastdefine) lastdefine->hashnext = define->hashnext;
01140 else source->definehash[hash] = define->hashnext;
01141 PC_FreeDefine(define);
01142 }
01143 break;
01144 }
01145 lastdefine = define;
01146 }
01147 #else //DEFINEHASHING
01148 for (lastdefine = NULL, define = source->defines; define; define = define->next)
01149 {
01150 if (!strcmp(define->name, token.string))
01151 {
01152 if (define->flags & DEFINE_FIXED)
01153 {
01154 SourceWarning(source, "can't undef %s", token.string);
01155 }
01156 else
01157 {
01158 if (lastdefine) lastdefine->next = define->next;
01159 else source->defines = define->next;
01160 PC_FreeDefine(define);
01161 }
01162 break;
01163 }
01164 lastdefine = define;
01165 }
01166 #endif //DEFINEHASHING
01167 return qtrue;
01168 }
01169
01170
01171
01172
01173
01174
01175 int PC_Directive_define(source_t *source)
01176 {
01177 token_t token, *t, *last;
01178 define_t *define;
01179
01180 if (source->skip > 0) return qtrue;
01181
01182 if (!PC_ReadLine(source, &token))
01183 {
01184 SourceError(source, "#define without name");
01185 return qfalse;
01186 }
01187 if (token.type != TT_NAME)
01188 {
01189 PC_UnreadSourceToken(source, &token);
01190 SourceError(source, "expected name after #define, found %s", token.string);
01191 return qfalse;
01192 }
01193
01194 #if DEFINEHASHING
01195 define = PC_FindHashedDefine(source->definehash, token.string);
01196 #else
01197 define = PC_FindDefine(source->defines, token.string);
01198 #endif //DEFINEHASHING
01199 if (define)
01200 {
01201 if (define->flags & DEFINE_FIXED)
01202 {
01203 SourceError(source, "can't redefine %s", token.string);
01204 return qfalse;
01205 }
01206 SourceWarning(source, "redefinition of %s", token.string);
01207
01208 PC_UnreadSourceToken(source, &token);
01209 if (!PC_Directive_undef(source)) return qfalse;
01210
01211 #if DEFINEHASHING
01212 define = PC_FindHashedDefine(source->definehash, token.string);
01213 #else
01214 define = PC_FindDefine(source->defines, token.string);
01215 #endif //DEFINEHASHING
01216 }
01217
01218 define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1);
01219 Com_Memset(define, 0, sizeof(define_t));
01220 define->name = (char *) define + sizeof(define_t);
01221 strcpy(define->name, token.string);
01222
01223 #if DEFINEHASHING
01224 PC_AddDefineToHash(define, source->definehash);
01225 #else //DEFINEHASHING
01226 define->next = source->defines;
01227 source->defines = define;
01228 #endif //DEFINEHASHING
01229
01230 if (!PC_ReadLine(source, &token)) return qtrue;
01231
01232 if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "("))
01233 {
01234
01235 last = NULL;
01236 if (!PC_CheckTokenString(source, ")"))
01237 {
01238 while(1)
01239 {
01240 if (!PC_ReadLine(source, &token))
01241 {
01242 SourceError(source, "expected define parameter");
01243 return qfalse;
01244 }
01245
01246 if (token.type != TT_NAME)
01247 {
01248 SourceError(source, "invalid define parameter");
01249 return qfalse;
01250 }
01251
01252 if (PC_FindDefineParm(define, token.string) >= 0)
01253 {
01254 SourceError(source, "two the same define parameters");
01255 return qfalse;
01256 }
01257
01258 t = PC_CopyToken(&token);
01259 PC_ClearTokenWhiteSpace(t);
01260 t->next = NULL;
01261 if (last) last->next = t;
01262 else define->parms = t;
01263 last = t;
01264 define->numparms++;
01265
01266 if (!PC_ReadLine(source, &token))
01267 {
01268 SourceError(source, "define parameters not terminated");
01269 return qfalse;
01270 }
01271
01272 if (!strcmp(token.string, ")")) break;
01273
01274 if (strcmp(token.string, ","))
01275 {
01276 SourceError(source, "define not terminated");
01277 return qfalse;
01278 }
01279 }
01280 }
01281 if (!PC_ReadLine(source, &token)) return qtrue;
01282 }
01283
01284 last = NULL;
01285 do
01286 {
01287 t = PC_CopyToken(&token);
01288 if (t->type == TT_NAME && !strcmp(t->string, define->name))
01289 {
01290 SourceError(source, "recursive define (removed recursion)");
01291 continue;
01292 }
01293 PC_ClearTokenWhiteSpace(t);
01294 t->next = NULL;
01295 if (last) last->next = t;
01296 else define->tokens = t;
01297 last = t;
01298 } while(PC_ReadLine(source, &token));
01299
01300 if (last)
01301 {
01302
01303 if (!strcmp(define->tokens->string, "##") ||
01304 !strcmp(last->string, "##"))
01305 {
01306 SourceError(source, "define with misplaced ##");
01307 return qfalse;
01308 }
01309 }
01310 return qtrue;
01311 }
01312
01313
01314
01315
01316
01317
01318 define_t *PC_DefineFromString(char *string)
01319 {
01320 script_t *script;
01321 source_t src;
01322 token_t *t;
01323 int res, i;
01324 define_t *def;
01325
01326 PC_InitTokenHeap();
01327
01328 script = LoadScriptMemory(string, strlen(string), "*extern");
01329
01330 Com_Memset(&src, 0, sizeof(source_t));
01331 strncpy(src.filename, "*extern", MAX_PATH);
01332 src.scriptstack = script;
01333 #if DEFINEHASHING
01334 src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
01335 #endif //DEFINEHASHING
01336
01337 res = PC_Directive_define(&src);
01338
01339 for (t = src.tokens; t; t = src.tokens)
01340 {
01341 src.tokens = src.tokens->next;
01342 PC_FreeToken(t);
01343 }
01344 #ifdef DEFINEHASHING
01345 def = NULL;
01346 for (i = 0; i < DEFINEHASHSIZE; i++)
01347 {
01348 if (src.definehash[i])
01349 {
01350 def = src.definehash[i];
01351 break;
01352 }
01353 }
01354 #else
01355 def = src.defines;
01356 #endif //DEFINEHASHING
01357
01358 #if DEFINEHASHING
01359 FreeMemory(src.definehash);
01360 #endif //DEFINEHASHING
01361
01362 FreeScript(script);
01363
01364 if (res > 0) return def;
01365
01366 if (src.defines) PC_FreeDefine(def);
01367
01368 return NULL;
01369 }
01370
01371
01372
01373
01374
01375
01376 int PC_AddDefine(source_t *source, char *string)
01377 {
01378 define_t *define;
01379
01380 define = PC_DefineFromString(string);
01381 if (!define) return qfalse;
01382 #if DEFINEHASHING
01383 PC_AddDefineToHash(define, source->definehash);
01384 #else //DEFINEHASHING
01385 define->next = source->defines;
01386 source->defines = define;
01387 #endif //DEFINEHASHING
01388 return qtrue;
01389 }
01390
01391
01392
01393
01394
01395
01396
01397 int PC_AddGlobalDefine(char *string)
01398 {
01399 define_t *define;
01400
01401 define = PC_DefineFromString(string);
01402 if (!define) return qfalse;
01403 define->next = globaldefines;
01404 globaldefines = define;
01405 return qtrue;
01406 }
01407
01408
01409
01410
01411
01412
01413
01414 int PC_RemoveGlobalDefine(char *name)
01415 {
01416 define_t *define;
01417
01418 define = PC_FindDefine(globaldefines, name);
01419 if (define)
01420 {
01421 PC_FreeDefine(define);
01422 return qtrue;
01423 }
01424 return qfalse;
01425 }
01426
01427
01428
01429
01430
01431
01432
01433 void PC_RemoveAllGlobalDefines(void)
01434 {
01435 define_t *define;
01436
01437 for (define = globaldefines; define; define = globaldefines)
01438 {
01439 globaldefines = globaldefines->next;
01440 PC_FreeDefine(define);
01441 }
01442 }
01443
01444
01445
01446
01447
01448
01449 define_t *PC_CopyDefine(source_t *source, define_t *define)
01450 {
01451 define_t *newdefine;
01452 token_t *token, *newtoken, *lasttoken;
01453
01454 newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1);
01455
01456 newdefine->name = (char *) newdefine + sizeof(define_t);
01457 strcpy(newdefine->name, define->name);
01458 newdefine->flags = define->flags;
01459 newdefine->builtin = define->builtin;
01460 newdefine->numparms = define->numparms;
01461
01462 newdefine->next = NULL;
01463 newdefine->hashnext = NULL;
01464
01465 newdefine->tokens = NULL;
01466 for (lasttoken = NULL, token = define->tokens; token; token = token->next)
01467 {
01468 newtoken = PC_CopyToken(token);
01469 newtoken->next = NULL;
01470 if (lasttoken) lasttoken->next = newtoken;
01471 else newdefine->tokens = newtoken;
01472 lasttoken = newtoken;
01473 }
01474
01475 newdefine->parms = NULL;
01476 for (lasttoken = NULL, token = define->parms; token; token = token->next)
01477 {
01478 newtoken = PC_CopyToken(token);
01479 newtoken->next = NULL;
01480 if (lasttoken) lasttoken->next = newtoken;
01481 else newdefine->parms = newtoken;
01482 lasttoken = newtoken;
01483 }
01484 return newdefine;
01485 }
01486
01487
01488
01489
01490
01491
01492 void PC_AddGlobalDefinesToSource(source_t *source)
01493 {
01494 define_t *define, *newdefine;
01495
01496 for (define = globaldefines; define; define = define->next)
01497 {
01498 newdefine = PC_CopyDefine(source, define);
01499 #if DEFINEHASHING
01500 PC_AddDefineToHash(newdefine, source->definehash);
01501 #else //DEFINEHASHING
01502 newdefine->next = source->defines;
01503 source->defines = newdefine;
01504 #endif //DEFINEHASHING
01505 }
01506 }
01507
01508
01509
01510
01511
01512
01513 int PC_Directive_if_def(source_t *source, int type)
01514 {
01515 token_t token;
01516 define_t *d;
01517 int skip;
01518
01519 if (!PC_ReadLine(source, &token))
01520 {
01521 SourceError(source, "#ifdef without name");
01522 return qfalse;
01523 }
01524 if (token.type != TT_NAME)
01525 {
01526 PC_UnreadSourceToken(source, &token);
01527 SourceError(source, "expected name after #ifdef, found %s", token.string);
01528 return qfalse;
01529 }
01530 #if DEFINEHASHING
01531 d = PC_FindHashedDefine(source->definehash, token.string);
01532 #else
01533 d = PC_FindDefine(source->defines, token.string);
01534 #endif //DEFINEHASHING
01535 skip = (type == INDENT_IFDEF) == (d == NULL);
01536 PC_PushIndent(source, type, skip);
01537 return qtrue;
01538 }
01539
01540
01541
01542
01543
01544
01545 int PC_Directive_ifdef(source_t *source)
01546 {
01547 return PC_Directive_if_def(source, INDENT_IFDEF);
01548 }
01549
01550
01551
01552
01553
01554
01555 int PC_Directive_ifndef(source_t *source)
01556 {
01557 return PC_Directive_if_def(source, INDENT_IFNDEF);
01558 }
01559
01560
01561
01562
01563
01564
01565 int PC_Directive_else(source_t *source)
01566 {
01567 int type, skip;
01568
01569 PC_PopIndent(source, &type, &skip);
01570 if (!type)
01571 {
01572 SourceError(source, "misplaced #else");
01573 return qfalse;
01574 }
01575 if (type == INDENT_ELSE)
01576 {
01577 SourceError(source, "#else after #else");
01578 return qfalse;
01579 }
01580 PC_PushIndent(source, INDENT_ELSE, !skip);
01581 return qtrue;
01582 }
01583
01584
01585
01586
01587
01588
01589 int PC_Directive_endif(source_t *source)
01590 {
01591 int type, skip;
01592
01593 PC_PopIndent(source, &type, &skip);
01594 if (!type)
01595 {
01596 SourceError(source, "misplaced #endif");
01597 return qfalse;
01598 }
01599 return qtrue;
01600 }
01601
01602
01603
01604
01605
01606
01607 typedef struct operator_s
01608 {
01609 int operator;
01610 int priority;
01611 int parentheses;
01612 struct operator_s *prev, *next;
01613 } operator_t;
01614
01615 typedef struct value_s
01616 {
01617 signed long int intvalue;
01618 double floatvalue;
01619 int parentheses;
01620 struct value_s *prev, *next;
01621 } value_t;
01622
01623 int PC_OperatorPriority(int op)
01624 {
01625 switch(op)
01626 {
01627 case P_MUL: return 15;
01628 case P_DIV: return 15;
01629 case P_MOD: return 15;
01630 case P_ADD: return 14;
01631 case P_SUB: return 14;
01632
01633 case P_LOGIC_AND: return 7;
01634 case P_LOGIC_OR: return 6;
01635 case P_LOGIC_GEQ: return 12;
01636 case P_LOGIC_LEQ: return 12;
01637 case P_LOGIC_EQ: return 11;
01638 case P_LOGIC_UNEQ: return 11;
01639
01640 case P_LOGIC_NOT: return 16;
01641 case P_LOGIC_GREATER: return 12;
01642 case P_LOGIC_LESS: return 12;
01643
01644 case P_RSHIFT: return 13;
01645 case P_LSHIFT: return 13;
01646
01647 case P_BIN_AND: return 10;
01648 case P_BIN_OR: return 8;
01649 case P_BIN_XOR: return 9;
01650 case P_BIN_NOT: return 16;
01651
01652 case P_COLON: return 5;
01653 case P_QUESTIONMARK: return 5;
01654 }
01655 return qfalse;
01656 }
01657
01658
01659
01660
01661
01662
01663 #define MAX_VALUES 64
01664 #define MAX_OPERATORS 64
01665 #define AllocValue(val) \
01666 if (numvalues >= MAX_VALUES) { \
01667 SourceError(source, "out of value space\n"); \
01668 error = 1; \
01669 break; \
01670 } \
01671 else \
01672 val = &value_heap[numvalues++];
01673 #define FreeValue(val)
01674
01675 #define AllocOperator(op) \
01676 if (numoperators >= MAX_OPERATORS) { \
01677 SourceError(source, "out of operator space\n"); \
01678 error = 1; \
01679 break; \
01680 } \
01681 else \
01682 op = &operator_heap[numoperators++];
01683 #define FreeOperator(op)
01684
01685 int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,
01686 double *floatvalue, int integer)
01687 {
01688 operator_t *o, *firstoperator, *lastoperator;
01689 value_t *v, *firstvalue, *lastvalue, *v1, *v2;
01690 token_t *t;
01691 int brace = 0;
01692 int parentheses = 0;
01693 int error = 0;
01694 int lastwasvalue = 0;
01695 int negativevalue = 0;
01696 int questmarkintvalue = 0;
01697 double questmarkfloatvalue = 0;
01698 int gotquestmarkvalue = qfalse;
01699 int lastoperatortype = 0;
01700
01701 operator_t operator_heap[MAX_OPERATORS];
01702 int numoperators = 0;
01703 value_t value_heap[MAX_VALUES];
01704 int numvalues = 0;
01705
01706 firstoperator = lastoperator = NULL;
01707 firstvalue = lastvalue = NULL;
01708 if (intvalue) *intvalue = 0;
01709 if (floatvalue) *floatvalue = 0;
01710 for (t = tokens; t; t = t->next)
01711 {
01712 switch(t->type)
01713 {
01714 case TT_NAME:
01715 {
01716 if (lastwasvalue || negativevalue)
01717 {
01718 SourceError(source, "syntax error in #if/#elif");
01719 error = 1;
01720 break;
01721 }
01722 if (strcmp(t->string, "defined"))
01723 {
01724 SourceError(source, "undefined name %s in #if/#elif", t->string);
01725 error = 1;
01726 break;
01727 }
01728 t = t->next;
01729 if (!strcmp(t->string, "("))
01730 {
01731 brace = qtrue;
01732 t = t->next;
01733 }
01734 if (!t || t->type != TT_NAME)
01735 {
01736 SourceError(source, "defined without name in #if/#elif");
01737 error = 1;
01738 break;
01739 }
01740
01741 AllocValue(v);
01742 #if DEFINEHASHING
01743 if (PC_FindHashedDefine(source->definehash, t->string))
01744 #else
01745 if (PC_FindDefine(source->defines, t->string))
01746 #endif //DEFINEHASHING
01747 {
01748 v->intvalue = 1;
01749 v->floatvalue = 1;
01750 }
01751 else
01752 {
01753 v->intvalue = 0;
01754 v->floatvalue = 0;
01755 }
01756 v->parentheses = parentheses;
01757 v->next = NULL;
01758 v->prev = lastvalue;
01759 if (lastvalue) lastvalue->next = v;
01760 else firstvalue = v;
01761 lastvalue = v;
01762 if (brace)
01763 {
01764 t = t->next;
01765 if (!t || strcmp(t->string, ")"))
01766 {
01767 SourceError(source, "defined without ) in #if/#elif");
01768 error = 1;
01769 break;
01770 }
01771 }
01772 brace = qfalse;
01773
01774 lastwasvalue = 1;
01775 break;
01776 }
01777 case TT_NUMBER:
01778 {
01779 if (lastwasvalue)
01780 {
01781 SourceError(source, "syntax error in #if/#elif");
01782 error = 1;
01783 break;
01784 }
01785
01786 AllocValue(v);
01787 if (negativevalue)
01788 {
01789 v->intvalue = - (signed int) t->intvalue;
01790 v->floatvalue = - t->floatvalue;
01791 }
01792 else
01793 {
01794 v->intvalue = t->intvalue;
01795 v->floatvalue = t->floatvalue;
01796 }
01797 v->parentheses = parentheses;
01798 v->next = NULL;
01799 v->prev = lastvalue;
01800 if (lastvalue) lastvalue->next = v;
01801 else firstvalue = v;
01802 lastvalue = v;
01803
01804 lastwasvalue = 1;
01805
01806 negativevalue = 0;
01807 break;
01808 }
01809 case TT_PUNCTUATION:
01810 {
01811 if (negativevalue)
01812 {
01813 SourceError(source, "misplaced minus sign in #if/#elif");
01814 error = 1;
01815 break;
01816 }
01817 if (t->subtype == P_PARENTHESESOPEN)
01818 {
01819 parentheses++;
01820 break;
01821 }
01822 else if (t->subtype == P_PARENTHESESCLOSE)
01823 {
01824 parentheses--;
01825 if (parentheses < 0)
01826 {
01827 SourceError(source, "too many ) in #if/#elsif");
01828 error = 1;
01829 }
01830 break;
01831 }
01832
01833 if (!integer)
01834 {
01835 if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
01836 t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
01837 t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
01838 t->subtype == P_BIN_XOR)
01839 {
01840 SourceError(source, "illigal operator %s on floating point operands\n", t->string);
01841 error = 1;
01842 break;
01843 }
01844 }
01845 switch(t->subtype)
01846 {
01847 case P_LOGIC_NOT:
01848 case P_BIN_NOT:
01849 {
01850 if (lastwasvalue)
01851 {
01852 SourceError(source, "! or ~ after value in #if/#elif");
01853 error = 1;
01854 break;
01855 }
01856 break;
01857 }
01858 case P_INC:
01859 case P_DEC:
01860 {
01861 SourceError(source, "++ or -- used in #if/#elif");
01862 break;
01863 }
01864 case P_SUB:
01865 {
01866 if (!lastwasvalue)
01867 {
01868 negativevalue = 1;
01869 break;
01870 }
01871 }
01872
01873 case P_MUL:
01874 case P_DIV:
01875 case P_MOD:
01876 case P_ADD:
01877
01878 case P_LOGIC_AND:
01879 case P_LOGIC_OR:
01880 case P_LOGIC_GEQ:
01881 case P_LOGIC_LEQ:
01882 case P_LOGIC_EQ:
01883 case P_LOGIC_UNEQ:
01884
01885 case P_LOGIC_GREATER:
01886 case P_LOGIC_LESS:
01887
01888 case P_RSHIFT:
01889 case P_LSHIFT:
01890
01891 case P_BIN_AND:
01892 case P_BIN_OR:
01893 case P_BIN_XOR:
01894
01895 case P_COLON:
01896 case P_QUESTIONMARK:
01897 {
01898 if (!lastwasvalue)
01899 {
01900 SourceError(source, "operator %s after operator in #if/#elif", t->string);
01901 error = 1;
01902 break;
01903 }
01904 break;
01905 }
01906 default:
01907 {
01908 SourceError(source, "invalid operator %s in #if/#elif", t->string);
01909 error = 1;
01910 break;
01911 }
01912 }
01913 if (!error && !negativevalue)
01914 {
01915
01916 AllocOperator(o);
01917 o->operator = t->subtype;
01918 o->priority = PC_OperatorPriority(t->subtype);
01919 o->parentheses = parentheses;
01920 o->next = NULL;
01921 o->prev = lastoperator;
01922 if (lastoperator) lastoperator->next = o;
01923 else firstoperator = o;
01924 lastoperator = o;
01925 lastwasvalue = 0;
01926 }
01927 break;
01928 }
01929 default:
01930 {
01931 SourceError(source, "unknown %s in #if/#elif", t->string);
01932 error = 1;
01933 break;
01934 }
01935 }
01936 if (error) break;
01937 }
01938 if (!error)
01939 {
01940 if (!lastwasvalue)
01941 {
01942 SourceError(source, "trailing operator in #if/#elif");
01943 error = 1;
01944 }
01945 else if (parentheses)
01946 {
01947 SourceError(source, "too many ( in #if/#elif");
01948 error = 1;
01949 }
01950 }
01951
01952 gotquestmarkvalue = qfalse;
01953 questmarkintvalue = 0;
01954 questmarkfloatvalue = 0;
01955
01956 while(!error && firstoperator)
01957 {
01958 v = firstvalue;
01959 for (o = firstoperator; o->next; o = o->next)
01960 {
01961
01962
01963 if (o->parentheses > o->next->parentheses) break;
01964
01965 if (o->parentheses == o->next->parentheses)
01966 {
01967
01968
01969 if (o->priority >= o->next->priority) break;
01970 }
01971
01972 if (o->operator != P_LOGIC_NOT
01973 && o->operator != P_BIN_NOT) v = v->next;
01974
01975 if (!v)
01976 {
01977 SourceError(source, "mising values in #if/#elif");
01978 error = 1;
01979 break;
01980 }
01981 }
01982 if (error) break;
01983 v1 = v;
01984 v2 = v->next;
01985 #ifdef DEBUG_EVAL
01986 if (integer)
01987 {
01988 Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue);
01989 if (v2) Log_Write("value2 = %d", v2->intvalue);
01990 }
01991 else
01992 {
01993 Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue);
01994 if (v2) Log_Write("value2 = %f", v2->floatvalue);
01995 }
01996 #endif //DEBUG_EVAL
01997 switch(o->operator)
01998 {
01999 case P_LOGIC_NOT: v1->intvalue = !v1->intvalue;
02000 v1->floatvalue = !v1->floatvalue; break;
02001 case P_BIN_NOT: v1->intvalue = ~v1->intvalue;
02002 break;
02003 case P_MUL: v1->intvalue *= v2->intvalue;
02004 v1->floatvalue *= v2->floatvalue; break;
02005 case P_DIV: if (!v2->intvalue || !v2->floatvalue)
02006 {
02007 SourceError(source, "divide by zero in #if/#elif\n");
02008 error = 1;
02009 break;
02010 }
02011 v1->intvalue /= v2->intvalue;
02012 v1->floatvalue /= v2->floatvalue; break;
02013 case P_MOD: if (!v2->intvalue)
02014 {
02015 SourceError(source, "divide by zero in #if/#elif\n");
02016 error = 1;
02017 break;
02018 }
02019 v1->intvalue %= v2->intvalue; break;
02020 case P_ADD: v1->intvalue += v2->intvalue;
02021 v1->floatvalue += v2->floatvalue; break;
02022 case P_SUB: v1->intvalue -= v2->intvalue;
02023 v1->floatvalue -= v2->floatvalue; break;
02024 case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue;
02025 v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
02026 case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue;
02027 v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
02028 case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue;
02029 v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
02030 case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue;
02031 v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
02032 case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue;
02033 v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
02034 case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue;
02035 v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
02036 case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue;
02037 v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
02038 case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue;
02039 v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
02040 case P_RSHIFT: v1->intvalue >>= v2->intvalue;
02041 break;
02042 case P_LSHIFT: v1->intvalue <<= v2->intvalue;
02043 break;
02044 case P_BIN_AND: v1->intvalue &= v2->intvalue;
02045 break;
02046 case P_BIN_OR: v1->intvalue |= v2->intvalue;
02047 break;
02048 case P_BIN_XOR: v1->intvalue ^= v2->intvalue;
02049 break;
02050 case P_COLON:
02051 {
02052 if (!gotquestmarkvalue)
02053 {
02054 SourceError(source, ": without ? in #if/#elif");
02055 error = 1;
02056 break;
02057 }
02058 if (integer)
02059 {
02060 if (!questmarkintvalue) v1->intvalue = v2->intvalue;
02061 }
02062 else
02063 {
02064 if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;
02065 }
02066 gotquestmarkvalue = qfalse;
02067 break;
02068 }
02069 case P_QUESTIONMARK:
02070 {
02071 if (gotquestmarkvalue)
02072 {
02073 SourceError(source, "? after ? in #if/#elif");
02074 error = 1;
02075 break;
02076 }
02077 questmarkintvalue = v1->intvalue;
02078 questmarkfloatvalue = v1->floatvalue;
02079 gotquestmarkvalue = qtrue;
02080 break;
02081 }
02082 }
02083 #ifdef DEBUG_EVAL
02084 if (integer) Log_Write("result value = %d", v1->intvalue);
02085 else Log_Write("result value = %f", v1->floatvalue);
02086 #endif //DEBUG_EVAL
02087 if (error) break;
02088 lastoperatortype = o->operator;
02089
02090 if (o->operator != P_LOGIC_NOT
02091 && o->operator != P_BIN_NOT)
02092 {
02093
02094 if (o->operator != P_QUESTIONMARK) v = v->next;
02095
02096 if (v->prev) v->prev->next = v->next;
02097 else firstvalue = v->next;
02098 if (v->next) v->next->prev = v->prev;
02099 else lastvalue = v->prev;
02100
02101 FreeValue(v);
02102 }
02103
02104 if (o->prev) o->prev->next = o->next;
02105 else firstoperator = o->next;
02106 if (o->next) o->next->prev = o->prev;
02107 else lastoperator = o->prev;
02108
02109 FreeOperator(o);
02110 }
02111 if (firstvalue)
02112 {
02113 if (intvalue) *intvalue = firstvalue->intvalue;
02114 if (floatvalue) *floatvalue = firstvalue->floatvalue;
02115 }
02116 for (o = firstoperator; o; o = lastoperator)
02117 {
02118 lastoperator = o->next;
02119
02120 FreeOperator(o);
02121 }
02122 for (v = firstvalue; v; v = lastvalue)
02123 {
02124 lastvalue = v->next;
02125
02126 FreeValue(v);
02127 }
02128 if (!error) return qtrue;
02129 if (intvalue) *intvalue = 0;
02130 if (floatvalue) *floatvalue = 0;
02131 return qfalse;
02132 }
02133
02134
02135
02136
02137
02138
02139 int PC_Evaluate(source_t *source, signed long int *intvalue,
02140 double *floatvalue, int integer)
02141 {
02142 token_t token, *firsttoken, *lasttoken;
02143 token_t *t, *nexttoken;
02144 define_t *define;
02145 int defined = qfalse;
02146
02147 if (intvalue) *intvalue = 0;
02148 if (floatvalue) *floatvalue = 0;
02149
02150 if (!PC_ReadLine(source, &token))
02151 {
02152 SourceError(source, "no value after #if/#elif");
02153 return qfalse;
02154 }
02155 firsttoken = NULL;
02156 lasttoken = NULL;
02157 do
02158 {
02159
02160 if (token.type == TT_NAME)
02161 {
02162 if (defined)
02163 {
02164 defined = qfalse;
02165 t = PC_CopyToken(&token);
02166 t->next = NULL;
02167 if (lasttoken) lasttoken->next = t;
02168 else firsttoken = t;
02169 lasttoken = t;
02170 }
02171 else if (!strcmp(token.string, "defined"))
02172 {
02173 defined = qtrue;
02174 t = PC_CopyToken(&token);
02175 t->next = NULL;
02176 if (lasttoken) lasttoken->next = t;
02177 else firsttoken = t;
02178 lasttoken = t;
02179 }
02180 else
02181 {
02182
02183 #if DEFINEHASHING
02184 define = PC_FindHashedDefine(source->definehash, token.string);
02185 #else
02186 define = PC_FindDefine(source->defines, token.string);
02187 #endif //DEFINEHASHING
02188 if (!define)
02189 {
02190 SourceError(source, "can't evaluate %s, not defined", token.string);
02191 return qfalse;
02192 }
02193 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
02194 }
02195 }
02196
02197 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
02198 {
02199 t = PC_CopyToken(&token);
02200 t->next = NULL;
02201 if (lasttoken) lasttoken->next = t;
02202 else firsttoken = t;
02203 lasttoken = t;
02204 }
02205 else
02206 {
02207 SourceError(source, "can't evaluate %s", token.string);
02208 return qfalse;
02209 }
02210 } while(PC_ReadLine(source, &token));
02211
02212 if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
02213
02214 #ifdef DEBUG_EVAL
02215 Log_Write("eval:");
02216 #endif //DEBUG_EVAL
02217 for (t = firsttoken; t; t = nexttoken)
02218 {
02219 #ifdef DEBUG_EVAL
02220 Log_Write(" %s", t->string);
02221 #endif //DEBUG_EVAL
02222 nexttoken = t->next;
02223 PC_FreeToken(t);
02224 }
02225 #ifdef DEBUG_EVAL
02226 if (integer) Log_Write("eval result: %d", *intvalue);
02227 else Log_Write("eval result: %f", *floatvalue);
02228 #endif //DEBUG_EVAL
02229
02230 return qtrue;
02231 }
02232
02233
02234
02235
02236
02237
02238 int PC_DollarEvaluate(source_t *source, signed long int *intvalue,
02239 double *floatvalue, int integer)
02240 {
02241 int indent, defined = qfalse;
02242 token_t token, *firsttoken, *lasttoken;
02243 token_t *t, *nexttoken;
02244 define_t *define;
02245
02246 if (intvalue) *intvalue = 0;
02247 if (floatvalue) *floatvalue = 0;
02248
02249 if (!PC_ReadSourceToken(source, &token))
02250 {
02251 SourceError(source, "no leading ( after $evalint/$evalfloat");
02252 return qfalse;
02253 }
02254 if (!PC_ReadSourceToken(source, &token))
02255 {
02256 SourceError(source, "nothing to evaluate");
02257 return qfalse;
02258 }
02259 indent = 1;
02260 firsttoken = NULL;
02261 lasttoken = NULL;
02262 do
02263 {
02264
02265 if (token.type == TT_NAME)
02266 {
02267 if (defined)
02268 {
02269 defined = qfalse;
02270 t = PC_CopyToken(&token);
02271 t->next = NULL;
02272 if (lasttoken) lasttoken->next = t;
02273 else firsttoken = t;
02274 lasttoken = t;
02275 }
02276 else if (!strcmp(token.string, "defined"))
02277 {
02278 defined = qtrue;
02279 t = PC_CopyToken(&token);
02280 t->next = NULL;
02281 if (lasttoken) lasttoken->next = t;
02282 else firsttoken = t;
02283 lasttoken = t;
02284 }
02285 else
02286 {
02287
02288 #if DEFINEHASHING
02289 define = PC_FindHashedDefine(source->definehash, token.string);
02290 #else
02291 define = PC_FindDefine(source->defines, token.string);
02292 #endif //DEFINEHASHING
02293 if (!define)
02294 {
02295 SourceError(source, "can't evaluate %s, not defined", token.string);
02296 return qfalse;
02297 }
02298 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
02299 }
02300 }
02301
02302 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
02303 {
02304 if (*token.string == '(') indent++;
02305 else if (*token.string == ')') indent--;
02306 if (indent <= 0) break;
02307 t = PC_CopyToken(&token);
02308 t->next = NULL;
02309 if (lasttoken) lasttoken->next = t;
02310 else firsttoken = t;
02311 lasttoken = t;
02312 }
02313 else
02314 {
02315 SourceError(source, "can't evaluate %s", token.string);
02316 return qfalse;
02317 }
02318 } while(PC_ReadSourceToken(source, &token));
02319
02320 if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
02321
02322 #ifdef DEBUG_EVAL
02323 Log_Write("$eval:");
02324 #endif //DEBUG_EVAL
02325 for (t = firsttoken; t; t = nexttoken)
02326 {
02327 #ifdef DEBUG_EVAL
02328 Log_Write(" %s", t->string);
02329 #endif //DEBUG_EVAL
02330 nexttoken = t->next;
02331 PC_FreeToken(t);
02332 }
02333 #ifdef DEBUG_EVAL
02334 if (integer) Log_Write("$eval result: %d", *intvalue);
02335 else Log_Write("$eval result: %f", *floatvalue);
02336 #endif //DEBUG_EVAL
02337
02338 return qtrue;
02339 }
02340
02341
02342
02343
02344
02345
02346 int PC_Directive_elif(source_t *source)
02347 {
02348 signed long int value;
02349 int type, skip;
02350
02351 PC_PopIndent(source, &type, &skip);
02352 if (!type || type == INDENT_ELSE)
02353 {
02354 SourceError(source, "misplaced #elif");
02355 return qfalse;
02356 }
02357 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02358 skip = (value == 0);
02359 PC_PushIndent(source, INDENT_ELIF, skip);
02360 return qtrue;
02361 }
02362
02363
02364
02365
02366
02367
02368 int PC_Directive_if(source_t *source)
02369 {
02370 signed long int value;
02371 int skip;
02372
02373 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02374 skip = (value == 0);
02375 PC_PushIndent(source, INDENT_IF, skip);
02376 return qtrue;
02377 }
02378
02379
02380
02381
02382
02383
02384 int PC_Directive_line(source_t *source)
02385 {
02386 SourceError(source, "#line directive not supported");
02387 return qfalse;
02388 }
02389
02390
02391
02392
02393
02394
02395 int PC_Directive_error(source_t *source)
02396 {
02397 token_t token;
02398
02399 strcpy(token.string, "");
02400 PC_ReadSourceToken(source, &token);
02401 SourceError(source, "#error directive: %s", token.string);
02402 return qfalse;
02403 }
02404
02405
02406
02407
02408
02409
02410 int PC_Directive_pragma(source_t *source)
02411 {
02412 token_t token;
02413
02414 SourceWarning(source, "#pragma directive not supported");
02415 while(PC_ReadLine(source, &token)) ;
02416 return qtrue;
02417 }
02418
02419
02420
02421
02422
02423
02424 void UnreadSignToken(source_t *source)
02425 {
02426 token_t token;
02427
02428 token.line = source->scriptstack->line;
02429 token.whitespace_p = source->scriptstack->script_p;
02430 token.endwhitespace_p = source->scriptstack->script_p;
02431 token.linescrossed = 0;
02432 strcpy(token.string, "-");
02433 token.type = TT_PUNCTUATION;
02434 token.subtype = P_SUB;
02435 PC_UnreadSourceToken(source, &token);
02436 }
02437
02438
02439
02440
02441
02442
02443 int PC_Directive_eval(source_t *source)
02444 {
02445 signed long int value;
02446 token_t token;
02447
02448 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02449
02450 token.line = source->scriptstack->line;
02451 token.whitespace_p = source->scriptstack->script_p;
02452 token.endwhitespace_p = source->scriptstack->script_p;
02453 token.linescrossed = 0;
02454 sprintf(token.string, "%d", abs(value));
02455 token.type = TT_NUMBER;
02456 token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
02457 PC_UnreadSourceToken(source, &token);
02458 if (value < 0) UnreadSignToken(source);
02459 return qtrue;
02460 }
02461
02462
02463
02464
02465
02466
02467 int PC_Directive_evalfloat(source_t *source)
02468 {
02469 double value;
02470 token_t token;
02471
02472 if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse;
02473 token.line = source->scriptstack->line;
02474 token.whitespace_p = source->scriptstack->script_p;
02475 token.endwhitespace_p = source->scriptstack->script_p;
02476 token.linescrossed = 0;
02477 sprintf(token.string, "%1.2f", fabs(value));
02478 token.type = TT_NUMBER;
02479 token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
02480 PC_UnreadSourceToken(source, &token);
02481 if (value < 0) UnreadSignToken(source);
02482 return qtrue;
02483 }
02484
02485
02486
02487
02488
02489
02490 directive_t directives[20] =
02491 {
02492 {"if", PC_Directive_if},
02493 {"ifdef", PC_Directive_ifdef},
02494 {"ifndef", PC_Directive_ifndef},
02495 {"elif", PC_Directive_elif},
02496 {"else", PC_Directive_else},
02497 {"endif", PC_Directive_endif},
02498 {"include", PC_Directive_include},
02499 {"define", PC_Directive_define},
02500 {"undef", PC_Directive_undef},
02501 {"line", PC_Directive_line},
02502 {"error", PC_Directive_error},
02503 {"pragma", PC_Directive_pragma},
02504 {"eval", PC_Directive_eval},
02505 {"evalfloat", PC_Directive_evalfloat},
02506 {NULL, NULL}
02507 };
02508
02509 int PC_ReadDirective(source_t *source)
02510 {
02511 token_t token;
02512 int i;
02513
02514
02515 if (!PC_ReadSourceToken(source, &token))
02516 {
02517 SourceError(source, "found # without name");
02518 return qfalse;
02519 }
02520
02521 if (token.linescrossed > 0)
02522 {
02523 PC_UnreadSourceToken(source, &token);
02524 SourceError(source, "found # at end of line");
02525 return qfalse;
02526 }
02527
02528 if (token.type == TT_NAME)
02529 {
02530
02531 for (i = 0; directives[i].name; i++)
02532 {
02533 if (!strcmp(directives[i].name, token.string))
02534 {
02535 return directives[i].func(source);
02536 }
02537 }
02538 }
02539 SourceError(source, "unknown precompiler directive %s", token.string);
02540 return qfalse;
02541 }
02542
02543
02544
02545
02546
02547
02548 int PC_DollarDirective_evalint(source_t *source)
02549 {
02550 signed long int value;
02551 token_t token;
02552
02553 if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse;
02554
02555 token.line = source->scriptstack->line;
02556 token.whitespace_p = source->scriptstack->script_p;
02557 token.endwhitespace_p = source->scriptstack->script_p;
02558 token.linescrossed = 0;
02559 sprintf(token.string, "%d", abs(value));
02560 token.type = TT_NUMBER;
02561 token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
02562 #ifdef NUMBERVALUE
02563 token.intvalue = value;
02564 token.floatvalue = value;
02565 #endif //NUMBERVALUE
02566 PC_UnreadSourceToken(source, &token);
02567 if (value < 0) UnreadSignToken(source);
02568 return qtrue;
02569 }
02570
02571
02572
02573
02574
02575
02576 int PC_DollarDirective_evalfloat(source_t *source)
02577 {
02578 double value;
02579 token_t token;
02580
02581 if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse;
02582 token.line = source->scriptstack->line;
02583 token.whitespace_p = source->scriptstack->script_p;
02584 token.endwhitespace_p = source->scriptstack->script_p;
02585 token.linescrossed = 0;
02586 sprintf(token.string, "%1.2f", fabs(value));
02587 token.type = TT_NUMBER;
02588 token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
02589 #ifdef NUMBERVALUE
02590 token.intvalue = (unsigned long) value;
02591 token.floatvalue = value;
02592 #endif //NUMBERVALUE
02593 PC_UnreadSourceToken(source, &token);
02594 if (value < 0) UnreadSignToken(source);
02595 return qtrue;
02596 }
02597
02598
02599
02600
02601
02602
02603 directive_t dollardirectives[20] =
02604 {
02605 {"evalint", PC_DollarDirective_evalint},
02606 {"evalfloat", PC_DollarDirective_evalfloat},
02607 {NULL, NULL}
02608 };
02609
02610 int PC_ReadDollarDirective(source_t *source)
02611 {
02612 token_t token;
02613 int i;
02614
02615
02616 if (!PC_ReadSourceToken(source, &token))
02617 {
02618 SourceError(source, "found $ without name");
02619 return qfalse;
02620 }
02621
02622 if (token.linescrossed > 0)
02623 {
02624 PC_UnreadSourceToken(source, &token);
02625 SourceError(source, "found $ at end of line");
02626 return qfalse;
02627 }
02628
02629 if (token.type == TT_NAME)
02630 {
02631
02632 for (i = 0; dollardirectives[i].name; i++)
02633 {
02634 if (!strcmp(dollardirectives[i].name, token.string))
02635 {
02636 return dollardirectives[i].func(source);
02637 }
02638 }
02639 }
02640 PC_UnreadSourceToken(source, &token);
02641 SourceError(source, "unknown precompiler directive %s", token.string);
02642 return qfalse;
02643 }
02644
02645 #ifdef QUAKEC
02646
02647
02648
02649
02650
02651
02652 int BuiltinFunction(source_t *source)
02653 {
02654 token_t token;
02655
02656 if (!PC_ReadSourceToken(source, &token)) return qfalse;
02657 if (token.type == TT_NUMBER)
02658 {
02659 PC_UnreadSourceToken(source, &token);
02660 return qtrue;
02661 }
02662 else
02663 {
02664 PC_UnreadSourceToken(source, &token);
02665 return qfalse;
02666 }
02667 }
02668
02669
02670
02671
02672
02673
02674 int QuakeCMacro(source_t *source)
02675 {
02676 int i;
02677 token_t token;
02678
02679 if (!PC_ReadSourceToken(source, &token)) return qtrue;
02680 if (token.type != TT_NAME)
02681 {
02682 PC_UnreadSourceToken(source, &token);
02683 return qtrue;
02684 }
02685
02686 for (i = 0; dollardirectives[i].name; i++)
02687 {
02688 if (!strcmp(dollardirectives[i].name, token.string))
02689 {
02690 PC_UnreadSourceToken(source, &token);
02691 return qfalse;
02692 }
02693 }
02694 PC_UnreadSourceToken(source, &token);
02695 return qtrue;
02696 }
02697 #endif //QUAKEC
02698
02699
02700
02701
02702
02703
02704 int PC_ReadToken(source_t *source, token_t *token)
02705 {
02706 define_t *define;
02707
02708 while(1)
02709 {
02710 if (!PC_ReadSourceToken(source, token)) return qfalse;
02711
02712 if (token->type == TT_PUNCTUATION && *token->string == '#')
02713 {
02714 #ifdef QUAKEC
02715 if (!BuiltinFunction(source))
02716 #endif //QUAKC
02717 {
02718
02719 if (!PC_ReadDirective(source)) return qfalse;
02720 continue;
02721 }
02722 }
02723 if (token->type == TT_PUNCTUATION && *token->string == '$')
02724 {
02725 #ifdef QUAKEC
02726 if (!QuakeCMacro(source))
02727 #endif //QUAKEC
02728 {
02729
02730 if (!PC_ReadDollarDirective(source)) return qfalse;
02731 continue;
02732 }
02733 }
02734
02735 if (token->type == TT_STRING)
02736 {
02737 token_t newtoken;
02738 if (PC_ReadToken(source, &newtoken))
02739 {
02740 if (newtoken.type == TT_STRING)
02741 {
02742 token->string[strlen(token->string)-1] = '\0';
02743 if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN)
02744 {
02745 SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN);
02746 return qfalse;
02747 }
02748 strcat(token->string, newtoken.string+1);
02749 }
02750 else
02751 {
02752 PC_UnreadToken(source, &newtoken);
02753 }
02754 }
02755 }
02756
02757 if (source->skip) continue;
02758
02759 if (token->type == TT_NAME)
02760 {
02761
02762 #if DEFINEHASHING
02763 define = PC_FindHashedDefine(source->definehash, token->string);
02764 #else
02765 define = PC_FindDefine(source->defines, token->string);
02766 #endif //DEFINEHASHING
02767
02768 if (define)
02769 {
02770
02771 if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse;
02772 continue;
02773 }
02774 }
02775
02776 Com_Memcpy(&source->token, token, sizeof(token_t));
02777
02778 return qtrue;
02779 }
02780 }
02781
02782
02783
02784
02785
02786
02787 int PC_ExpectTokenString(source_t *source, char *string)
02788 {
02789 token_t token;
02790
02791 if (!PC_ReadToken(source, &token))
02792 {
02793 SourceError(source, "couldn't find expected %s", string);
02794 return qfalse;
02795 }
02796
02797 if (strcmp(token.string, string))
02798 {
02799 SourceError(source, "expected %s, found %s", string, token.string);
02800 return qfalse;
02801 }
02802 return qtrue;
02803 }
02804
02805
02806
02807
02808
02809
02810 int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token)
02811 {
02812 char str[MAX_TOKEN];
02813
02814 if (!PC_ReadToken(source, token))
02815 {
02816 SourceError(source, "couldn't read expected token");
02817 return qfalse;
02818 }
02819
02820 if (token->type != type)
02821 {
02822 strcpy(str, "");
02823 if (type == TT_STRING) strcpy(str, "string");
02824 if (type == TT_LITERAL) strcpy(str, "literal");
02825 if (type == TT_NUMBER) strcpy(str, "number");
02826 if (type == TT_NAME) strcpy(str, "name");
02827 if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
02828 SourceError(source, "expected a %s, found %s", str, token->string);
02829 return qfalse;
02830 }
02831 if (token->type == TT_NUMBER)
02832 {
02833 if ((token->subtype & subtype) != subtype)
02834 {
02835 if (subtype & TT_DECIMAL) strcpy(str, "decimal");
02836 if (subtype & TT_HEX) strcpy(str, "hex");
02837 if (subtype & TT_OCTAL) strcpy(str, "octal");
02838 if (subtype & TT_BINARY) strcpy(str, "binary");
02839 if (subtype & TT_LONG) strcat(str, " long");
02840 if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
02841 if (subtype & TT_FLOAT) strcat(str, " float");
02842 if (subtype & TT_INTEGER) strcat(str, " integer");
02843 SourceError(source, "expected %s, found %s", str, token->string);
02844 return qfalse;
02845 }
02846 }
02847 else if (token->type == TT_PUNCTUATION)
02848 {
02849 if (token->subtype != subtype)
02850 {
02851 SourceError(source, "found %s", token->string);
02852 return qfalse;
02853 }
02854 }
02855 return qtrue;
02856 }
02857
02858
02859
02860
02861
02862
02863 int PC_ExpectAnyToken(source_t *source, token_t *token)
02864 {
02865 if (!PC_ReadToken(source, token))
02866 {
02867 SourceError(source, "couldn't read expected token");
02868 return qfalse;
02869 }
02870 else
02871 {
02872 return qtrue;
02873 }
02874 }
02875
02876
02877
02878
02879
02880
02881 int PC_CheckTokenString(source_t *source, char *string)
02882 {
02883 token_t tok;
02884
02885 if (!PC_ReadToken(source, &tok)) return qfalse;
02886
02887 if (!strcmp(tok.string, string)) return qtrue;
02888
02889 PC_UnreadSourceToken(source, &tok);
02890 return qfalse;
02891 }
02892
02893
02894
02895
02896
02897
02898 int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token)
02899 {
02900 token_t tok;
02901
02902 if (!PC_ReadToken(source, &tok)) return qfalse;
02903
02904 if (tok.type == type &&
02905 (tok.subtype & subtype) == subtype)
02906 {
02907 Com_Memcpy(token, &tok, sizeof(token_t));
02908 return qtrue;
02909 }
02910
02911 PC_UnreadSourceToken(source, &tok);
02912 return qfalse;
02913 }
02914
02915
02916
02917
02918
02919
02920 int PC_SkipUntilString(source_t *source, char *string)
02921 {
02922 token_t token;
02923
02924 while(PC_ReadToken(source, &token))
02925 {
02926 if (!strcmp(token.string, string)) return qtrue;
02927 }
02928 return qfalse;
02929 }
02930
02931
02932
02933
02934
02935
02936 void PC_UnreadLastToken(source_t *source)
02937 {
02938 PC_UnreadSourceToken(source, &source->token);
02939 }
02940
02941
02942
02943
02944
02945
02946 void PC_UnreadToken(source_t *source, token_t *token)
02947 {
02948 PC_UnreadSourceToken(source, token);
02949 }
02950
02951
02952
02953
02954
02955
02956 void PC_SetIncludePath(source_t *source, char *path)
02957 {
02958 strncpy(source->includepath, path, MAX_PATH);
02959
02960 if (source->includepath[strlen(source->includepath)-1] != '\\' &&
02961 source->includepath[strlen(source->includepath)-1] != '/')
02962 {
02963 strcat(source->includepath, PATHSEPERATOR_STR);
02964 }
02965 }
02966
02967
02968
02969
02970
02971
02972 void PC_SetPunctuations(source_t *source, punctuation_t *p)
02973 {
02974 source->punctuations = p;
02975 }
02976
02977
02978
02979
02980
02981
02982 source_t *LoadSourceFile(const char *filename)
02983 {
02984 source_t *source;
02985 script_t *script;
02986
02987 PC_InitTokenHeap();
02988
02989 script = LoadScriptFile(filename);
02990 if (!script) return NULL;
02991
02992 script->next = NULL;
02993
02994 source = (source_t *) GetMemory(sizeof(source_t));
02995 Com_Memset(source, 0, sizeof(source_t));
02996
02997 strncpy(source->filename, filename, MAX_PATH);
02998 source->scriptstack = script;
02999 source->tokens = NULL;
03000 source->defines = NULL;
03001 source->indentstack = NULL;
03002 source->skip = 0;
03003
03004 #if DEFINEHASHING
03005 source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
03006 #endif //DEFINEHASHING
03007 PC_AddGlobalDefinesToSource(source);
03008 return source;
03009 }
03010
03011
03012
03013
03014
03015
03016 source_t *LoadSourceMemory(char *ptr, int length, char *name)
03017 {
03018 source_t *source;
03019 script_t *script;
03020
03021 PC_InitTokenHeap();
03022
03023 script = LoadScriptMemory(ptr, length, name);
03024 if (!script) return NULL;
03025 script->next = NULL;
03026
03027 source = (source_t *) GetMemory(sizeof(source_t));
03028 Com_Memset(source, 0, sizeof(source_t));
03029
03030 strncpy(source->filename, name, MAX_PATH);
03031 source->scriptstack = script;
03032 source->tokens = NULL;
03033 source->defines = NULL;
03034 source->indentstack = NULL;
03035 source->skip = 0;
03036
03037 #if DEFINEHASHING
03038 source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
03039 #endif //DEFINEHASHING
03040 PC_AddGlobalDefinesToSource(source);
03041 return source;
03042 }
03043
03044
03045
03046
03047
03048
03049 void FreeSource(source_t *source)
03050 {
03051 script_t *script;
03052 token_t *token;
03053 define_t *define;
03054 indent_t *indent;
03055 int i;
03056
03057
03058
03059 while(source->scriptstack)
03060 {
03061 script = source->scriptstack;
03062 source->scriptstack = source->scriptstack->next;
03063 FreeScript(script);
03064 }
03065
03066 while(source->tokens)
03067 {
03068 token = source->tokens;
03069 source->tokens = source->tokens->next;
03070 PC_FreeToken(token);
03071 }
03072 #if DEFINEHASHING
03073 for (i = 0; i < DEFINEHASHSIZE; i++)
03074 {
03075 while(source->definehash[i])
03076 {
03077 define = source->definehash[i];
03078 source->definehash[i] = source->definehash[i]->hashnext;
03079 PC_FreeDefine(define);
03080 }
03081 }
03082 #else //DEFINEHASHING
03083
03084 while(source->defines)
03085 {
03086 define = source->defines;
03087 source->defines = source->defines->next;
03088 PC_FreeDefine(define);
03089 }
03090 #endif //DEFINEHASHING
03091
03092 while(source->indentstack)
03093 {
03094 indent = source->indentstack;
03095 source->indentstack = source->indentstack->next;
03096 FreeMemory(indent);
03097 }
03098 #if DEFINEHASHING
03099
03100 if (source->definehash) FreeMemory(source->definehash);
03101 #endif //DEFINEHASHING
03102
03103 FreeMemory(source);
03104 }
03105
03106
03107
03108
03109
03110
03111
03112 #define MAX_SOURCEFILES 64
03113
03114 source_t *sourceFiles[MAX_SOURCEFILES];
03115
03116 int PC_LoadSourceHandle(const char *filename)
03117 {
03118 source_t *source;
03119 int i;
03120
03121 for (i = 1; i < MAX_SOURCEFILES; i++)
03122 {
03123 if (!sourceFiles[i])
03124 break;
03125 }
03126 if (i >= MAX_SOURCEFILES)
03127 return 0;
03128 PS_SetBaseFolder("");
03129 source = LoadSourceFile(filename);
03130 if (!source)
03131 return 0;
03132 sourceFiles[i] = source;
03133 return i;
03134 }
03135
03136
03137
03138
03139
03140
03141 int PC_FreeSourceHandle(int handle)
03142 {
03143 if (handle < 1 || handle >= MAX_SOURCEFILES)
03144 return qfalse;
03145 if (!sourceFiles[handle])
03146 return qfalse;
03147
03148 FreeSource(sourceFiles[handle]);
03149 sourceFiles[handle] = NULL;
03150 return qtrue;
03151 }
03152
03153
03154
03155
03156
03157
03158 int PC_ReadTokenHandle(int handle, pc_token_t *pc_token)
03159 {
03160 token_t token;
03161 int ret;
03162
03163 if (handle < 1 || handle >= MAX_SOURCEFILES)
03164 return 0;
03165 if (!sourceFiles[handle])
03166 return 0;
03167
03168 ret = PC_ReadToken(sourceFiles[handle], &token);
03169 strcpy(pc_token->string, token.string);
03170 pc_token->type = token.type;
03171 pc_token->subtype = token.subtype;
03172 pc_token->intvalue = token.intvalue;
03173 pc_token->floatvalue = token.floatvalue;
03174 if (pc_token->type == TT_STRING)
03175 StripDoubleQuotes(pc_token->string);
03176 return ret;
03177 }
03178
03179
03180
03181
03182
03183
03184 int PC_SourceFileAndLine(int handle, char *filename, int *line)
03185 {
03186 if (handle < 1 || handle >= MAX_SOURCEFILES)
03187 return qfalse;
03188 if (!sourceFiles[handle])
03189 return qfalse;
03190
03191 strcpy(filename, sourceFiles[handle]->filename);
03192 if (sourceFiles[handle]->scriptstack)
03193 *line = sourceFiles[handle]->scriptstack->line;
03194 else
03195 *line = 0;
03196 return qtrue;
03197 }
03198
03199
03200
03201
03202
03203
03204 void PC_SetBaseFolder(char *path)
03205 {
03206 PS_SetBaseFolder(path);
03207 }
03208
03209
03210
03211
03212
03213
03214 void PC_CheckOpenSourceHandles(void)
03215 {
03216 int i;
03217
03218 for (i = 1; i < MAX_SOURCEFILES; i++)
03219 {
03220 if (sourceFiles[i])
03221 {
03222 #ifdef BOTLIB
03223 botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename);
03224 #endif //BOTLIB
03225 }
03226 }
03227 }
03228