l_precomp.c (88624B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 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. 11 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. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 24 /***************************************************************************** 25 * name: l_precomp.c 26 * 27 * desc: pre compiler 28 * 29 * $Archive: /MissionPack/code/botlib/l_precomp.c $ 30 * 31 *****************************************************************************/ 32 33 //Notes: fix: PC_StringizeTokens 34 35 //#define SCREWUP 36 //#define BOTLIB 37 //#define QUAKE 38 //#define QUAKEC 39 //#define MEQCC 40 41 #ifdef SCREWUP 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <limits.h> 45 #include <string.h> 46 #include <stdarg.h> 47 #include <time.h> 48 #include "l_memory.h" 49 #include "l_script.h" 50 #include "l_precomp.h" 51 52 typedef enum {qfalse, qtrue} qboolean; 53 #endif //SCREWUP 54 55 #ifdef BOTLIB 56 #include "../game/q_shared.h" 57 #include "../game/botlib.h" 58 #include "be_interface.h" 59 #include "l_memory.h" 60 #include "l_script.h" 61 #include "l_precomp.h" 62 #include "l_log.h" 63 #endif //BOTLIB 64 65 #ifdef MEQCC 66 #include "qcc.h" 67 #include "time.h" //time & ctime 68 #include "math.h" //fabs 69 #include "l_memory.h" 70 #include "l_script.h" 71 #include "l_precomp.h" 72 #include "l_log.h" 73 74 #define qtrue true 75 #define qfalse false 76 #endif //MEQCC 77 78 #ifdef BSPC 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" 84 85 #define qtrue true 86 #define qfalse false 87 #define Q_stricmp stricmp 88 89 #endif //BSPC 90 91 #if defined(QUAKE) && !defined(BSPC) 92 #include "l_utils.h" 93 #endif //QUAKE 94 95 //#define DEBUG_EVAL 96 97 #define MAX_DEFINEPARMS 128 98 99 #define DEFINEHASHING 1 100 101 //directive name with parse function 102 typedef struct directive_s 103 { 104 char *name; 105 int (*func)(source_t *source); 106 } directive_t; 107 108 #define DEFINEHASHSIZE 1024 109 110 #define TOKEN_HEAP_SIZE 4096 111 112 int numtokens; 113 /* 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 117 */ 118 119 //list with global defines added to every source loaded 120 define_t *globaldefines; 121 122 //============================================================================ 123 // 124 // Parameter: - 125 // Returns: - 126 // Changes Globals: - 127 //============================================================================ 128 void QDECL SourceError(source_t *source, char *str, ...) 129 { 130 char text[1024]; 131 va_list ap; 132 133 va_start(ap, str); 134 vsprintf(text, str, ap); 135 va_end(ap); 136 #ifdef BOTLIB 137 botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 138 #endif //BOTLIB 139 #ifdef MEQCC 140 printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 141 #endif //MEQCC 142 #ifdef BSPC 143 Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 144 #endif //BSPC 145 } //end of the function SourceError 146 //=========================================================================== 147 // 148 // Parameter: - 149 // Returns: - 150 // Changes Globals: - 151 //=========================================================================== 152 void QDECL SourceWarning(source_t *source, char *str, ...) 153 { 154 char text[1024]; 155 va_list ap; 156 157 va_start(ap, str); 158 vsprintf(text, str, ap); 159 va_end(ap); 160 #ifdef BOTLIB 161 botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 162 #endif //BOTLIB 163 #ifdef MEQCC 164 printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 165 #endif //MEQCC 166 #ifdef BSPC 167 Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); 168 #endif //BSPC 169 } //end of the function ScriptWarning 170 //============================================================================ 171 // 172 // Parameter: - 173 // Returns: - 174 // Changes Globals: - 175 //============================================================================ 176 void PC_PushIndent(source_t *source, int type, int skip) 177 { 178 indent_t *indent; 179 180 indent = (indent_t *) GetMemory(sizeof(indent_t)); 181 indent->type = type; 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 //============================================================================ 189 // 190 // Parameter: - 191 // Returns: - 192 // Changes Globals: - 193 //============================================================================ 194 void PC_PopIndent(source_t *source, int *type, int *skip) 195 { 196 indent_t *indent; 197 198 *type = 0; 199 *skip = 0; 200 201 indent = source->indentstack; 202 if (!indent) return; 203 204 //must be an indent from the current script 205 if (source->indentstack->script != source->scriptstack) return; 206 207 *type = indent->type; 208 *skip = indent->skip; 209 source->indentstack = source->indentstack->next; 210 source->skip -= indent->skip; 211 FreeMemory(indent); 212 } //end of the function PC_PopIndent 213 //============================================================================ 214 // 215 // Parameter: - 216 // Returns: - 217 // Changes Globals: - 218 //============================================================================ 219 void PC_PushScript(source_t *source, script_t *script) 220 { 221 script_t *s; 222 223 for (s = source->scriptstack; s; s = s->next) 224 { 225 if (!Q_stricmp(s->filename, script->filename)) 226 { 227 SourceError(source, "%s recursively included", script->filename); 228 return; 229 } //end if 230 } //end for 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 //============================================================================ 236 // 237 // Parameter: - 238 // Returns: - 239 // Changes Globals: - 240 //============================================================================ 241 void PC_InitTokenHeap(void) 242 { 243 /* 244 int i; 245 246 if (tokenheapinitialized) return; 247 freetokens = NULL; 248 for (i = 0; i < TOKEN_HEAP_SIZE; i++) 249 { 250 token_heap[i].next = freetokens; 251 freetokens = &token_heap[i]; 252 } //end for 253 tokenheapinitialized = qtrue; 254 */ 255 } //end of the function PC_InitTokenHeap 256 //============================================================================ 257 // 258 // Parameter: - 259 // Returns: - 260 // Changes Globals: - 261 //============================================================================ 262 token_t *PC_CopyToken(token_t *token) 263 { 264 token_t *t; 265 266 // t = (token_t *) malloc(sizeof(token_t)); 267 t = (token_t *) GetMemory(sizeof(token_t)); 268 // t = freetokens; 269 if (!t) 270 { 271 #ifdef BSPC 272 Error("out of token space\n"); 273 #else 274 Com_Error(ERR_FATAL, "out of token space\n"); 275 #endif 276 return NULL; 277 } //end if 278 // freetokens = freetokens->next; 279 Com_Memcpy(t, token, sizeof(token_t)); 280 t->next = NULL; 281 numtokens++; 282 return t; 283 } //end of the function PC_CopyToken 284 //============================================================================ 285 // 286 // Parameter: - 287 // Returns: - 288 // Changes Globals: - 289 //============================================================================ 290 void PC_FreeToken(token_t *token) 291 { 292 //free(token); 293 FreeMemory(token); 294 // token->next = freetokens; 295 // freetokens = token; 296 numtokens--; 297 } //end of the function PC_FreeToken 298 //============================================================================ 299 // 300 // Parameter: - 301 // Returns: - 302 // Changes Globals: - 303 //============================================================================ 304 int PC_ReadSourceToken(source_t *source, token_t *token) 305 { 306 token_t *t; 307 script_t *script; 308 int type, skip; 309 310 //if there's no token already available 311 while(!source->tokens) 312 { 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)) 317 { 318 //remove all indents of the script 319 while(source->indentstack && 320 source->indentstack->script == source->scriptstack) 321 { 322 SourceWarning(source, "missing #endif"); 323 PC_PopIndent(source, &type, &skip); 324 } //end if 325 } //end if 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; 331 FreeScript(script); 332 } //end while 333 //copy the already available token 334 Com_Memcpy(token, source->tokens, sizeof(token_t)); 335 //free the read token 336 t = source->tokens; 337 source->tokens = source->tokens->next; 338 PC_FreeToken(t); 339 return qtrue; 340 } //end of the function PC_ReadSourceToken 341 //============================================================================ 342 // 343 // Parameter: - 344 // Returns: - 345 // Changes Globals: - 346 //============================================================================ 347 int PC_UnreadSourceToken(source_t *source, token_t *token) 348 { 349 token_t *t; 350 351 t = PC_CopyToken(token); 352 t->next = source->tokens; 353 source->tokens = t; 354 return qtrue; 355 } //end of the function PC_UnreadSourceToken 356 //============================================================================ 357 // 358 // Parameter: - 359 // Returns: - 360 // Changes Globals: - 361 //============================================================================ 362 int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) 363 { 364 token_t token, *t, *last; 365 int i, done, lastcomma, numparms, indent; 366 367 if (!PC_ReadSourceToken(source, &token)) 368 { 369 SourceError(source, "define %s missing parms", define->name); 370 return qfalse; 371 } //end if 372 // 373 if (define->numparms > maxparms) 374 { 375 SourceError(source, "define with more than %d parameters", maxparms); 376 return qfalse; 377 } //end if 378 // 379 for (i = 0; i < define->numparms; i++) parms[i] = NULL; 380 //if no leading "(" 381 if (strcmp(token.string, "(")) 382 { 383 PC_UnreadSourceToken(source, &token); 384 SourceError(source, "define %s missing parms", define->name); 385 return qfalse; 386 } //end if 387 //read the define parameters 388 for (done = 0, numparms = 0, indent = 0; !done;) 389 { 390 if (numparms >= maxparms) 391 { 392 SourceError(source, "define %s with too many parms", define->name); 393 return qfalse; 394 } //end if 395 if (numparms >= define->numparms) 396 { 397 SourceWarning(source, "define %s has too many parms", define->name); 398 return qfalse; 399 } //end if 400 parms[numparms] = NULL; 401 lastcomma = 1; 402 last = NULL; 403 while(!done) 404 { 405 // 406 if (!PC_ReadSourceToken(source, &token)) 407 { 408 SourceError(source, "define %s incomplete", define->name); 409 return qfalse; 410 } //end if 411 // 412 if (!strcmp(token.string, ",")) 413 { 414 if (indent <= 0) 415 { 416 if (lastcomma) SourceWarning(source, "too many comma's"); 417 lastcomma = 1; 418 break; 419 } //end if 420 } //end if 421 lastcomma = 0; 422 // 423 if (!strcmp(token.string, "(")) 424 { 425 indent++; 426 continue; 427 } //end if 428 else if (!strcmp(token.string, ")")) 429 { 430 if (--indent <= 0) 431 { 432 if (!parms[define->numparms-1]) 433 { 434 SourceWarning(source, "too few define parms"); 435 } //end if 436 done = 1; 437 break; 438 } //end if 439 } //end if 440 // 441 if (numparms < define->numparms) 442 { 443 // 444 t = PC_CopyToken(&token); 445 t->next = NULL; 446 if (last) last->next = t; 447 else parms[numparms] = t; 448 last = t; 449 } //end if 450 } //end while 451 numparms++; 452 } //end for 453 return qtrue; 454 } //end of the function PC_ReadDefineParms 455 //============================================================================ 456 // 457 // Parameter: - 458 // Returns: - 459 // Changes Globals: - 460 //============================================================================ 461 int PC_StringizeTokens(token_t *tokens, token_t *token) 462 { 463 token_t *t; 464 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) 471 { 472 strncat(token->string, t->string, MAX_TOKEN - strlen(token->string)); 473 } //end for 474 strncat(token->string, "\"", MAX_TOKEN - strlen(token->string)); 475 return qtrue; 476 } //end of the function PC_StringizeTokens 477 //============================================================================ 478 // 479 // Parameter: - 480 // Returns: - 481 // Changes Globals: - 482 //============================================================================ 483 int PC_MergeTokens(token_t *t1, token_t *t2) 484 { 485 //merging of a name with a name or number 486 if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) 487 { 488 strcat(t1->string, t2->string); 489 return qtrue; 490 } //end if 491 //merging of two strings 492 if (t1->type == TT_STRING && t2->type == TT_STRING) 493 { 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]); 498 return qtrue; 499 } //end if 500 //FIXME: merging of two number of the same sub type 501 return qfalse; 502 } //end of the function PC_MergeTokens 503 //============================================================================ 504 // 505 // Parameter: - 506 // Returns: - 507 // Changes Globals: - 508 //============================================================================ 509 /* 510 void PC_PrintDefine(define_t *define) 511 { 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*/ 520 #if DEFINEHASHING 521 //============================================================================ 522 // 523 // Parameter: - 524 // Returns: - 525 // Changes Globals: - 526 //============================================================================ 527 void PC_PrintDefineHashTable(define_t **definehash) 528 { 529 int i; 530 define_t *d; 531 532 for (i = 0; i < DEFINEHASHSIZE; i++) 533 { 534 Log_Write("%4d:", i); 535 for (d = definehash[i]; d; d = d->hashnext) 536 { 537 Log_Write(" %s", d->name); 538 } //end for 539 Log_Write("\n"); 540 } //end for 541 } //end of the function PC_PrintDefineHashTable 542 //============================================================================ 543 // 544 // Parameter: - 545 // Returns: - 546 // Changes Globals: - 547 //============================================================================ 548 //char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; 549 550 int PC_NameHash(char *name) 551 { 552 int register hash, i; 553 554 hash = 0; 555 for (i = 0; name[i] != '\0'; i++) 556 { 557 hash += name[i] * (119 + i); 558 //hash += (name[i] << 7) + i; 559 //hash += (name[i] << (i&15)); 560 } //end while 561 hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); 562 return hash; 563 } //end of the function PC_NameHash 564 //============================================================================ 565 // 566 // Parameter: - 567 // Returns: - 568 // Changes Globals: - 569 //============================================================================ 570 void PC_AddDefineToHash(define_t *define, define_t **definehash) 571 { 572 int hash; 573 574 hash = PC_NameHash(define->name); 575 define->hashnext = definehash[hash]; 576 definehash[hash] = define; 577 } //end of the function PC_AddDefineToHash 578 //============================================================================ 579 // 580 // Parameter: - 581 // Returns: - 582 // Changes Globals: - 583 //============================================================================ 584 define_t *PC_FindHashedDefine(define_t **definehash, char *name) 585 { 586 define_t *d; 587 int hash; 588 589 hash = PC_NameHash(name); 590 for (d = definehash[hash]; d; d = d->hashnext) 591 { 592 if (!strcmp(d->name, name)) return d; 593 } //end for 594 return NULL; 595 } //end of the function PC_FindHashedDefine 596 #endif //DEFINEHASHING 597 //============================================================================ 598 // 599 // Parameter: - 600 // Returns: - 601 // Changes Globals: - 602 //============================================================================ 603 define_t *PC_FindDefine(define_t *defines, char *name) 604 { 605 define_t *d; 606 607 for (d = defines; d; d = d->next) 608 { 609 if (!strcmp(d->name, name)) return d; 610 } //end for 611 return NULL; 612 } //end of the function PC_FindDefine 613 //============================================================================ 614 // 615 // Parameter: - 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) 621 { 622 token_t *p; 623 int i; 624 625 i = 0; 626 for (p = define->parms; p; p = p->next) 627 { 628 if (!strcmp(p->string, name)) return i; 629 i++; 630 } //end for 631 return -1; 632 } //end of the function PC_FindDefineParm 633 //============================================================================ 634 // 635 // Parameter: - 636 // Returns: - 637 // Changes Globals: - 638 //============================================================================ 639 void PC_FreeDefine(define_t *define) 640 { 641 token_t *t, *next; 642 643 //free the define parameters 644 for (t = define->parms; t; t = next) 645 { 646 next = t->next; 647 PC_FreeToken(t); 648 } //end for 649 //free the define tokens 650 for (t = define->tokens; t; t = next) 651 { 652 next = t->next; 653 PC_FreeToken(t); 654 } //end for 655 //free the define 656 FreeMemory(define); 657 } //end of the function PC_FreeDefine 658 //============================================================================ 659 // 660 // Parameter: - 661 // Returns: - 662 // Changes Globals: - 663 //============================================================================ 664 void PC_AddBuiltinDefines(source_t *source) 665 { 666 int i; 667 define_t *define; 668 struct builtin 669 { 670 char *string; 671 int builtin; 672 } builtin[] = { // bk001204 - brackets 673 { "__LINE__", BUILTIN_LINE }, 674 { "__FILE__", BUILTIN_FILE }, 675 { "__DATE__", BUILTIN_DATE }, 676 { "__TIME__", BUILTIN_TIME }, 677 // { "__STDC__", BUILTIN_STDC }, 678 { NULL, 0 } 679 }; 680 681 for (i = 0; builtin[i].string; i++) 682 { 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 690 #if DEFINEHASHING 691 PC_AddDefineToHash(define, source->definehash); 692 #else 693 define->next = source->defines; 694 source->defines = define; 695 #endif //DEFINEHASHING 696 } //end for 697 } //end of the function PC_AddBuiltinDefines 698 //============================================================================ 699 // 700 // Parameter: - 701 // Returns: - 702 // Changes Globals: - 703 //============================================================================ 704 int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, 705 token_t **firsttoken, token_t **lasttoken) 706 { 707 token_t *token; 708 unsigned long t; // time_t t; //to prevent LCC warning 709 char *curtime; 710 711 token = PC_CopyToken(deftoken); 712 switch(define->builtin) 713 { 714 case BUILTIN_LINE: 715 { 716 sprintf(token->string, "%d", deftoken->line); 717 #ifdef NUMBERVALUE 718 token->intvalue = deftoken->line; 719 token->floatvalue = deftoken->line; 720 #endif //NUMBERVALUE 721 token->type = TT_NUMBER; 722 token->subtype = TT_DECIMAL | TT_INTEGER; 723 *firsttoken = token; 724 *lasttoken = token; 725 break; 726 } //end case 727 case BUILTIN_FILE: 728 { 729 strcpy(token->string, source->scriptstack->filename); 730 token->type = TT_NAME; 731 token->subtype = strlen(token->string); 732 *firsttoken = token; 733 *lasttoken = token; 734 break; 735 } //end case 736 case BUILTIN_DATE: 737 { 738 t = time(NULL); 739 curtime = ctime(&t); 740 strcpy(token->string, "\""); 741 strncat(token->string, curtime+4, 7); 742 strncat(token->string+7, curtime+20, 4); 743 strcat(token->string, "\""); 744 free(curtime); 745 token->type = TT_NAME; 746 token->subtype = strlen(token->string); 747 *firsttoken = token; 748 *lasttoken = token; 749 break; 750 } //end case 751 case BUILTIN_TIME: 752 { 753 t = time(NULL); 754 curtime = ctime(&t); 755 strcpy(token->string, "\""); 756 strncat(token->string, curtime+11, 8); 757 strcat(token->string, "\""); 758 free(curtime); 759 token->type = TT_NAME; 760 token->subtype = strlen(token->string); 761 *firsttoken = token; 762 *lasttoken = token; 763 break; 764 } //end case 765 case BUILTIN_STDC: 766 default: 767 { 768 *firsttoken = NULL; 769 *lasttoken = NULL; 770 break; 771 } //end case 772 } //end switch 773 return qtrue; 774 } //end of the function PC_ExpandBuiltinDefine 775 //============================================================================ 776 // 777 // Parameter: - 778 // Returns: - 779 // Changes Globals: - 780 //============================================================================ 781 int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, 782 token_t **firsttoken, token_t **lasttoken) 783 { 784 token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; 785 token_t *t1, *t2, *first, *last, *nextpt, token; 786 int parmnum, i; 787 788 //if it is a builtin define 789 if (define->builtin) 790 { 791 return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); 792 } //end if 793 //if the define has parameters 794 if (define->numparms) 795 { 796 if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; 797 #ifdef DEBUG_EVAL 798 for (i = 0; i < define->numparms; i++) 799 { 800 Log_Write("define parms %d:", i); 801 for (pt = parms[i]; pt; pt = pt->next) 802 { 803 Log_Write("%s", pt->string); 804 } //end for 805 } //end for 806 #endif //DEBUG_EVAL 807 } //end if 808 //empty list at first 809 first = NULL; 810 last = NULL; 811 //create a list with tokens of the expanded define 812 for (dt = define->tokens; dt; dt = dt->next) 813 { 814 parmnum = -1; 815 //if the token is a name, it could be a define parameter 816 if (dt->type == TT_NAME) 817 { 818 parmnum = PC_FindDefineParm(define, dt->string); 819 } //end if 820 //if it is a define parameter 821 if (parmnum >= 0) 822 { 823 for (pt = parms[parmnum]; pt; pt = pt->next) 824 { 825 t = PC_CopyToken(pt); 826 //add the token to the list 827 t->next = NULL; 828 if (last) last->next = t; 829 else first = t; 830 last = t; 831 } //end for 832 } //end if 833 else 834 { 835 //if stringizing operator 836 if (dt->string[0] == '#' && dt->string[1] == '\0') 837 { 838 //the stringizing operator must be followed by a define parameter 839 if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string); 840 else parmnum = -1; 841 // 842 if (parmnum >= 0) 843 { 844 //step over the stringizing operator 845 dt = dt->next; 846 //stringize the define parameter tokens 847 if (!PC_StringizeTokens(parms[parmnum], &token)) 848 { 849 SourceError(source, "can't stringize tokens"); 850 return qfalse; 851 } //end if 852 t = PC_CopyToken(&token); 853 } //end if 854 else 855 { 856 SourceWarning(source, "stringizing operator without define parameter"); 857 continue; 858 } //end if 859 } //end if 860 else 861 { 862 t = PC_CopyToken(dt); 863 } //end else 864 //add the token to the list 865 t->next = NULL; 866 if (last) last->next = t; 867 else first = t; 868 last = t; 869 } //end else 870 } //end for 871 //check for the merging operator 872 for (t = first; t; ) 873 { 874 if (t->next) 875 { 876 //if the merging operator 877 if (t->next->string[0] == '#' && t->next->string[1] == '#') 878 { 879 t1 = t; 880 t2 = t->next->next; 881 if (t2) 882 { 883 if (!PC_MergeTokens(t1, t2)) 884 { 885 SourceError(source, "can't merge %s with %s", t1->string, t2->string); 886 return qfalse; 887 } //end if 888 PC_FreeToken(t1->next); 889 t1->next = t2->next; 890 if (t2 == last) last = t1; 891 PC_FreeToken(t2); 892 continue; 893 } //end if 894 } //end if 895 } //end if 896 t = t->next; 897 } //end for 898 //store the first and last token of the list 899 *firsttoken = first; 900 *lasttoken = last; 901 //free all the parameter tokens 902 for (i = 0; i < define->numparms; i++) 903 { 904 for (pt = parms[i]; pt; pt = nextpt) 905 { 906 nextpt = pt->next; 907 PC_FreeToken(pt); 908 } //end for 909 } //end for 910 // 911 return qtrue; 912 } //end of the function PC_ExpandDefine 913 //============================================================================ 914 // 915 // Parameter: - 916 // Returns: - 917 // Changes Globals: - 918 //============================================================================ 919 int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) 920 { 921 token_t *firsttoken, *lasttoken; 922 923 if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; 924 925 if (firsttoken && lasttoken) 926 { 927 lasttoken->next = source->tokens; 928 source->tokens = firsttoken; 929 return qtrue; 930 } //end if 931 return qfalse; 932 } //end of the function PC_ExpandDefineIntoSource 933 //============================================================================ 934 // 935 // Parameter: - 936 // Returns: - 937 // Changes Globals: - 938 //============================================================================ 939 void PC_ConvertPath(char *path) 940 { 941 char *ptr; 942 943 //remove double path seperators 944 for (ptr = path; *ptr;) 945 { 946 if ((*ptr == '\\' || *ptr == '/') && 947 (*(ptr+1) == '\\' || *(ptr+1) == '/')) 948 { 949 strcpy(ptr, ptr+1); 950 } //end if 951 else 952 { 953 ptr++; 954 } //end else 955 } //end while 956 //set OS dependent path seperators 957 for (ptr = path; *ptr;) 958 { 959 if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR; 960 ptr++; 961 } //end while 962 } //end of the function PC_ConvertPath 963 //============================================================================ 964 // 965 // Parameter: - 966 // Returns: - 967 // Changes Globals: - 968 //============================================================================ 969 int PC_Directive_include(source_t *source) 970 { 971 script_t *script; 972 token_t token; 973 char path[MAX_PATH]; 974 #ifdef QUAKE 975 foundfile_t file; 976 #endif //QUAKE 977 978 if (source->skip > 0) return qtrue; 979 // 980 if (!PC_ReadSourceToken(source, &token)) 981 { 982 SourceError(source, "#include without file name"); 983 return qfalse; 984 } //end if 985 if (token.linescrossed > 0) 986 { 987 SourceError(source, "#include without file name"); 988 return qfalse; 989 } //end if 990 if (token.type == TT_STRING) 991 { 992 StripDoubleQuotes(token.string); 993 PC_ConvertPath(token.string); 994 script = LoadScriptFile(token.string); 995 if (!script) 996 { 997 strcpy(path, source->includepath); 998 strcat(path, token.string); 999 script = LoadScriptFile(path); 1000 } //end if 1001 } //end if 1002 else if (token.type == TT_PUNCTUATION && *token.string == '<') 1003 { 1004 strcpy(path, source->includepath); 1005 while(PC_ReadSourceToken(source, &token)) 1006 { 1007 if (token.linescrossed > 0) 1008 { 1009 PC_UnreadSourceToken(source, &token); 1010 break; 1011 } //end if 1012 if (token.type == TT_PUNCTUATION && *token.string == '>') break; 1013 strncat(path, token.string, MAX_PATH); 1014 } //end while 1015 if (*token.string != '>') 1016 { 1017 SourceWarning(source, "#include missing trailing >"); 1018 } //end if 1019 if (!strlen(path)) 1020 { 1021 SourceError(source, "#include without file name between < >"); 1022 return qfalse; 1023 } //end if 1024 PC_ConvertPath(path); 1025 script = LoadScriptFile(path); 1026 } //end if 1027 else 1028 { 1029 SourceError(source, "#include without file name"); 1030 return qfalse; 1031 } //end else 1032 #ifdef QUAKE 1033 if (!script) 1034 { 1035 Com_Memset(&file, 0, sizeof(foundfile_t)); 1036 script = LoadScriptFile(path); 1037 if (script) strncpy(script->filename, path, MAX_PATH); 1038 } //end if 1039 #endif //QUAKE 1040 if (!script) 1041 { 1042 #ifdef SCREWUP 1043 SourceWarning(source, "file %s not found", path); 1044 return qtrue; 1045 #else 1046 SourceError(source, "file %s not found", path); 1047 return qfalse; 1048 #endif //SCREWUP 1049 } //end if 1050 PC_PushScript(source, script); 1051 return qtrue; 1052 } //end of the function PC_Directive_include 1053 //============================================================================ 1054 // reads a token from the current line, continues reading on the next 1055 // line only if a backslash '\' is encountered. 1056 // 1057 // Parameter: - 1058 // Returns: - 1059 // Changes Globals: - 1060 //============================================================================ 1061 int PC_ReadLine(source_t *source, token_t *token) 1062 { 1063 int crossline; 1064 1065 crossline = 0; 1066 do 1067 { 1068 if (!PC_ReadSourceToken(source, token)) return qfalse; 1069 1070 if (token->linescrossed > crossline) 1071 { 1072 PC_UnreadSourceToken(source, token); 1073 return qfalse; 1074 } //end if 1075 crossline = 1; 1076 } while(!strcmp(token->string, "\\")); 1077 return qtrue; 1078 } //end of the function PC_ReadLine 1079 //============================================================================ 1080 // 1081 // Parameter: - 1082 // Returns: - 1083 // Changes Globals: - 1084 //============================================================================ 1085 int PC_WhiteSpaceBeforeToken(token_t *token) 1086 { 1087 return token->endwhitespace_p - token->whitespace_p > 0; 1088 } //end of the function PC_WhiteSpaceBeforeToken 1089 //============================================================================ 1090 // 1091 // Parameter: - 1092 // Returns: - 1093 // Changes Globals: - 1094 //============================================================================ 1095 void PC_ClearTokenWhiteSpace(token_t *token) 1096 { 1097 token->whitespace_p = NULL; 1098 token->endwhitespace_p = NULL; 1099 token->linescrossed = 0; 1100 } //end of the function PC_ClearTokenWhiteSpace 1101 //============================================================================ 1102 // 1103 // Parameter: - 1104 // Returns: - 1105 // Changes Globals: - 1106 //============================================================================ 1107 int PC_Directive_undef(source_t *source) 1108 { 1109 token_t token; 1110 define_t *define, *lastdefine; 1111 int hash; 1112 1113 if (source->skip > 0) return qtrue; 1114 // 1115 if (!PC_ReadLine(source, &token)) 1116 { 1117 SourceError(source, "undef without name"); 1118 return qfalse; 1119 } //end if 1120 if (token.type != TT_NAME) 1121 { 1122 PC_UnreadSourceToken(source, &token); 1123 SourceError(source, "expected name, found %s", token.string); 1124 return qfalse; 1125 } //end if 1126 #if DEFINEHASHING 1127 1128 hash = PC_NameHash(token.string); 1129 for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) 1130 { 1131 if (!strcmp(define->name, token.string)) 1132 { 1133 if (define->flags & DEFINE_FIXED) 1134 { 1135 SourceWarning(source, "can't undef %s", token.string); 1136 } //end if 1137 else 1138 { 1139 if (lastdefine) lastdefine->hashnext = define->hashnext; 1140 else source->definehash[hash] = define->hashnext; 1141 PC_FreeDefine(define); 1142 } //end else 1143 break; 1144 } //end if 1145 lastdefine = define; 1146 } //end for 1147 #else //DEFINEHASHING 1148 for (lastdefine = NULL, define = source->defines; define; define = define->next) 1149 { 1150 if (!strcmp(define->name, token.string)) 1151 { 1152 if (define->flags & DEFINE_FIXED) 1153 { 1154 SourceWarning(source, "can't undef %s", token.string); 1155 } //end if 1156 else 1157 { 1158 if (lastdefine) lastdefine->next = define->next; 1159 else source->defines = define->next; 1160 PC_FreeDefine(define); 1161 } //end else 1162 break; 1163 } //end if 1164 lastdefine = define; 1165 } //end for 1166 #endif //DEFINEHASHING 1167 return qtrue; 1168 } //end of the function PC_Directive_undef 1169 //============================================================================ 1170 // 1171 // Parameter: - 1172 // Returns: - 1173 // Changes Globals: - 1174 //============================================================================ 1175 int PC_Directive_define(source_t *source) 1176 { 1177 token_t token, *t, *last; 1178 define_t *define; 1179 1180 if (source->skip > 0) return qtrue; 1181 // 1182 if (!PC_ReadLine(source, &token)) 1183 { 1184 SourceError(source, "#define without name"); 1185 return qfalse; 1186 } //end if 1187 if (token.type != TT_NAME) 1188 { 1189 PC_UnreadSourceToken(source, &token); 1190 SourceError(source, "expected name after #define, found %s", token.string); 1191 return qfalse; 1192 } //end if 1193 //check if the define already exists 1194 #if DEFINEHASHING 1195 define = PC_FindHashedDefine(source->definehash, token.string); 1196 #else 1197 define = PC_FindDefine(source->defines, token.string); 1198 #endif //DEFINEHASHING 1199 if (define) 1200 { 1201 if (define->flags & DEFINE_FIXED) 1202 { 1203 SourceError(source, "can't redefine %s", token.string); 1204 return qfalse; 1205 } //end if 1206 SourceWarning(source, "redefinition of %s", token.string); 1207 //unread the define name before executing the #undef directive 1208 PC_UnreadSourceToken(source, &token); 1209 if (!PC_Directive_undef(source)) return qfalse; 1210 //if the define was not removed (define->flags & DEFINE_FIXED) 1211 #if DEFINEHASHING 1212 define = PC_FindHashedDefine(source->definehash, token.string); 1213 #else 1214 define = PC_FindDefine(source->defines, token.string); 1215 #endif //DEFINEHASHING 1216 } //end if 1217 //allocate define 1218 define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1); 1219 Com_Memset(define, 0, sizeof(define_t)); 1220 define->name = (char *) define + sizeof(define_t); 1221 strcpy(define->name, token.string); 1222 //add the define to the source 1223 #if DEFINEHASHING 1224 PC_AddDefineToHash(define, source->definehash); 1225 #else //DEFINEHASHING 1226 define->next = source->defines; 1227 source->defines = define; 1228 #endif //DEFINEHASHING 1229 //if nothing is defined, just return 1230 if (!PC_ReadLine(source, &token)) return qtrue; 1231 //if it is a define with parameters 1232 if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) 1233 { 1234 //read the define parameters 1235 last = NULL; 1236 if (!PC_CheckTokenString(source, ")")) 1237 { 1238 while(1) 1239 { 1240 if (!PC_ReadLine(source, &token)) 1241 { 1242 SourceError(source, "expected define parameter"); 1243 return qfalse; 1244 } //end if 1245 //if it isn't a name 1246 if (token.type != TT_NAME) 1247 { 1248 SourceError(source, "invalid define parameter"); 1249 return qfalse; 1250 } //end if 1251 // 1252 if (PC_FindDefineParm(define, token.string) >= 0) 1253 { 1254 SourceError(source, "two the same define parameters"); 1255 return qfalse; 1256 } //end if 1257 //add the define parm 1258 t = PC_CopyToken(&token); 1259 PC_ClearTokenWhiteSpace(t); 1260 t->next = NULL; 1261 if (last) last->next = t; 1262 else define->parms = t; 1263 last = t; 1264 define->numparms++; 1265 //read next token 1266 if (!PC_ReadLine(source, &token)) 1267 { 1268 SourceError(source, "define parameters not terminated"); 1269 return qfalse; 1270 } //end if 1271 // 1272 if (!strcmp(token.string, ")")) break; 1273 //then it must be a comma 1274 if (strcmp(token.string, ",")) 1275 { 1276 SourceError(source, "define not terminated"); 1277 return qfalse; 1278 } //end if 1279 } //end while 1280 } //end if 1281 if (!PC_ReadLine(source, &token)) return qtrue; 1282 } //end if 1283 //read the defined stuff 1284 last = NULL; 1285 do 1286 { 1287 t = PC_CopyToken(&token); 1288 if (t->type == TT_NAME && !strcmp(t->string, define->name)) 1289 { 1290 SourceError(source, "recursive define (removed recursion)"); 1291 continue; 1292 } //end if 1293 PC_ClearTokenWhiteSpace(t); 1294 t->next = NULL; 1295 if (last) last->next = t; 1296 else define->tokens = t; 1297 last = t; 1298 } while(PC_ReadLine(source, &token)); 1299 // 1300 if (last) 1301 { 1302 //check for merge operators at the beginning or end 1303 if (!strcmp(define->tokens->string, "##") || 1304 !strcmp(last->string, "##")) 1305 { 1306 SourceError(source, "define with misplaced ##"); 1307 return qfalse; 1308 } //end if 1309 } //end if 1310 return qtrue; 1311 } //end of the function PC_Directive_define 1312 //============================================================================ 1313 // 1314 // Parameter: - 1315 // Returns: - 1316 // Changes Globals: - 1317 //============================================================================ 1318 define_t *PC_DefineFromString(char *string) 1319 { 1320 script_t *script; 1321 source_t src; 1322 token_t *t; 1323 int res, i; 1324 define_t *def; 1325 1326 PC_InitTokenHeap(); 1327 1328 script = LoadScriptMemory(string, strlen(string), "*extern"); 1329 //create a new source 1330 Com_Memset(&src, 0, sizeof(source_t)); 1331 strncpy(src.filename, "*extern", MAX_PATH); 1332 src.scriptstack = script; 1333 #if DEFINEHASHING 1334 src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); 1335 #endif //DEFINEHASHING 1336 //create a define from the source 1337 res = PC_Directive_define(&src); 1338 //free any tokens if left 1339 for (t = src.tokens; t; t = src.tokens) 1340 { 1341 src.tokens = src.tokens->next; 1342 PC_FreeToken(t); 1343 } //end for 1344 #ifdef DEFINEHASHING 1345 def = NULL; 1346 for (i = 0; i < DEFINEHASHSIZE; i++) 1347 { 1348 if (src.definehash[i]) 1349 { 1350 def = src.definehash[i]; 1351 break; 1352 } //end if 1353 } //end for 1354 #else 1355 def = src.defines; 1356 #endif //DEFINEHASHING 1357 // 1358 #if DEFINEHASHING 1359 FreeMemory(src.definehash); 1360 #endif //DEFINEHASHING 1361 // 1362 FreeScript(script); 1363 //if the define was created succesfully 1364 if (res > 0) return def; 1365 //free the define is created 1366 if (src.defines) PC_FreeDefine(def); 1367 // 1368 return NULL; 1369 } //end of the function PC_DefineFromString 1370 //============================================================================ 1371 // 1372 // Parameter: - 1373 // Returns: - 1374 // Changes Globals: - 1375 //============================================================================ 1376 int PC_AddDefine(source_t *source, char *string) 1377 { 1378 define_t *define; 1379 1380 define = PC_DefineFromString(string); 1381 if (!define) return qfalse; 1382 #if DEFINEHASHING 1383 PC_AddDefineToHash(define, source->definehash); 1384 #else //DEFINEHASHING 1385 define->next = source->defines; 1386 source->defines = define; 1387 #endif //DEFINEHASHING 1388 return qtrue; 1389 } //end of the function PC_AddDefine 1390 //============================================================================ 1391 // add a globals define that will be added to all opened sources 1392 // 1393 // Parameter: - 1394 // Returns: - 1395 // Changes Globals: - 1396 //============================================================================ 1397 int PC_AddGlobalDefine(char *string) 1398 { 1399 define_t *define; 1400 1401 define = PC_DefineFromString(string); 1402 if (!define) return qfalse; 1403 define->next = globaldefines; 1404 globaldefines = define; 1405 return qtrue; 1406 } //end of the function PC_AddGlobalDefine 1407 //============================================================================ 1408 // remove the given global define 1409 // 1410 // Parameter: - 1411 // Returns: - 1412 // Changes Globals: - 1413 //============================================================================ 1414 int PC_RemoveGlobalDefine(char *name) 1415 { 1416 define_t *define; 1417 1418 define = PC_FindDefine(globaldefines, name); 1419 if (define) 1420 { 1421 PC_FreeDefine(define); 1422 return qtrue; 1423 } //end if 1424 return qfalse; 1425 } //end of the function PC_RemoveGlobalDefine 1426 //============================================================================ 1427 // remove all globals defines 1428 // 1429 // Parameter: - 1430 // Returns: - 1431 // Changes Globals: - 1432 //============================================================================ 1433 void PC_RemoveAllGlobalDefines(void) 1434 { 1435 define_t *define; 1436 1437 for (define = globaldefines; define; define = globaldefines) 1438 { 1439 globaldefines = globaldefines->next; 1440 PC_FreeDefine(define); 1441 } //end for 1442 } //end of the function PC_RemoveAllGlobalDefines 1443 //============================================================================ 1444 // 1445 // Parameter: - 1446 // Returns: - 1447 // Changes Globals: - 1448 //============================================================================ 1449 define_t *PC_CopyDefine(source_t *source, define_t *define) 1450 { 1451 define_t *newdefine; 1452 token_t *token, *newtoken, *lasttoken; 1453 1454 newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1); 1455 //copy the define name 1456 newdefine->name = (char *) newdefine + sizeof(define_t); 1457 strcpy(newdefine->name, define->name); 1458 newdefine->flags = define->flags; 1459 newdefine->builtin = define->builtin; 1460 newdefine->numparms = define->numparms; 1461 //the define is not linked 1462 newdefine->next = NULL; 1463 newdefine->hashnext = NULL; 1464 //copy the define tokens 1465 newdefine->tokens = NULL; 1466 for (lasttoken = NULL, token = define->tokens; token; token = token->next) 1467 { 1468 newtoken = PC_CopyToken(token); 1469 newtoken->next = NULL; 1470 if (lasttoken) lasttoken->next = newtoken; 1471 else newdefine->tokens = newtoken; 1472 lasttoken = newtoken; 1473 } //end for 1474 //copy the define parameters 1475 newdefine->parms = NULL; 1476 for (lasttoken = NULL, token = define->parms; token; token = token->next) 1477 { 1478 newtoken = PC_CopyToken(token); 1479 newtoken->next = NULL; 1480 if (lasttoken) lasttoken->next = newtoken; 1481 else newdefine->parms = newtoken; 1482 lasttoken = newtoken; 1483 } //end for 1484 return newdefine; 1485 } //end of the function PC_CopyDefine 1486 //============================================================================ 1487 // 1488 // Parameter: - 1489 // Returns: - 1490 // Changes Globals: - 1491 //============================================================================ 1492 void PC_AddGlobalDefinesToSource(source_t *source) 1493 { 1494 define_t *define, *newdefine; 1495 1496 for (define = globaldefines; define; define = define->next) 1497 { 1498 newdefine = PC_CopyDefine(source, define); 1499 #if DEFINEHASHING 1500 PC_AddDefineToHash(newdefine, source->definehash); 1501 #else //DEFINEHASHING 1502 newdefine->next = source->defines; 1503 source->defines = newdefine; 1504 #endif //DEFINEHASHING 1505 } //end for 1506 } //end of the function PC_AddGlobalDefinesToSource 1507 //============================================================================ 1508 // 1509 // Parameter: - 1510 // Returns: - 1511 // Changes Globals: - 1512 //============================================================================ 1513 int PC_Directive_if_def(source_t *source, int type) 1514 { 1515 token_t token; 1516 define_t *d; 1517 int skip; 1518 1519 if (!PC_ReadLine(source, &token)) 1520 { 1521 SourceError(source, "#ifdef without name"); 1522 return qfalse; 1523 } //end if 1524 if (token.type != TT_NAME) 1525 { 1526 PC_UnreadSourceToken(source, &token); 1527 SourceError(source, "expected name after #ifdef, found %s", token.string); 1528 return qfalse; 1529 } //end if 1530 #if DEFINEHASHING 1531 d = PC_FindHashedDefine(source->definehash, token.string); 1532 #else 1533 d = PC_FindDefine(source->defines, token.string); 1534 #endif //DEFINEHASHING 1535 skip = (type == INDENT_IFDEF) == (d == NULL); 1536 PC_PushIndent(source, type, skip); 1537 return qtrue; 1538 } //end of the function PC_Directiveif_def 1539 //============================================================================ 1540 // 1541 // Parameter: - 1542 // Returns: - 1543 // Changes Globals: - 1544 //============================================================================ 1545 int PC_Directive_ifdef(source_t *source) 1546 { 1547 return PC_Directive_if_def(source, INDENT_IFDEF); 1548 } //end of the function PC_Directive_ifdef 1549 //============================================================================ 1550 // 1551 // Parameter: - 1552 // Returns: - 1553 // Changes Globals: - 1554 //============================================================================ 1555 int PC_Directive_ifndef(source_t *source) 1556 { 1557 return PC_Directive_if_def(source, INDENT_IFNDEF); 1558 } //end of the function PC_Directive_ifndef 1559 //============================================================================ 1560 // 1561 // Parameter: - 1562 // Returns: - 1563 // Changes Globals: - 1564 //============================================================================ 1565 int PC_Directive_else(source_t *source) 1566 { 1567 int type, skip; 1568 1569 PC_PopIndent(source, &type, &skip); 1570 if (!type) 1571 { 1572 SourceError(source, "misplaced #else"); 1573 return qfalse; 1574 } //end if 1575 if (type == INDENT_ELSE) 1576 { 1577 SourceError(source, "#else after #else"); 1578 return qfalse; 1579 } //end if 1580 PC_PushIndent(source, INDENT_ELSE, !skip); 1581 return qtrue; 1582 } //end of the function PC_Directive_else 1583 //============================================================================ 1584 // 1585 // Parameter: - 1586 // Returns: - 1587 // Changes Globals: - 1588 //============================================================================ 1589 int PC_Directive_endif(source_t *source) 1590 { 1591 int type, skip; 1592 1593 PC_PopIndent(source, &type, &skip); 1594 if (!type) 1595 { 1596 SourceError(source, "misplaced #endif"); 1597 return qfalse; 1598 } //end if 1599 return qtrue; 1600 } //end of the function PC_Directive_endif 1601 //============================================================================ 1602 // 1603 // Parameter: - 1604 // Returns: - 1605 // Changes Globals: - 1606 //============================================================================ 1607 typedef struct operator_s 1608 { 1609 int operator; 1610 int priority; 1611 int parentheses; 1612 struct operator_s *prev, *next; 1613 } operator_t; 1614 1615 typedef struct value_s 1616 { 1617 signed long int intvalue; 1618 double floatvalue; 1619 int parentheses; 1620 struct value_s *prev, *next; 1621 } value_t; 1622 1623 int PC_OperatorPriority(int op) 1624 { 1625 switch(op) 1626 { 1627 case P_MUL: return 15; 1628 case P_DIV: return 15; 1629 case P_MOD: return 15; 1630 case P_ADD: return 14; 1631 case P_SUB: return 14; 1632 1633 case P_LOGIC_AND: return 7; 1634 case P_LOGIC_OR: return 6; 1635 case P_LOGIC_GEQ: return 12; 1636 case P_LOGIC_LEQ: return 12; 1637 case P_LOGIC_EQ: return 11; 1638 case P_LOGIC_UNEQ: return 11; 1639 1640 case P_LOGIC_NOT: return 16; 1641 case P_LOGIC_GREATER: return 12; 1642 case P_LOGIC_LESS: return 12; 1643 1644 case P_RSHIFT: return 13; 1645 case P_LSHIFT: return 13; 1646 1647 case P_BIN_AND: return 10; 1648 case P_BIN_OR: return 8; 1649 case P_BIN_XOR: return 9; 1650 case P_BIN_NOT: return 16; 1651 1652 case P_COLON: return 5; 1653 case P_QUESTIONMARK: return 5; 1654 } //end switch 1655 return qfalse; 1656 } //end of the function PC_OperatorPriority 1657 1658 //#define AllocValue() GetClearedMemory(sizeof(value_t)); 1659 //#define FreeValue(val) FreeMemory(val) 1660 //#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t)); 1661 //#define FreeOperator(op) FreeMemory(op); 1662 1663 #define MAX_VALUES 64 1664 #define MAX_OPERATORS 64 1665 #define AllocValue(val) \ 1666 if (numvalues >= MAX_VALUES) { \ 1667 SourceError(source, "out of value space\n"); \ 1668 error = 1; \ 1669 break; \ 1670 } \ 1671 else \ 1672 val = &value_heap[numvalues++]; 1673 #define FreeValue(val) 1674 // 1675 #define AllocOperator(op) \ 1676 if (numoperators >= MAX_OPERATORS) { \ 1677 SourceError(source, "out of operator space\n"); \ 1678 error = 1; \ 1679 break; \ 1680 } \ 1681 else \ 1682 op = &operator_heap[numoperators++]; 1683 #define FreeOperator(op) 1684 1685 int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, 1686 double *floatvalue, int integer) 1687 { 1688 operator_t *o, *firstoperator, *lastoperator; 1689 value_t *v, *firstvalue, *lastvalue, *v1, *v2; 1690 token_t *t; 1691 int brace = 0; 1692 int parentheses = 0; 1693 int error = 0; 1694 int lastwasvalue = 0; 1695 int negativevalue = 0; 1696 int questmarkintvalue = 0; 1697 double questmarkfloatvalue = 0; 1698 int gotquestmarkvalue = qfalse; 1699 int lastoperatortype = 0; 1700 // 1701 operator_t operator_heap[MAX_OPERATORS]; 1702 int numoperators = 0; 1703 value_t value_heap[MAX_VALUES]; 1704 int numvalues = 0; 1705 1706 firstoperator = lastoperator = NULL; 1707 firstvalue = lastvalue = NULL; 1708 if (intvalue) *intvalue = 0; 1709 if (floatvalue) *floatvalue = 0; 1710 for (t = tokens; t; t = t->next) 1711 { 1712 switch(t->type) 1713 { 1714 case TT_NAME: 1715 { 1716 if (lastwasvalue || negativevalue) 1717 { 1718 SourceError(source, "syntax error in #if/#elif"); 1719 error = 1; 1720 break; 1721 } //end if 1722 if (strcmp(t->string, "defined")) 1723 { 1724 SourceError(source, "undefined name %s in #if/#elif", t->string); 1725 error = 1; 1726 break; 1727 } //end if 1728 t = t->next; 1729 if (!strcmp(t->string, "(")) 1730 { 1731 brace = qtrue; 1732 t = t->next; 1733 } //end if 1734 if (!t || t->type != TT_NAME) 1735 { 1736 SourceError(source, "defined without name in #if/#elif"); 1737 error = 1; 1738 break; 1739 } //end if 1740 //v = (value_t *) GetClearedMemory(sizeof(value_t)); 1741 AllocValue(v); 1742 #if DEFINEHASHING 1743 if (PC_FindHashedDefine(source->definehash, t->string)) 1744 #else 1745 if (PC_FindDefine(source->defines, t->string)) 1746 #endif //DEFINEHASHING 1747 { 1748 v->intvalue = 1; 1749 v->floatvalue = 1; 1750 } //end if 1751 else 1752 { 1753 v->intvalue = 0; 1754 v->floatvalue = 0; 1755 } //end else 1756 v->parentheses = parentheses; 1757 v->next = NULL; 1758 v->prev = lastvalue; 1759 if (lastvalue) lastvalue->next = v; 1760 else firstvalue = v; 1761 lastvalue = v; 1762 if (brace) 1763 { 1764 t = t->next; 1765 if (!t || strcmp(t->string, ")")) 1766 { 1767 SourceError(source, "defined without ) in #if/#elif"); 1768 error = 1; 1769 break; 1770 } //end if 1771 } //end if 1772 brace = qfalse; 1773 // defined() creates a value 1774 lastwasvalue = 1; 1775 break; 1776 } //end case 1777 case TT_NUMBER: 1778 { 1779 if (lastwasvalue) 1780 { 1781 SourceError(source, "syntax error in #if/#elif"); 1782 error = 1; 1783 break; 1784 } //end if 1785 //v = (value_t *) GetClearedMemory(sizeof(value_t)); 1786 AllocValue(v); 1787 if (negativevalue) 1788 { 1789 v->intvalue = - (signed int) t->intvalue; 1790 v->floatvalue = - t->floatvalue; 1791 } //end if 1792 else 1793 { 1794 v->intvalue = t->intvalue; 1795 v->floatvalue = t->floatvalue; 1796 } //end else 1797 v->parentheses = parentheses; 1798 v->next = NULL; 1799 v->prev = lastvalue; 1800 if (lastvalue) lastvalue->next = v; 1801 else firstvalue = v; 1802 lastvalue = v; 1803 //last token was a value 1804 lastwasvalue = 1; 1805 // 1806 negativevalue = 0; 1807 break; 1808 } //end case 1809 case TT_PUNCTUATION: 1810 { 1811 if (negativevalue) 1812 { 1813 SourceError(source, "misplaced minus sign in #if/#elif"); 1814 error = 1; 1815 break; 1816 } //end if 1817 if (t->subtype == P_PARENTHESESOPEN) 1818 { 1819 parentheses++; 1820 break; 1821 } //end if 1822 else if (t->subtype == P_PARENTHESESCLOSE) 1823 { 1824 parentheses--; 1825 if (parentheses < 0) 1826 { 1827 SourceError(source, "too many ) in #if/#elsif"); 1828 error = 1; 1829 } //end if 1830 break; 1831 } //end else if 1832 //check for invalid operators on floating point values 1833 if (!integer) 1834 { 1835 if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || 1836 t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || 1837 t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || 1838 t->subtype == P_BIN_XOR) 1839 { 1840 SourceError(source, "illigal operator %s on floating point operands\n", t->string); 1841 error = 1; 1842 break; 1843 } //end if 1844 } //end if 1845 switch(t->subtype) 1846 { 1847 case P_LOGIC_NOT: 1848 case P_BIN_NOT: 1849 { 1850 if (lastwasvalue) 1851 { 1852 SourceError(source, "! or ~ after value in #if/#elif"); 1853 error = 1; 1854 break; 1855 } //end if 1856 break; 1857 } //end case 1858 case P_INC: 1859 case P_DEC: 1860 { 1861 SourceError(source, "++ or -- used in #if/#elif"); 1862 break; 1863 } //end case 1864 case P_SUB: 1865 { 1866 if (!lastwasvalue) 1867 { 1868 negativevalue = 1; 1869 break; 1870 } //end if 1871 } //end case 1872 1873 case P_MUL: 1874 case P_DIV: 1875 case P_MOD: 1876 case P_ADD: 1877 1878 case P_LOGIC_AND: 1879 case P_LOGIC_OR: 1880 case P_LOGIC_GEQ: 1881 case P_LOGIC_LEQ: 1882 case P_LOGIC_EQ: 1883 case P_LOGIC_UNEQ: 1884 1885 case P_LOGIC_GREATER: 1886 case P_LOGIC_LESS: 1887 1888 case P_RSHIFT: 1889 case P_LSHIFT: 1890 1891 case P_BIN_AND: 1892 case P_BIN_OR: 1893 case P_BIN_XOR: 1894 1895 case P_COLON: 1896 case P_QUESTIONMARK: 1897 { 1898 if (!lastwasvalue) 1899 { 1900 SourceError(source, "operator %s after operator in #if/#elif", t->string); 1901 error = 1; 1902 break; 1903 } //end if 1904 break; 1905 } //end case 1906 default: 1907 { 1908 SourceError(source, "invalid operator %s in #if/#elif", t->string); 1909 error = 1; 1910 break; 1911 } //end default 1912 } //end switch 1913 if (!error && !negativevalue) 1914 { 1915 //o = (operator_t *) GetClearedMemory(sizeof(operator_t)); 1916 AllocOperator(o); 1917 o->operator = t->subtype; 1918 o->priority = PC_OperatorPriority(t->subtype); 1919 o->parentheses = parentheses; 1920 o->next = NULL; 1921 o->prev = lastoperator; 1922 if (lastoperator) lastoperator->next = o; 1923 else firstoperator = o; 1924 lastoperator = o; 1925 lastwasvalue = 0; 1926 } //end if 1927 break; 1928 } //end case 1929 default: 1930 { 1931 SourceError(source, "unknown %s in #if/#elif", t->string); 1932 error = 1; 1933 break; 1934 } //end default 1935 } //end switch 1936 if (error) break; 1937 } //end for 1938 if (!error) 1939 { 1940 if (!lastwasvalue) 1941 { 1942 SourceError(source, "trailing operator in #if/#elif"); 1943 error = 1; 1944 } //end if 1945 else if (parentheses) 1946 { 1947 SourceError(source, "too many ( in #if/#elif"); 1948 error = 1; 1949 } //end else if 1950 } //end if 1951 // 1952 gotquestmarkvalue = qfalse; 1953 questmarkintvalue = 0; 1954 questmarkfloatvalue = 0; 1955 //while there are operators 1956 while(!error && firstoperator) 1957 { 1958 v = firstvalue; 1959 for (o = firstoperator; o->next; o = o->next) 1960 { 1961 //if the current operator is nested deeper in parentheses 1962 //than the next operator 1963 if (o->parentheses > o->next->parentheses) break; 1964 //if the current and next operator are nested equally deep in parentheses 1965 if (o->parentheses == o->next->parentheses) 1966 { 1967 //if the priority of the current operator is equal or higher 1968 //than the priority of the next operator 1969 if (o->priority >= o->next->priority) break; 1970 } //end if 1971 //if the arity of the operator isn't equal to 1 1972 if (o->operator != P_LOGIC_NOT 1973 && o->operator != P_BIN_NOT) v = v->next; 1974 //if there's no value or no next value 1975 if (!v) 1976 { 1977 SourceError(source, "mising values in #if/#elif"); 1978 error = 1; 1979 break; 1980 } //end if 1981 } //end for 1982 if (error) break; 1983 v1 = v; 1984 v2 = v->next; 1985 #ifdef DEBUG_EVAL 1986 if (integer) 1987 { 1988 Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue); 1989 if (v2) Log_Write("value2 = %d", v2->intvalue); 1990 } //end if 1991 else 1992 { 1993 Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue); 1994 if (v2) Log_Write("value2 = %f", v2->floatvalue); 1995 } //end else 1996 #endif //DEBUG_EVAL 1997 switch(o->operator) 1998 { 1999 case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; 2000 v1->floatvalue = !v1->floatvalue; break; 2001 case P_BIN_NOT: v1->intvalue = ~v1->intvalue; 2002 break; 2003 case P_MUL: v1->intvalue *= v2->intvalue; 2004 v1->floatvalue *= v2->floatvalue; break; 2005 case P_DIV: if (!v2->intvalue || !v2->floatvalue) 2006 { 2007 SourceError(source, "divide by zero in #if/#elif\n"); 2008 error = 1; 2009 break; 2010 } 2011 v1->intvalue /= v2->intvalue; 2012 v1->floatvalue /= v2->floatvalue; break; 2013 case P_MOD: if (!v2->intvalue) 2014 { 2015 SourceError(source, "divide by zero in #if/#elif\n"); 2016 error = 1; 2017 break; 2018 } 2019 v1->intvalue %= v2->intvalue; break; 2020 case P_ADD: v1->intvalue += v2->intvalue; 2021 v1->floatvalue += v2->floatvalue; break; 2022 case P_SUB: v1->intvalue -= v2->intvalue; 2023 v1->floatvalue -= v2->floatvalue; break; 2024 case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; 2025 v1->floatvalue = v1->floatvalue && v2->floatvalue; break; 2026 case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; 2027 v1->floatvalue = v1->floatvalue || v2->floatvalue; break; 2028 case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; 2029 v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; 2030 case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; 2031 v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; 2032 case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; 2033 v1->floatvalue = v1->floatvalue == v2->floatvalue; break; 2034 case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; 2035 v1->floatvalue = v1->floatvalue != v2->floatvalue; break; 2036 case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; 2037 v1->floatvalue = v1->floatvalue > v2->floatvalue; break; 2038 case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; 2039 v1->floatvalue = v1->floatvalue < v2->floatvalue; break; 2040 case P_RSHIFT: v1->intvalue >>= v2->intvalue; 2041 break; 2042 case P_LSHIFT: v1->intvalue <<= v2->intvalue; 2043 break; 2044 case P_BIN_AND: v1->intvalue &= v2->intvalue; 2045 break; 2046 case P_BIN_OR: v1->intvalue |= v2->intvalue; 2047 break; 2048 case P_BIN_XOR: v1->intvalue ^= v2->intvalue; 2049 break; 2050 case P_COLON: 2051 { 2052 if (!gotquestmarkvalue) 2053 { 2054 SourceError(source, ": without ? in #if/#elif"); 2055 error = 1; 2056 break; 2057 } //end if 2058 if (integer) 2059 { 2060 if (!questmarkintvalue) v1->intvalue = v2->intvalue; 2061 } //end if 2062 else 2063 { 2064 if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; 2065 } //end else 2066 gotquestmarkvalue = qfalse; 2067 break; 2068 } //end case 2069 case P_QUESTIONMARK: 2070 { 2071 if (gotquestmarkvalue) 2072 { 2073 SourceError(source, "? after ? in #if/#elif"); 2074 error = 1; 2075 break; 2076 } //end if 2077 questmarkintvalue = v1->intvalue; 2078 questmarkfloatvalue = v1->floatvalue; 2079 gotquestmarkvalue = qtrue; 2080 break; 2081 } //end if 2082 } //end switch 2083 #ifdef DEBUG_EVAL 2084 if (integer) Log_Write("result value = %d", v1->intvalue); 2085 else Log_Write("result value = %f", v1->floatvalue); 2086 #endif //DEBUG_EVAL 2087 if (error) break; 2088 lastoperatortype = o->operator; 2089 //if not an operator with arity 1 2090 if (o->operator != P_LOGIC_NOT 2091 && o->operator != P_BIN_NOT) 2092 { 2093 //remove the second value if not question mark operator 2094 if (o->operator != P_QUESTIONMARK) v = v->next; 2095 // 2096 if (v->prev) v->prev->next = v->next; 2097 else firstvalue = v->next; 2098 if (v->next) v->next->prev = v->prev; 2099 else lastvalue = v->prev; 2100 //FreeMemory(v); 2101 FreeValue(v); 2102 } //end if 2103 //remove the operator 2104 if (o->prev) o->prev->next = o->next; 2105 else firstoperator = o->next; 2106 if (o->next) o->next->prev = o->prev; 2107 else lastoperator = o->prev; 2108 //FreeMemory(o); 2109 FreeOperator(o); 2110 } //end while 2111 if (firstvalue) 2112 { 2113 if (intvalue) *intvalue = firstvalue->intvalue; 2114 if (floatvalue) *floatvalue = firstvalue->floatvalue; 2115 } //end if 2116 for (o = firstoperator; o; o = lastoperator) 2117 { 2118 lastoperator = o->next; 2119 //FreeMemory(o); 2120 FreeOperator(o); 2121 } //end for 2122 for (v = firstvalue; v; v = lastvalue) 2123 { 2124 lastvalue = v->next; 2125 //FreeMemory(v); 2126 FreeValue(v); 2127 } //end for 2128 if (!error) return qtrue; 2129 if (intvalue) *intvalue = 0; 2130 if (floatvalue) *floatvalue = 0; 2131 return qfalse; 2132 } //end of the function PC_EvaluateTokens 2133 //============================================================================ 2134 // 2135 // Parameter: - 2136 // Returns: - 2137 // Changes Globals: - 2138 //============================================================================ 2139 int PC_Evaluate(source_t *source, signed long int *intvalue, 2140 double *floatvalue, int integer) 2141 { 2142 token_t token, *firsttoken, *lasttoken; 2143 token_t *t, *nexttoken; 2144 define_t *define; 2145 int defined = qfalse; 2146 2147 if (intvalue) *intvalue = 0; 2148 if (floatvalue) *floatvalue = 0; 2149 // 2150 if (!PC_ReadLine(source, &token)) 2151 { 2152 SourceError(source, "no value after #if/#elif"); 2153 return qfalse; 2154 } //end if 2155 firsttoken = NULL; 2156 lasttoken = NULL; 2157 do 2158 { 2159 //if the token is a name 2160 if (token.type == TT_NAME) 2161 { 2162 if (defined) 2163 { 2164 defined = qfalse; 2165 t = PC_CopyToken(&token); 2166 t->next = NULL; 2167 if (lasttoken) lasttoken->next = t; 2168 else firsttoken = t; 2169 lasttoken = t; 2170 } //end if 2171 else if (!strcmp(token.string, "defined")) 2172 { 2173 defined = qtrue; 2174 t = PC_CopyToken(&token); 2175 t->next = NULL; 2176 if (lasttoken) lasttoken->next = t; 2177 else firsttoken = t; 2178 lasttoken = t; 2179 } //end if 2180 else 2181 { 2182 //then it must be a define 2183 #if DEFINEHASHING 2184 define = PC_FindHashedDefine(source->definehash, token.string); 2185 #else 2186 define = PC_FindDefine(source->defines, token.string); 2187 #endif //DEFINEHASHING 2188 if (!define) 2189 { 2190 SourceError(source, "can't evaluate %s, not defined", token.string); 2191 return qfalse; 2192 } //end if 2193 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; 2194 } //end else 2195 } //end if 2196 //if the token is a number or a punctuation 2197 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) 2198 { 2199 t = PC_CopyToken(&token); 2200 t->next = NULL; 2201 if (lasttoken) lasttoken->next = t; 2202 else firsttoken = t; 2203 lasttoken = t; 2204 } //end else 2205 else //can't evaluate the token 2206 { 2207 SourceError(source, "can't evaluate %s", token.string); 2208 return qfalse; 2209 } //end else 2210 } while(PC_ReadLine(source, &token)); 2211 // 2212 if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; 2213 // 2214 #ifdef DEBUG_EVAL 2215 Log_Write("eval:"); 2216 #endif //DEBUG_EVAL 2217 for (t = firsttoken; t; t = nexttoken) 2218 { 2219 #ifdef DEBUG_EVAL 2220 Log_Write(" %s", t->string); 2221 #endif //DEBUG_EVAL 2222 nexttoken = t->next; 2223 PC_FreeToken(t); 2224 } //end for 2225 #ifdef DEBUG_EVAL 2226 if (integer) Log_Write("eval result: %d", *intvalue); 2227 else Log_Write("eval result: %f", *floatvalue); 2228 #endif //DEBUG_EVAL 2229 // 2230 return qtrue; 2231 } //end of the function PC_Evaluate 2232 //============================================================================ 2233 // 2234 // Parameter: - 2235 // Returns: - 2236 // Changes Globals: - 2237 //============================================================================ 2238 int PC_DollarEvaluate(source_t *source, signed long int *intvalue, 2239 double *floatvalue, int integer) 2240 { 2241 int indent, defined = qfalse; 2242 token_t token, *firsttoken, *lasttoken; 2243 token_t *t, *nexttoken; 2244 define_t *define; 2245 2246 if (intvalue) *intvalue = 0; 2247 if (floatvalue) *floatvalue = 0; 2248 // 2249 if (!PC_ReadSourceToken(source, &token)) 2250 { 2251 SourceError(source, "no leading ( after $evalint/$evalfloat"); 2252 return qfalse; 2253 } //end if 2254 if (!PC_ReadSourceToken(source, &token)) 2255 { 2256 SourceError(source, "nothing to evaluate"); 2257 return qfalse; 2258 } //end if 2259 indent = 1; 2260 firsttoken = NULL; 2261 lasttoken = NULL; 2262 do 2263 { 2264 //if the token is a name 2265 if (token.type == TT_NAME) 2266 { 2267 if (defined) 2268 { 2269 defined = qfalse; 2270 t = PC_CopyToken(&token); 2271 t->next = NULL; 2272 if (lasttoken) lasttoken->next = t; 2273 else firsttoken = t; 2274 lasttoken = t; 2275 } //end if 2276 else if (!strcmp(token.string, "defined")) 2277 { 2278 defined = qtrue; 2279 t = PC_CopyToken(&token); 2280 t->next = NULL; 2281 if (lasttoken) lasttoken->next = t; 2282 else firsttoken = t; 2283 lasttoken = t; 2284 } //end if 2285 else 2286 { 2287 //then it must be a define 2288 #if DEFINEHASHING 2289 define = PC_FindHashedDefine(source->definehash, token.string); 2290 #else 2291 define = PC_FindDefine(source->defines, token.string); 2292 #endif //DEFINEHASHING 2293 if (!define) 2294 { 2295 SourceError(source, "can't evaluate %s, not defined", token.string); 2296 return qfalse; 2297 } //end if 2298 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; 2299 } //end else 2300 } //end if 2301 //if the token is a number or a punctuation 2302 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) 2303 { 2304 if (*token.string == '(') indent++; 2305 else if (*token.string == ')') indent--; 2306 if (indent <= 0) break; 2307 t = PC_CopyToken(&token); 2308 t->next = NULL; 2309 if (lasttoken) lasttoken->next = t; 2310 else firsttoken = t; 2311 lasttoken = t; 2312 } //end else 2313 else //can't evaluate the token 2314 { 2315 SourceError(source, "can't evaluate %s", token.string); 2316 return qfalse; 2317 } //end else 2318 } while(PC_ReadSourceToken(source, &token)); 2319 // 2320 if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; 2321 // 2322 #ifdef DEBUG_EVAL 2323 Log_Write("$eval:"); 2324 #endif //DEBUG_EVAL 2325 for (t = firsttoken; t; t = nexttoken) 2326 { 2327 #ifdef DEBUG_EVAL 2328 Log_Write(" %s", t->string); 2329 #endif //DEBUG_EVAL 2330 nexttoken = t->next; 2331 PC_FreeToken(t); 2332 } //end for 2333 #ifdef DEBUG_EVAL 2334 if (integer) Log_Write("$eval result: %d", *intvalue); 2335 else Log_Write("$eval result: %f", *floatvalue); 2336 #endif //DEBUG_EVAL 2337 // 2338 return qtrue; 2339 } //end of the function PC_DollarEvaluate 2340 //============================================================================ 2341 // 2342 // Parameter: - 2343 // Returns: - 2344 // Changes Globals: - 2345 //============================================================================ 2346 int PC_Directive_elif(source_t *source) 2347 { 2348 signed long int value; 2349 int type, skip; 2350 2351 PC_PopIndent(source, &type, &skip); 2352 if (!type || type == INDENT_ELSE) 2353 { 2354 SourceError(source, "misplaced #elif"); 2355 return qfalse; 2356 } //end if 2357 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; 2358 skip = (value == 0); 2359 PC_PushIndent(source, INDENT_ELIF, skip); 2360 return qtrue; 2361 } //end of the function PC_Directive_elif 2362 //============================================================================ 2363 // 2364 // Parameter: - 2365 // Returns: - 2366 // Changes Globals: - 2367 //============================================================================ 2368 int PC_Directive_if(source_t *source) 2369 { 2370 signed long int value; 2371 int skip; 2372 2373 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; 2374 skip = (value == 0); 2375 PC_PushIndent(source, INDENT_IF, skip); 2376 return qtrue; 2377 } //end of the function PC_Directive 2378 //============================================================================ 2379 // 2380 // Parameter: - 2381 // Returns: - 2382 // Changes Globals: - 2383 //============================================================================ 2384 int PC_Directive_line(source_t *source) 2385 { 2386 SourceError(source, "#line directive not supported"); 2387 return qfalse; 2388 } //end of the function PC_Directive_line 2389 //============================================================================ 2390 // 2391 // Parameter: - 2392 // Returns: - 2393 // Changes Globals: - 2394 //============================================================================ 2395 int PC_Directive_error(source_t *source) 2396 { 2397 token_t token; 2398 2399 strcpy(token.string, ""); 2400 PC_ReadSourceToken(source, &token); 2401 SourceError(source, "#error directive: %s", token.string); 2402 return qfalse; 2403 } //end of the function PC_Directive_error 2404 //============================================================================ 2405 // 2406 // Parameter: - 2407 // Returns: - 2408 // Changes Globals: - 2409 //============================================================================ 2410 int PC_Directive_pragma(source_t *source) 2411 { 2412 token_t token; 2413 2414 SourceWarning(source, "#pragma directive not supported"); 2415 while(PC_ReadLine(source, &token)) ; 2416 return qtrue; 2417 } //end of the function PC_Directive_pragma 2418 //============================================================================ 2419 // 2420 // Parameter: - 2421 // Returns: - 2422 // Changes Globals: - 2423 //============================================================================ 2424 void UnreadSignToken(source_t *source) 2425 { 2426 token_t token; 2427 2428 token.line = source->scriptstack->line; 2429 token.whitespace_p = source->scriptstack->script_p; 2430 token.endwhitespace_p = source->scriptstack->script_p; 2431 token.linescrossed = 0; 2432 strcpy(token.string, "-"); 2433 token.type = TT_PUNCTUATION; 2434 token.subtype = P_SUB; 2435 PC_UnreadSourceToken(source, &token); 2436 } //end of the function UnreadSignToken 2437 //============================================================================ 2438 // 2439 // Parameter: - 2440 // Returns: - 2441 // Changes Globals: - 2442 //============================================================================ 2443 int PC_Directive_eval(source_t *source) 2444 { 2445 signed long int value; 2446 token_t token; 2447 2448 if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; 2449 // 2450 token.line = source->scriptstack->line; 2451 token.whitespace_p = source->scriptstack->script_p; 2452 token.endwhitespace_p = source->scriptstack->script_p; 2453 token.linescrossed = 0; 2454 sprintf(token.string, "%d", abs(value)); 2455 token.type = TT_NUMBER; 2456 token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; 2457 PC_UnreadSourceToken(source, &token); 2458 if (value < 0) UnreadSignToken(source); 2459 return qtrue; 2460 } //end of the function PC_Directive_eval 2461 //============================================================================ 2462 // 2463 // Parameter: - 2464 // Returns: - 2465 // Changes Globals: - 2466 //============================================================================ 2467 int PC_Directive_evalfloat(source_t *source) 2468 { 2469 double value; 2470 token_t token; 2471 2472 if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse; 2473 token.line = source->scriptstack->line; 2474 token.whitespace_p = source->scriptstack->script_p; 2475 token.endwhitespace_p = source->scriptstack->script_p; 2476 token.linescrossed = 0; 2477 sprintf(token.string, "%1.2f", fabs(value)); 2478 token.type = TT_NUMBER; 2479 token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; 2480 PC_UnreadSourceToken(source, &token); 2481 if (value < 0) UnreadSignToken(source); 2482 return qtrue; 2483 } //end of the function PC_Directive_evalfloat 2484 //============================================================================ 2485 // 2486 // Parameter: - 2487 // Returns: - 2488 // Changes Globals: - 2489 //============================================================================ 2490 directive_t directives[20] = 2491 { 2492 {"if", PC_Directive_if}, 2493 {"ifdef", PC_Directive_ifdef}, 2494 {"ifndef", PC_Directive_ifndef}, 2495 {"elif", PC_Directive_elif}, 2496 {"else", PC_Directive_else}, 2497 {"endif", PC_Directive_endif}, 2498 {"include", PC_Directive_include}, 2499 {"define", PC_Directive_define}, 2500 {"undef", PC_Directive_undef}, 2501 {"line", PC_Directive_line}, 2502 {"error", PC_Directive_error}, 2503 {"pragma", PC_Directive_pragma}, 2504 {"eval", PC_Directive_eval}, 2505 {"evalfloat", PC_Directive_evalfloat}, 2506 {NULL, NULL} 2507 }; 2508 2509 int PC_ReadDirective(source_t *source) 2510 { 2511 token_t token; 2512 int i; 2513 2514 //read the directive name 2515 if (!PC_ReadSourceToken(source, &token)) 2516 { 2517 SourceError(source, "found # without name"); 2518 return qfalse; 2519 } //end if 2520 //directive name must be on the same line 2521 if (token.linescrossed > 0) 2522 { 2523 PC_UnreadSourceToken(source, &token); 2524 SourceError(source, "found # at end of line"); 2525 return qfalse; 2526 } //end if 2527 //if if is a name 2528 if (token.type == TT_NAME) 2529 { 2530 //find the precompiler directive 2531 for (i = 0; directives[i].name; i++) 2532 { 2533 if (!strcmp(directives[i].name, token.string)) 2534 { 2535 return directives[i].func(source); 2536 } //end if 2537 } //end for 2538 } //end if 2539 SourceError(source, "unknown precompiler directive %s", token.string); 2540 return qfalse; 2541 } //end of the function PC_ReadDirective 2542 //============================================================================ 2543 // 2544 // Parameter: - 2545 // Returns: - 2546 // Changes Globals: - 2547 //============================================================================ 2548 int PC_DollarDirective_evalint(source_t *source) 2549 { 2550 signed long int value; 2551 token_t token; 2552 2553 if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; 2554 // 2555 token.line = source->scriptstack->line; 2556 token.whitespace_p = source->scriptstack->script_p; 2557 token.endwhitespace_p = source->scriptstack->script_p; 2558 token.linescrossed = 0; 2559 sprintf(token.string, "%d", abs(value)); 2560 token.type = TT_NUMBER; 2561 token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; 2562 #ifdef NUMBERVALUE 2563 token.intvalue = value; 2564 token.floatvalue = value; 2565 #endif //NUMBERVALUE 2566 PC_UnreadSourceToken(source, &token); 2567 if (value < 0) UnreadSignToken(source); 2568 return qtrue; 2569 } //end of the function PC_DollarDirective_evalint 2570 //============================================================================ 2571 // 2572 // Parameter: - 2573 // Returns: - 2574 // Changes Globals: - 2575 //============================================================================ 2576 int PC_DollarDirective_evalfloat(source_t *source) 2577 { 2578 double value; 2579 token_t token; 2580 2581 if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; 2582 token.line = source->scriptstack->line; 2583 token.whitespace_p = source->scriptstack->script_p; 2584 token.endwhitespace_p = source->scriptstack->script_p; 2585 token.linescrossed = 0; 2586 sprintf(token.string, "%1.2f", fabs(value)); 2587 token.type = TT_NUMBER; 2588 token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; 2589 #ifdef NUMBERVALUE 2590 token.intvalue = (unsigned long) value; 2591 token.floatvalue = value; 2592 #endif //NUMBERVALUE 2593 PC_UnreadSourceToken(source, &token); 2594 if (value < 0) UnreadSignToken(source); 2595 return qtrue; 2596 } //end of the function PC_DollarDirective_evalfloat 2597 //============================================================================ 2598 // 2599 // Parameter: - 2600 // Returns: - 2601 // Changes Globals: - 2602 //============================================================================ 2603 directive_t dollardirectives[20] = 2604 { 2605 {"evalint", PC_DollarDirective_evalint}, 2606 {"evalfloat", PC_DollarDirective_evalfloat}, 2607 {NULL, NULL} 2608 }; 2609 2610 int PC_ReadDollarDirective(source_t *source) 2611 { 2612 token_t token; 2613 int i; 2614 2615 //read the directive name 2616 if (!PC_ReadSourceToken(source, &token)) 2617 { 2618 SourceError(source, "found $ without name"); 2619 return qfalse; 2620 } //end if 2621 //directive name must be on the same line 2622 if (token.linescrossed > 0) 2623 { 2624 PC_UnreadSourceToken(source, &token); 2625 SourceError(source, "found $ at end of line"); 2626 return qfalse; 2627 } //end if 2628 //if if is a name 2629 if (token.type == TT_NAME) 2630 { 2631 //find the precompiler directive 2632 for (i = 0; dollardirectives[i].name; i++) 2633 { 2634 if (!strcmp(dollardirectives[i].name, token.string)) 2635 { 2636 return dollardirectives[i].func(source); 2637 } //end if 2638 } //end for 2639 } //end if 2640 PC_UnreadSourceToken(source, &token); 2641 SourceError(source, "unknown precompiler directive %s", token.string); 2642 return qfalse; 2643 } //end of the function PC_ReadDirective 2644 2645 #ifdef QUAKEC 2646 //============================================================================ 2647 // 2648 // Parameter: - 2649 // Returns: - 2650 // Changes Globals: - 2651 //============================================================================ 2652 int BuiltinFunction(source_t *source) 2653 { 2654 token_t token; 2655 2656 if (!PC_ReadSourceToken(source, &token)) return qfalse; 2657 if (token.type == TT_NUMBER) 2658 { 2659 PC_UnreadSourceToken(source, &token); 2660 return qtrue; 2661 } //end if 2662 else 2663 { 2664 PC_UnreadSourceToken(source, &token); 2665 return qfalse; 2666 } //end else 2667 } //end of the function BuiltinFunction 2668 //============================================================================ 2669 // 2670 // Parameter: - 2671 // Returns: - 2672 // Changes Globals: - 2673 //============================================================================ 2674 int QuakeCMacro(source_t *source) 2675 { 2676 int i; 2677 token_t token; 2678 2679 if (!PC_ReadSourceToken(source, &token)) return qtrue; 2680 if (token.type != TT_NAME) 2681 { 2682 PC_UnreadSourceToken(source, &token); 2683 return qtrue; 2684 } //end if 2685 //find the precompiler directive 2686 for (i = 0; dollardirectives[i].name; i++) 2687 { 2688 if (!strcmp(dollardirectives[i].name, token.string)) 2689 { 2690 PC_UnreadSourceToken(source, &token); 2691 return qfalse; 2692 } //end if 2693 } //end for 2694 PC_UnreadSourceToken(source, &token); 2695 return qtrue; 2696 } //end of the function QuakeCMacro 2697 #endif //QUAKEC 2698 //============================================================================ 2699 // 2700 // Parameter: - 2701 // Returns: - 2702 // Changes Globals: - 2703 //============================================================================ 2704 int PC_ReadToken(source_t *source, token_t *token) 2705 { 2706 define_t *define; 2707 2708 while(1) 2709 { 2710 if (!PC_ReadSourceToken(source, token)) return qfalse; 2711 //check for precompiler directives 2712 if (token->type == TT_PUNCTUATION && *token->string == '#') 2713 { 2714 #ifdef QUAKEC 2715 if (!BuiltinFunction(source)) 2716 #endif //QUAKC 2717 { 2718 //read the precompiler directive 2719 if (!PC_ReadDirective(source)) return qfalse; 2720 continue; 2721 } //end if 2722 } //end if 2723 if (token->type == TT_PUNCTUATION && *token->string == '$') 2724 { 2725 #ifdef QUAKEC 2726 if (!QuakeCMacro(source)) 2727 #endif //QUAKEC 2728 { 2729 //read the precompiler directive 2730 if (!PC_ReadDollarDirective(source)) return qfalse; 2731 continue; 2732 } //end if 2733 } //end if 2734 // recursively concatenate strings that are behind each other still resolving defines 2735 if (token->type == TT_STRING) 2736 { 2737 token_t newtoken; 2738 if (PC_ReadToken(source, &newtoken)) 2739 { 2740 if (newtoken.type == TT_STRING) 2741 { 2742 token->string[strlen(token->string)-1] = '\0'; 2743 if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN) 2744 { 2745 SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN); 2746 return qfalse; 2747 } 2748 strcat(token->string, newtoken.string+1); 2749 } 2750 else 2751 { 2752 PC_UnreadToken(source, &newtoken); 2753 } 2754 } 2755 } //end if 2756 //if skipping source because of conditional compilation 2757 if (source->skip) continue; 2758 //if the token is a name 2759 if (token->type == TT_NAME) 2760 { 2761 //check if the name is a define macro 2762 #if DEFINEHASHING 2763 define = PC_FindHashedDefine(source->definehash, token->string); 2764 #else 2765 define = PC_FindDefine(source->defines, token->string); 2766 #endif //DEFINEHASHING 2767 //if it is a define macro 2768 if (define) 2769 { 2770 //expand the defined macro 2771 if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse; 2772 continue; 2773 } //end if 2774 } //end if 2775 //copy token for unreading 2776 Com_Memcpy(&source->token, token, sizeof(token_t)); 2777 //found a token 2778 return qtrue; 2779 } //end while 2780 } //end of the function PC_ReadToken 2781 //============================================================================ 2782 // 2783 // Parameter: - 2784 // Returns: - 2785 // Changes Globals: - 2786 //============================================================================ 2787 int PC_ExpectTokenString(source_t *source, char *string) 2788 { 2789 token_t token; 2790 2791 if (!PC_ReadToken(source, &token)) 2792 { 2793 SourceError(source, "couldn't find expected %s", string); 2794 return qfalse; 2795 } //end if 2796 2797 if (strcmp(token.string, string)) 2798 { 2799 SourceError(source, "expected %s, found %s", string, token.string); 2800 return qfalse; 2801 } //end if 2802 return qtrue; 2803 } //end of the function PC_ExpectTokenString 2804 //============================================================================ 2805 // 2806 // Parameter: - 2807 // Returns: - 2808 // Changes Globals: - 2809 //============================================================================ 2810 int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token) 2811 { 2812 char str[MAX_TOKEN]; 2813 2814 if (!PC_ReadToken(source, token)) 2815 { 2816 SourceError(source, "couldn't read expected token"); 2817 return qfalse; 2818 } //end if 2819 2820 if (token->type != type) 2821 { 2822 strcpy(str, ""); 2823 if (type == TT_STRING) strcpy(str, "string"); 2824 if (type == TT_LITERAL) strcpy(str, "literal"); 2825 if (type == TT_NUMBER) strcpy(str, "number"); 2826 if (type == TT_NAME) strcpy(str, "name"); 2827 if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); 2828 SourceError(source, "expected a %s, found %s", str, token->string); 2829 return qfalse; 2830 } //end if 2831 if (token->type == TT_NUMBER) 2832 { 2833 if ((token->subtype & subtype) != subtype) 2834 { 2835 if (subtype & TT_DECIMAL) strcpy(str, "decimal"); 2836 if (subtype & TT_HEX) strcpy(str, "hex"); 2837 if (subtype & TT_OCTAL) strcpy(str, "octal"); 2838 if (subtype & TT_BINARY) strcpy(str, "binary"); 2839 if (subtype & TT_LONG) strcat(str, " long"); 2840 if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); 2841 if (subtype & TT_FLOAT) strcat(str, " float"); 2842 if (subtype & TT_INTEGER) strcat(str, " integer"); 2843 SourceError(source, "expected %s, found %s", str, token->string); 2844 return qfalse; 2845 } //end if 2846 } //end if 2847 else if (token->type == TT_PUNCTUATION) 2848 { 2849 if (token->subtype != subtype) 2850 { 2851 SourceError(source, "found %s", token->string); 2852 return qfalse; 2853 } //end if 2854 } //end else if 2855 return qtrue; 2856 } //end of the function PC_ExpectTokenType 2857 //============================================================================ 2858 // 2859 // Parameter: - 2860 // Returns: - 2861 // Changes Globals: - 2862 //============================================================================ 2863 int PC_ExpectAnyToken(source_t *source, token_t *token) 2864 { 2865 if (!PC_ReadToken(source, token)) 2866 { 2867 SourceError(source, "couldn't read expected token"); 2868 return qfalse; 2869 } //end if 2870 else 2871 { 2872 return qtrue; 2873 } //end else 2874 } //end of the function PC_ExpectAnyToken 2875 //============================================================================ 2876 // 2877 // Parameter: - 2878 // Returns: - 2879 // Changes Globals: - 2880 //============================================================================ 2881 int PC_CheckTokenString(source_t *source, char *string) 2882 { 2883 token_t tok; 2884 2885 if (!PC_ReadToken(source, &tok)) return qfalse; 2886 //if the token is available 2887 if (!strcmp(tok.string, string)) return qtrue; 2888 // 2889 PC_UnreadSourceToken(source, &tok); 2890 return qfalse; 2891 } //end of the function PC_CheckTokenString 2892 //============================================================================ 2893 // 2894 // Parameter: - 2895 // Returns: - 2896 // Changes Globals: - 2897 //============================================================================ 2898 int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token) 2899 { 2900 token_t tok; 2901 2902 if (!PC_ReadToken(source, &tok)) return qfalse; 2903 //if the type matches 2904 if (tok.type == type && 2905 (tok.subtype & subtype) == subtype) 2906 { 2907 Com_Memcpy(token, &tok, sizeof(token_t)); 2908 return qtrue; 2909 } //end if 2910 // 2911 PC_UnreadSourceToken(source, &tok); 2912 return qfalse; 2913 } //end of the function PC_CheckTokenType 2914 //============================================================================ 2915 // 2916 // Parameter: - 2917 // Returns: - 2918 // Changes Globals: - 2919 //============================================================================ 2920 int PC_SkipUntilString(source_t *source, char *string) 2921 { 2922 token_t token; 2923 2924 while(PC_ReadToken(source, &token)) 2925 { 2926 if (!strcmp(token.string, string)) return qtrue; 2927 } //end while 2928 return qfalse; 2929 } //end of the function PC_SkipUntilString 2930 //============================================================================ 2931 // 2932 // Parameter: - 2933 // Returns: - 2934 // Changes Globals: - 2935 //============================================================================ 2936 void PC_UnreadLastToken(source_t *source) 2937 { 2938 PC_UnreadSourceToken(source, &source->token); 2939 } //end of the function PC_UnreadLastToken 2940 //============================================================================ 2941 // 2942 // Parameter: - 2943 // Returns: - 2944 // Changes Globals: - 2945 //============================================================================ 2946 void PC_UnreadToken(source_t *source, token_t *token) 2947 { 2948 PC_UnreadSourceToken(source, token); 2949 } //end of the function PC_UnreadToken 2950 //============================================================================ 2951 // 2952 // Parameter: - 2953 // Returns: - 2954 // Changes Globals: - 2955 //============================================================================ 2956 void PC_SetIncludePath(source_t *source, char *path) 2957 { 2958 strncpy(source->includepath, path, MAX_PATH); 2959 //add trailing path seperator 2960 if (source->includepath[strlen(source->includepath)-1] != '\\' && 2961 source->includepath[strlen(source->includepath)-1] != '/') 2962 { 2963 strcat(source->includepath, PATHSEPERATOR_STR); 2964 } //end if 2965 } //end of the function PC_SetIncludePath 2966 //============================================================================ 2967 // 2968 // Parameter: - 2969 // Returns: - 2970 // Changes Globals: - 2971 //============================================================================ 2972 void PC_SetPunctuations(source_t *source, punctuation_t *p) 2973 { 2974 source->punctuations = p; 2975 } //end of the function PC_SetPunctuations 2976 //============================================================================ 2977 // 2978 // Parameter: - 2979 // Returns: - 2980 // Changes Globals: - 2981 //============================================================================ 2982 source_t *LoadSourceFile(const char *filename) 2983 { 2984 source_t *source; 2985 script_t *script; 2986 2987 PC_InitTokenHeap(); 2988 2989 script = LoadScriptFile(filename); 2990 if (!script) return NULL; 2991 2992 script->next = NULL; 2993 2994 source = (source_t *) GetMemory(sizeof(source_t)); 2995 Com_Memset(source, 0, sizeof(source_t)); 2996 2997 strncpy(source->filename, filename, MAX_PATH); 2998 source->scriptstack = script; 2999 source->tokens = NULL; 3000 source->defines = NULL; 3001 source->indentstack = NULL; 3002 source->skip = 0; 3003 3004 #if DEFINEHASHING 3005 source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); 3006 #endif //DEFINEHASHING 3007 PC_AddGlobalDefinesToSource(source); 3008 return source; 3009 } //end of the function LoadSourceFile 3010 //============================================================================ 3011 // 3012 // Parameter: - 3013 // Returns: - 3014 // Changes Globals: - 3015 //============================================================================ 3016 source_t *LoadSourceMemory(char *ptr, int length, char *name) 3017 { 3018 source_t *source; 3019 script_t *script; 3020 3021 PC_InitTokenHeap(); 3022 3023 script = LoadScriptMemory(ptr, length, name); 3024 if (!script) return NULL; 3025 script->next = NULL; 3026 3027 source = (source_t *) GetMemory(sizeof(source_t)); 3028 Com_Memset(source, 0, sizeof(source_t)); 3029 3030 strncpy(source->filename, name, MAX_PATH); 3031 source->scriptstack = script; 3032 source->tokens = NULL; 3033 source->defines = NULL; 3034 source->indentstack = NULL; 3035 source->skip = 0; 3036 3037 #if DEFINEHASHING 3038 source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); 3039 #endif //DEFINEHASHING 3040 PC_AddGlobalDefinesToSource(source); 3041 return source; 3042 } //end of the function LoadSourceMemory 3043 //============================================================================ 3044 // 3045 // Parameter: - 3046 // Returns: - 3047 // Changes Globals: - 3048 //============================================================================ 3049 void FreeSource(source_t *source) 3050 { 3051 script_t *script; 3052 token_t *token; 3053 define_t *define; 3054 indent_t *indent; 3055 int i; 3056 3057 //PC_PrintDefineHashTable(source->definehash); 3058 //free all the scripts 3059 while(source->scriptstack) 3060 { 3061 script = source->scriptstack; 3062 source->scriptstack = source->scriptstack->next; 3063 FreeScript(script); 3064 } //end for 3065 //free all the tokens 3066 while(source->tokens) 3067 { 3068 token = source->tokens; 3069 source->tokens = source->tokens->next; 3070 PC_FreeToken(token); 3071 } //end for 3072 #if DEFINEHASHING 3073 for (i = 0; i < DEFINEHASHSIZE; i++) 3074 { 3075 while(source->definehash[i]) 3076 { 3077 define = source->definehash[i]; 3078 source->definehash[i] = source->definehash[i]->hashnext; 3079 PC_FreeDefine(define); 3080 } //end while 3081 } //end for 3082 #else //DEFINEHASHING 3083 //free all defines 3084 while(source->defines) 3085 { 3086 define = source->defines; 3087 source->defines = source->defines->next; 3088 PC_FreeDefine(define); 3089 } //end for 3090 #endif //DEFINEHASHING 3091 //free all indents 3092 while(source->indentstack) 3093 { 3094 indent = source->indentstack; 3095 source->indentstack = source->indentstack->next; 3096 FreeMemory(indent); 3097 } //end for 3098 #if DEFINEHASHING 3099 // 3100 if (source->definehash) FreeMemory(source->definehash); 3101 #endif //DEFINEHASHING 3102 //free the source itself 3103 FreeMemory(source); 3104 } //end of the function FreeSource 3105 //============================================================================ 3106 // 3107 // Parameter: - 3108 // Returns: - 3109 // Changes Globals: - 3110 //============================================================================ 3111 3112 #define MAX_SOURCEFILES 64 3113 3114 source_t *sourceFiles[MAX_SOURCEFILES]; 3115 3116 int PC_LoadSourceHandle(const char *filename) 3117 { 3118 source_t *source; 3119 int i; 3120 3121 for (i = 1; i < MAX_SOURCEFILES; i++) 3122 { 3123 if (!sourceFiles[i]) 3124 break; 3125 } //end for 3126 if (i >= MAX_SOURCEFILES) 3127 return 0; 3128 PS_SetBaseFolder(""); 3129 source = LoadSourceFile(filename); 3130 if (!source) 3131 return 0; 3132 sourceFiles[i] = source; 3133 return i; 3134 } //end of the function PC_LoadSourceHandle 3135 //============================================================================ 3136 // 3137 // Parameter: - 3138 // Returns: - 3139 // Changes Globals: - 3140 //============================================================================ 3141 int PC_FreeSourceHandle(int handle) 3142 { 3143 if (handle < 1 || handle >= MAX_SOURCEFILES) 3144 return qfalse; 3145 if (!sourceFiles[handle]) 3146 return qfalse; 3147 3148 FreeSource(sourceFiles[handle]); 3149 sourceFiles[handle] = NULL; 3150 return qtrue; 3151 } //end of the function PC_FreeSourceHandle 3152 //============================================================================ 3153 // 3154 // Parameter: - 3155 // Returns: - 3156 // Changes Globals: - 3157 //============================================================================ 3158 int PC_ReadTokenHandle(int handle, pc_token_t *pc_token) 3159 { 3160 token_t token; 3161 int ret; 3162 3163 if (handle < 1 || handle >= MAX_SOURCEFILES) 3164 return 0; 3165 if (!sourceFiles[handle]) 3166 return 0; 3167 3168 ret = PC_ReadToken(sourceFiles[handle], &token); 3169 strcpy(pc_token->string, token.string); 3170 pc_token->type = token.type; 3171 pc_token->subtype = token.subtype; 3172 pc_token->intvalue = token.intvalue; 3173 pc_token->floatvalue = token.floatvalue; 3174 if (pc_token->type == TT_STRING) 3175 StripDoubleQuotes(pc_token->string); 3176 return ret; 3177 } //end of the function PC_ReadTokenHandle 3178 //============================================================================ 3179 // 3180 // Parameter: - 3181 // Returns: - 3182 // Changes Globals: - 3183 //============================================================================ 3184 int PC_SourceFileAndLine(int handle, char *filename, int *line) 3185 { 3186 if (handle < 1 || handle >= MAX_SOURCEFILES) 3187 return qfalse; 3188 if (!sourceFiles[handle]) 3189 return qfalse; 3190 3191 strcpy(filename, sourceFiles[handle]->filename); 3192 if (sourceFiles[handle]->scriptstack) 3193 *line = sourceFiles[handle]->scriptstack->line; 3194 else 3195 *line = 0; 3196 return qtrue; 3197 } //end of the function PC_SourceFileAndLine 3198 //============================================================================ 3199 // 3200 // Parameter: - 3201 // Returns: - 3202 // Changes Globals: - 3203 //============================================================================ 3204 void PC_SetBaseFolder(char *path) 3205 { 3206 PS_SetBaseFolder(path); 3207 } //end of the function PC_SetBaseFolder 3208 //============================================================================ 3209 // 3210 // Parameter: - 3211 // Returns: - 3212 // Changes Globals: - 3213 //============================================================================ 3214 void PC_CheckOpenSourceHandles(void) 3215 { 3216 int i; 3217 3218 for (i = 1; i < MAX_SOURCEFILES; i++) 3219 { 3220 if (sourceFiles[i]) 3221 { 3222 #ifdef BOTLIB 3223 botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename); 3224 #endif //BOTLIB 3225 } //end if 3226 } //end for 3227 } //end of the function PC_CheckOpenSourceHandles 3228