OSDN Git Service

added new event script type
[zandronum/zandronum-acc.git] / token.c
1 \r
2 //**************************************************************************\r
3 //**\r
4 //** token.c\r
5 //**\r
6 //**************************************************************************\r
7 \r
8 // HEADER FILES ------------------------------------------------------------\r
9 \r
10 #if defined(_WIN32) && !defined(_MSC_VER)\r
11 #define WIN32_LEAN_AND_MEAN\r
12 #include <windows.h>\r
13 #endif\r
14 \r
15 #ifdef __NeXT__\r
16 #include <libc.h>\r
17 #else\r
18 #ifndef unix\r
19 #include <io.h>\r
20 #endif\r
21 #include <limits.h>\r
22 #include <fcntl.h>\r
23 #include <stdlib.h>\r
24 #endif\r
25 #include <stdio.h>\r
26 #include <string.h>\r
27 #include <ctype.h>\r
28 #include "common.h"\r
29 #include "token.h"\r
30 #include "error.h"\r
31 #include "misc.h"\r
32 #include "symbol.h"\r
33 #include "parse.h"\r
34 \r
35 // MACROS ------------------------------------------------------------------\r
36 \r
37 #define NON_HEX_DIGIT 255\r
38 #define MAX_NESTED_SOURCES 16\r
39 \r
40 // TYPES -------------------------------------------------------------------\r
41 \r
42 typedef enum\r
43 {\r
44         CHR_EOF,\r
45         CHR_LETTER,\r
46         CHR_NUMBER,\r
47         CHR_QUOTE,\r
48         CHR_SPECIAL\r
49 } chr_t;\r
50 \r
51 typedef struct\r
52 {\r
53         char *name;\r
54         char *start;\r
55         char *end;\r
56         char *position;\r
57         int line;\r
58         boolean incLineNumber;\r
59         boolean imported;\r
60         enum ImportModes prevMode;\r
61         char lastChar;\r
62 } nestInfo_t;\r
63 \r
64 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------\r
65 \r
66 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------\r
67 \r
68 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------\r
69 \r
70 static int SortKeywords(const void *a, const void *b);\r
71 static void SetLocalIncludePath(char *sourceName);\r
72 static int PopNestedSource(enum ImportModes *prevMode);\r
73 static void ProcessLetterToken(void);\r
74 static void ProcessNumberToken(void);\r
75 static void EvalFixedConstant(int whole);\r
76 static void EvalHexConstant(void);\r
77 static void EvalRadixConstant(void);\r
78 static int DigitValue(char digit, int radix);\r
79 static void ProcessQuoteToken(void);\r
80 static void ProcessSpecialToken(void);\r
81 static boolean CheckForKeyword(void);\r
82 static boolean CheckForLineSpecial(void);\r
83 static boolean CheckForConstant(void);\r
84 static void NextChr(void);\r
85 static void SkipComment(void);\r
86 static void SkipCPPComment(void);\r
87 static void BumpMasterSourceLine(char Chr, boolean clear); // master line - Ty 07jan2000\r
88 static char *AddFileName(const char *name);\r
89 static int OctalChar();\r
90 \r
91 // EXTERNAL DATA DECLARATIONS ----------------------------------------------\r
92 \r
93 // PUBLIC DATA DEFINITIONS -------------------------------------------------\r
94 \r
95 tokenType_t tk_Token;\r
96 int tk_Line;\r
97 int tk_Number;\r
98 char *tk_String;\r
99 int tk_SpecialValue;\r
100 int tk_SpecialArgCount;\r
101 char *tk_SourceName;\r
102 int tk_IncludedLines;\r
103 boolean forSemicolonHack;\r
104 char MasterSourceLine[MAX_STATEMENT_LENGTH+1];  // master line - Ty 07jan2000\r
105 int MasterSourcePos;      // master position - Ty 07jan2000\r
106 int PrevMasterSourcePos;        // previous master position - RH 09feb2000\r
107 boolean ClearMasterSourceLine;  // master clear flag - Ty 07jan2000\r
108 \r
109 // PRIVATE DATA DEFINITIONS ------------------------------------------------\r
110 \r
111 static char Chr;\r
112 static char *FileStart;\r
113 static char *FilePtr;\r
114 static char *FileEnd;\r
115 static boolean SourceOpen;\r
116 static char ASCIIToChrCode[256];\r
117 static byte ASCIIToHexDigit[256];\r
118 static char TokenStringBuffer[MAX_QUOTED_LENGTH];\r
119 static nestInfo_t OpenFiles[MAX_NESTED_SOURCES];\r
120 static boolean AlreadyGot;\r
121 static int NestDepth;\r
122 static boolean IncLineNumber;\r
123 static char *FileNames;\r
124 static size_t FileNamesLen, FileNamesMax;\r
125 \r
126 // Pascal 12/11/08\r
127 // Include paths. Lowest is searched first.\r
128 // Include path 0 is always set to the directory of the file being parsed.\r
129 static char IncludePaths[MAX_INCLUDE_PATHS][MAX_FILE_NAME_LENGTH];\r
130 static int NumIncludePaths;\r
131 \r
132 static struct keyword_s\r
133 {\r
134         char *name;\r
135         tokenType_t token;\r
136 } Keywords[] =\r
137 {\r
138         { "break", TK_BREAK },\r
139         { "case", TK_CASE },\r
140         { "const", TK_CONST },\r
141         { "continue", TK_CONTINUE },\r
142         { "default", TK_DEFAULT },\r
143         { "define", TK_DEFINE },\r
144         { "do", TK_DO },\r
145         { "else", TK_ELSE },\r
146         { "for", TK_FOR },\r
147         { "goto", TK_GOTO },\r
148         { "if", TK_IF },\r
149         { "include", TK_INCLUDE },\r
150         { "int", TK_INT },\r
151         { "open", TK_OPEN },\r
152         { "print", TK_PRINT },\r
153         { "printbold", TK_PRINTBOLD },\r
154         { "log", TK_LOG },\r
155         { "hudmessage", TK_HUDMESSAGE },\r
156         { "hudmessagebold", TK_HUDMESSAGEBOLD },\r
157         { "restart", TK_RESTART },\r
158         { "script", TK_SCRIPT },\r
159         { "special", TK_SPECIAL },\r
160         { "str", TK_STR },\r
161         { "suspend", TK_SUSPEND },\r
162         { "switch", TK_SWITCH },\r
163         { "terminate", TK_TERMINATE },\r
164         { "until", TK_UNTIL },\r
165         { "void", TK_VOID },\r
166         { "while", TK_WHILE },\r
167         { "world", TK_WORLD },\r
168         { "global", TK_GLOBAL },\r
169         // [BC] Start Skulltag tokens.\r
170         { "respawn", TK_RESPAWN },\r
171         { "death", TK_DEATH },\r
172         { "enter", TK_ENTER },\r
173         { "pickup", TK_PICKUP },\r
174         { "bluereturn", TK_BLUERETURN },\r
175         { "redreturn", TK_REDRETURN },\r
176         { "whitereturn", TK_WHITERETURN },\r
177         // [BC] End Skulltag tokens.\r
178         { "nocompact", TK_NOCOMPACT },\r
179         { "lightning", TK_LIGHTNING },\r
180         { "createtranslation", TK_CREATETRANSLATION },\r
181         { "function", TK_FUNCTION },\r
182         { "return", TK_RETURN },\r
183         { "wadauthor", TK_WADAUTHOR },\r
184         { "nowadauthor", TK_NOWADAUTHOR },\r
185         { "acs_executewait", TK_ACSEXECUTEWAIT },\r
186         { "acs_namedexecutewait", TK_ACSNAMEDEXECUTEWAIT },\r
187         { "encryptstrings", TK_ENCRYPTSTRINGS },\r
188         { "import", TK_IMPORT },\r
189         { "library", TK_LIBRARY },\r
190         { "libdefine", TK_LIBDEFINE },\r
191         { "bool", TK_BOOL },\r
192         { "net", TK_NET },\r
193         { "clientside", TK_CLIENTSIDE }, // [BB]\r
194         { "disconnect", TK_DISCONNECT },\r
195         { "event", TK_EVENT }, //[BB]\r
196         { "unloading", TK_UNLOADING },\r
197         { "static", TK_STATIC },\r
198         { "strparam", TK_STRPARAM_EVAL }, // [FDARI]\r
199         { "strcpy", TK_STRCPY }, // [FDARI]\r
200 };\r
201 \r
202 #define NUM_KEYWORDS (sizeof(Keywords)/sizeof(Keywords[0]))\r
203 \r
204 // CODE --------------------------------------------------------------------\r
205 \r
206 //==========================================================================\r
207 //\r
208 // TK_Init\r
209 //\r
210 //==========================================================================\r
211 \r
212 void TK_Init(void)\r
213 {\r
214         int i;\r
215 \r
216         for(i = 0; i < 256; i++)\r
217         {\r
218                 ASCIIToChrCode[i] = CHR_SPECIAL;\r
219                 ASCIIToHexDigit[i] = NON_HEX_DIGIT;\r
220         }\r
221         for(i = '0'; i <= '9'; i++)\r
222         {\r
223                 ASCIIToChrCode[i] = CHR_NUMBER;\r
224                 ASCIIToHexDigit[i] = i-'0';\r
225         }\r
226         for(i = 'A'; i <= 'F'; i++)\r
227         {\r
228                 ASCIIToHexDigit[i] = 10+(i-'A');\r
229         }\r
230         for(i = 'a'; i <= 'f'; i++)\r
231         {\r
232                 ASCIIToHexDigit[i] = 10+(i-'a');\r
233         }\r
234         for(i = 'A'; i <= 'Z'; i++)\r
235         {\r
236                 ASCIIToChrCode[i] = CHR_LETTER;\r
237         }\r
238         for(i = 'a'; i <= 'z'; i++)\r
239         {\r
240                 ASCIIToChrCode[i] = CHR_LETTER;\r
241         }\r
242         ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE;\r
243         ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER;\r
244         ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF;\r
245         tk_String = TokenStringBuffer;\r
246         IncLineNumber = FALSE;\r
247         tk_IncludedLines = 0;\r
248         NumIncludePaths = 1;    // the first path is always the parsed file path - Pascal 12/11/08\r
249         SourceOpen = FALSE;\r
250         *MasterSourceLine = '\0'; // master line - Ty 07jan2000\r
251         MasterSourcePos = 0;      // master position - Ty 07jan2000\r
252         ClearMasterSourceLine = TRUE; // clear the line to start\r
253         qsort (Keywords, NUM_KEYWORDS, sizeof(Keywords[0]), SortKeywords);\r
254         FileNames = MS_Alloc(4096, ERR_OUT_OF_MEMORY);\r
255         FileNamesLen = 0;\r
256         FileNamesMax = 4096;\r
257 }\r
258 \r
259 //==========================================================================\r
260 //\r
261 // SortKeywords\r
262 //\r
263 //==========================================================================\r
264 \r
265 static int SortKeywords(const void *a, const void *b)\r
266 {\r
267         return strcmp (((struct keyword_s *)a)->name,\r
268                 ((struct keyword_s *)b)->name);\r
269 }\r
270 \r
271 //==========================================================================\r
272 //\r
273 // TK_OpenSource\r
274 //\r
275 //==========================================================================\r
276 \r
277 void TK_OpenSource(char *fileName)\r
278 {\r
279         int size;\r
280 \r
281         TK_CloseSource();\r
282         size = MS_LoadFile(fileName, &FileStart);\r
283         tk_SourceName = AddFileName(fileName);\r
284         SetLocalIncludePath(fileName);\r
285         SourceOpen = TRUE;\r
286         FileEnd = FileStart+size;\r
287         FilePtr = FileStart;\r
288         tk_Line = 1;\r
289         tk_Token = TK_NONE;\r
290         AlreadyGot = FALSE;\r
291         NestDepth = 0;\r
292         NextChr();\r
293 }\r
294 \r
295 //==========================================================================\r
296 //\r
297 // AddFileName\r
298 //\r
299 //==========================================================================\r
300 \r
301 static char *AddFileName(const char *name)\r
302 {\r
303         size_t len = strlen(name) + 1;\r
304         char *namespot;\r
305 \r
306         if (FileNamesLen + len > FileNamesMax)\r
307         {\r
308                 FileNames = MS_Alloc(FileNamesMax, ERR_OUT_OF_MEMORY);\r
309                 FileNamesLen = 0;\r
310         }\r
311         namespot = FileNames + FileNamesLen;\r
312         memcpy(namespot, name, len);\r
313         FileNamesLen += len;\r
314         return namespot;\r
315 }\r
316 \r
317 //==========================================================================\r
318 //\r
319 // TK_AddIncludePath\r
320 // This adds an include path with less priority than the ones already added\r
321 // \r
322 // Pascal 12/11/08\r
323 //\r
324 //==========================================================================\r
325 \r
326 void TK_AddIncludePath(char *sourcePath)\r
327 {\r
328         if(NumIncludePaths < MAX_INCLUDE_PATHS)\r
329         {\r
330                 // Add to list\r
331                 strcpy(IncludePaths[NumIncludePaths], sourcePath);\r
332                 \r
333                 // Not ending with directory delimiter?\r
334                 if(!MS_IsDirectoryDelimiter(*(IncludePaths[NumIncludePaths] + strlen(IncludePaths[NumIncludePaths]) - 1)))\r
335                 {\r
336                         // Add a directory delimiter to the include path\r
337                         strcat(IncludePaths[NumIncludePaths], "/");\r
338                 }\r
339                 MS_Message(MSG_DEBUG, "Add include path %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]);\r
340                 NumIncludePaths++;\r
341         }\r
342 }\r
343 \r
344 //==========================================================================\r
345 //\r
346 // TK_AddProgramIncludePath\r
347 // Adds an include path for the directory of the executable.\r
348 //\r
349 //==========================================================================\r
350 \r
351 void TK_AddProgramIncludePath(char *progname)\r
352 {\r
353         if(NumIncludePaths < MAX_INCLUDE_PATHS)\r
354         {\r
355 #ifdef _WIN32\r
356 #ifdef _MSC_VER\r
357 #if _MSC_VER >= 1300\r
358                 if (_get_pgmptr(&progname) != 0)\r
359                 {\r
360                         return;\r
361                 }\r
362 #else\r
363                 progname = _pgmptr;\r
364 #endif\r
365 #else\r
366                 char progbuff[1024];\r
367                 GetModuleFileName(0, progbuff, sizeof(progbuff));\r
368                 progbuff[sizeof(progbuff)-1] = '\0';\r
369                 progname = progbuff;\r
370 #endif\r
371 #else\r
372                 char progbuff[PATH_MAX];\r
373                 if (realpath(progname, progbuff) != NULL)\r
374                 {\r
375                         progname = progbuff;\r
376                 }\r
377 #endif\r
378                 strcpy(IncludePaths[NumIncludePaths], progname);\r
379                 if(MS_StripFilename(IncludePaths[NumIncludePaths]))\r
380                 {\r
381                         MS_Message(MSG_DEBUG, "Program include path is %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]);\r
382                         NumIncludePaths++;\r
383                 }\r
384         }\r
385 }\r
386 \r
387 //==========================================================================\r
388 //\r
389 // SetLocalIncludePath\r
390 // This sets the first include path\r
391 // \r
392 // Pascal 12/11/08\r
393 //\r
394 //==========================================================================\r
395 \r
396 static void SetLocalIncludePath(char *sourceName)\r
397 {\r
398         strcpy(IncludePaths[0], sourceName);\r
399         if(MS_StripFilename(IncludePaths[0]) == NO)\r
400         {\r
401                 IncludePaths[0][0] = 0;\r
402         }\r
403 }\r
404 \r
405 \r
406 //==========================================================================\r
407 //\r
408 // TK_Include\r
409 //\r
410 //==========================================================================\r
411 \r
412 void TK_Include(char *fileName)\r
413 {\r
414         char sourceName[MAX_FILE_NAME_LENGTH];\r
415         int size, i;\r
416         nestInfo_t *info;\r
417         boolean foundfile = FALSE;\r
418         \r
419         MS_Message(MSG_DEBUG, "*Including %s\n", fileName);\r
420         if(NestDepth == MAX_NESTED_SOURCES)\r
421         {\r
422                 ERR_Exit(ERR_INCL_NESTING_TOO_DEEP, YES, fileName);\r
423         }\r
424         info = &OpenFiles[NestDepth++];\r
425         info->name = tk_SourceName;\r
426         info->start = FileStart;\r
427         info->end = FileEnd;\r
428         info->position = FilePtr;\r
429         info->line = tk_Line;\r
430         info->incLineNumber = IncLineNumber;\r
431         info->lastChar = Chr;\r
432         info->imported = NO;\r
433         \r
434         // Pascal 30/11/08\r
435         // Handle absolute paths\r
436         if(MS_IsPathAbsolute(fileName))\r
437         {\r
438 #if defined(_WIN32) || defined(__MSDOS__)\r
439                 sourceName[0] = '\0';\r
440                 if(MS_IsDirectoryDelimiter(fileName[0]))\r
441                 {\r
442                         // The source file is absolute for the drive, but does not\r
443                         // specify a drive. Use the path for the current file to\r
444                         // get the drive letter, if it has one.\r
445                         if(IncludePaths[0][0] != '\0' && IncludePaths[0][1] == ':')\r
446                         {\r
447                                 sourceName[0] = IncludePaths[0][0];\r
448                                 sourceName[1] = ':';\r
449                                 sourceName[2] = '\0';\r
450                         }\r
451                 }\r
452                 strcat(sourceName, fileName);\r
453 #else\r
454                 strcpy(sourceName, fileName);\r
455 #endif\r
456                 foundfile = MS_FileExists(sourceName);\r
457         }\r
458         else\r
459         {\r
460                 // Pascal 12/11/08\r
461                 // Find the file in the include paths\r
462                 for(i = 0; i < NumIncludePaths; i++)\r
463                 {\r
464                         strcpy(sourceName, IncludePaths[i]);\r
465                         strcat(sourceName, fileName);\r
466                         if(MS_FileExists(sourceName))\r
467                         {\r
468                                 foundfile = TRUE;\r
469                                 break;\r
470                         }\r
471                 }\r
472         }\r
473         \r
474         if(!foundfile)\r
475         {\r
476                 ERR_ErrorAt(tk_SourceName, tk_Line);\r
477                 ERR_Exit(ERR_CANT_FIND_INCLUDE, YES, fileName, tk_SourceName, tk_Line);\r
478         }\r
479 \r
480         MS_Message(MSG_DEBUG, "*Include file found at %s\n", sourceName);\r
481 \r
482         // Now change the first include path to the file directory\r
483         SetLocalIncludePath(sourceName);\r
484         \r
485         tk_SourceName = AddFileName(sourceName);\r
486         size = MS_LoadFile(tk_SourceName, &FileStart);\r
487         FileEnd = FileStart+size;\r
488         FilePtr = FileStart;\r
489         tk_Line = 1;\r
490         IncLineNumber = FALSE;\r
491         tk_Token = TK_NONE;\r
492         AlreadyGot = FALSE;\r
493         BumpMasterSourceLine('x',TRUE); // dummy x\r
494         NextChr();\r
495 }\r
496 \r
497 //==========================================================================\r
498 //\r
499 // TK_Import\r
500 //\r
501 //==========================================================================\r
502 \r
503 void TK_Import(char *fileName, enum ImportModes prevMode)\r
504 {\r
505         TK_Include (fileName);\r
506         OpenFiles[NestDepth - 1].imported = YES;\r
507         OpenFiles[NestDepth - 1].prevMode = prevMode;\r
508         ImportMode = IMPORT_Importing;\r
509 }\r
510 \r
511 //==========================================================================\r
512 //\r
513 // PopNestedSource\r
514 //\r
515 //==========================================================================\r
516 \r
517 static int PopNestedSource(enum ImportModes *prevMode)\r
518 {\r
519         nestInfo_t *info;\r
520         \r
521         MS_Message(MSG_DEBUG, "*Leaving %s\n", tk_SourceName);\r
522         free(FileStart);\r
523         SY_FreeConstants(NestDepth);\r
524         tk_IncludedLines += tk_Line;\r
525         info = &OpenFiles[--NestDepth];\r
526         tk_SourceName = info->name;\r
527         FileStart = info->start;\r
528         FileEnd = info->end;\r
529         FilePtr = info->position;\r
530         tk_Line = info->line;\r
531         IncLineNumber = info->incLineNumber;\r
532         Chr = info->lastChar;\r
533         tk_Token = TK_NONE;\r
534         AlreadyGot = FALSE;\r
535         \r
536         // Pascal 12/11/08\r
537         // Set the first include path back to this file directory\r
538         SetLocalIncludePath(tk_SourceName);\r
539         \r
540         *prevMode = info->prevMode;\r
541         return info->imported ? 2 : 0;\r
542 }\r
543 \r
544 //==========================================================================\r
545 //\r
546 // TK_CloseSource\r
547 //\r
548 //==========================================================================\r
549 \r
550 void TK_CloseSource(void)\r
551 {\r
552         int i;\r
553 \r
554         if(SourceOpen)\r
555         {\r
556                 free(FileStart);\r
557                 for(i = 0; i < NestDepth; i++)\r
558                 {\r
559                         free(OpenFiles[i].start);\r
560                 }\r
561                 SourceOpen = FALSE;\r
562         }\r
563 }\r
564 \r
565 //==========================================================================\r
566 //\r
567 // TK_GetDepth\r
568 //\r
569 //==========================================================================\r
570 \r
571 int TK_GetDepth(void)\r
572 {\r
573         return NestDepth;\r
574 }\r
575 \r
576 //==========================================================================\r
577 //\r
578 // TK_NextToken\r
579 //\r
580 //==========================================================================\r
581 \r
582 tokenType_t TK_NextToken(void)\r
583 {\r
584         enum ImportModes prevMode;\r
585         boolean validToken;\r
586 \r
587         if(AlreadyGot == TRUE)\r
588         {\r
589                 int t = MasterSourcePos;\r
590                 MasterSourcePos = PrevMasterSourcePos;\r
591                 PrevMasterSourcePos = t;\r
592                 AlreadyGot = FALSE;\r
593                 return tk_Token;\r
594         }\r
595         validToken = NO;\r
596         PrevMasterSourcePos = MasterSourcePos;\r
597         do\r
598         {\r
599                 while(Chr == ASCII_SPACE)\r
600                 {\r
601                         NextChr();\r
602                 }\r
603                 switch(ASCIIToChrCode[(byte)Chr])\r
604                 {\r
605                 case CHR_EOF:\r
606                         tk_Token = TK_EOF;\r
607                         break;\r
608                 case CHR_LETTER:\r
609                         ProcessLetterToken();\r
610                         break;\r
611                 case CHR_NUMBER:\r
612                         ProcessNumberToken();\r
613                         break;\r
614                 case CHR_QUOTE:\r
615                         ProcessQuoteToken();\r
616                         break;\r
617                 default:\r
618                         ProcessSpecialToken();\r
619                         break;\r
620                 }\r
621                 if(tk_Token == TK_STARTCOMMENT)\r
622                 {\r
623                         SkipComment();\r
624                 }\r
625                 else if(tk_Token == TK_CPPCOMMENT)\r
626                 {\r
627                         SkipCPPComment();\r
628                 }\r
629                 else if((tk_Token == TK_EOF) && (NestDepth > 0))\r
630                 {\r
631                         if (PopNestedSource(&prevMode))\r
632                         {\r
633                                 ImportMode = prevMode;\r
634                                 if(!ExporterFlagged)\r
635                                 {\r
636                                         ERR_Exit(ERR_EXPORTER_NOT_FLAGGED, NO);\r
637                                 }\r
638                                 SY_ClearShared();\r
639                         }\r
640                 }\r
641                 else\r
642                 {\r
643                         validToken = YES;\r
644                 }\r
645         } while(validToken == NO);\r
646         return tk_Token;\r
647 }\r
648 \r
649 //==========================================================================\r
650 //\r
651 // TK_NextCharacter\r
652 //\r
653 //==========================================================================\r
654 \r
655 int TK_NextCharacter(void)\r
656 {\r
657         int c;\r
658 \r
659         while(Chr == ASCII_SPACE)\r
660         {\r
661                 NextChr();\r
662         }\r
663         c = (int)Chr;\r
664         if(c == EOF_CHARACTER)\r
665         {\r
666                 c = -1;\r
667         }\r
668         NextChr();\r
669         return c;\r
670 }\r
671 \r
672 //==========================================================================\r
673 //\r
674 // TK_SkipPast\r
675 //\r
676 //==========================================================================\r
677 \r
678 void TK_SkipPast(tokenType_t token)\r
679 {\r
680         while (tk_Token != token && tk_Token != TK_EOF)\r
681         {\r
682                 TK_NextToken();\r
683         }\r
684         TK_NextToken();\r
685 }\r
686 \r
687 //==========================================================================\r
688 //\r
689 // TK_SkipTo\r
690 //\r
691 //==========================================================================\r
692 \r
693 void TK_SkipTo(tokenType_t token)\r
694 {\r
695         while (tk_Token != token && tk_Token != TK_EOF)\r
696         {\r
697                 TK_NextToken();\r
698         }\r
699 }\r
700 \r
701 //==========================================================================\r
702 //\r
703 // TK_NextTokenMustBe\r
704 //\r
705 //==========================================================================\r
706 \r
707 boolean TK_NextTokenMustBe(tokenType_t token, error_t error)\r
708 {\r
709         if(TK_NextToken() != token)\r
710         {\r
711                 ERR_Error(error, YES);\r
712                 /*\r
713                 if(skipToken == TK_EOF)\r
714                 {\r
715                         ERR_Finish();\r
716                 }\r
717                 else if(skipToken != TK_NONE)\r
718                 {\r
719                         TK_SkipPast(skipToken);\r
720                 }\r
721                 return NO;\r
722                 */\r
723                 ERR_Finish();\r
724         }\r
725         return YES;\r
726 }\r
727 \r
728 //==========================================================================\r
729 //\r
730 // TK_TokenMustBe\r
731 //\r
732 //==========================================================================\r
733 \r
734 boolean TK_TokenMustBe(tokenType_t token, error_t error)\r
735 {\r
736         if (token == TK_SEMICOLON && forSemicolonHack)\r
737         {\r
738                 token = TK_RPAREN;\r
739         }\r
740         if(tk_Token != token)\r
741         {\r
742                 ERR_Error(error, YES);\r
743                 /*\r
744                 if(skipToken == TK_EOF)\r
745                 {\r
746                         ERR_Finish();\r
747                 }\r
748                 else if(skipToken != TK_NONE)\r
749                 {\r
750                         while(tk_Token != skipToken)\r
751                         {\r
752                                 TK_NextToken();\r
753                         }\r
754                 }\r
755                 return NO;\r
756                 */\r
757                 ERR_Finish();\r
758         }\r
759         return YES;\r
760 }\r
761 \r
762 //==========================================================================\r
763 //\r
764 // TK_Member\r
765 //\r
766 //==========================================================================\r
767 \r
768 boolean TK_Member(tokenType_t *list)\r
769 {\r
770         int i;\r
771 \r
772         for(i = 0; list[i] != TK_NONE; i++)\r
773         {\r
774                 if(tk_Token == list[i])\r
775                 {\r
776                         return YES;\r
777                 }\r
778         }\r
779         return NO;\r
780 }\r
781 \r
782 //==========================================================================\r
783 //\r
784 // TK_Undo\r
785 //\r
786 //==========================================================================\r
787 \r
788 void TK_Undo(void)\r
789 {\r
790         if(tk_Token != TK_NONE)\r
791         {\r
792                 if (AlreadyGot == FALSE)\r
793                 {\r
794                         int t = MasterSourcePos;\r
795                         MasterSourcePos = PrevMasterSourcePos;\r
796                         PrevMasterSourcePos = t;\r
797                         AlreadyGot = TRUE;\r
798                 }\r
799         }\r
800 }\r
801 \r
802 //==========================================================================\r
803 //\r
804 // ProcessLetterToken\r
805 //\r
806 //==========================================================================\r
807 \r
808 static void ProcessLetterToken(void)\r
809 {\r
810         int i;\r
811         char *text;\r
812 \r
813         i = 0;\r
814         text = TokenStringBuffer;\r
815         while (ASCIIToChrCode[(byte)Chr] == CHR_LETTER\r
816                 || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER)\r
817         {\r
818                 if(++i == MAX_IDENTIFIER_LENGTH)\r
819                 {\r
820                         ERR_Error(ERR_IDENTIFIER_TOO_LONG, YES);\r
821                 }\r
822                 if(i < MAX_IDENTIFIER_LENGTH)\r
823                 {\r
824                         *text++ = Chr;\r
825                 }\r
826                 NextChr();\r
827         }\r
828         *text = 0;\r
829         MS_StrLwr(TokenStringBuffer);\r
830         if(CheckForKeyword() == FALSE\r
831                 && CheckForLineSpecial() == FALSE\r
832                 && CheckForConstant() == FALSE)\r
833         {\r
834                 tk_Token = TK_IDENTIFIER;\r
835         }\r
836 }\r
837 \r
838 //==========================================================================\r
839 //\r
840 // CheckForKeyword\r
841 //\r
842 //==========================================================================\r
843 \r
844 static boolean CheckForKeyword(void)\r
845 {\r
846         int min, max, probe, lexx;\r
847 \r
848         // [RH] Use a binary search\r
849         min = 0;\r
850         max = NUM_KEYWORDS-1;\r
851         probe = NUM_KEYWORDS/2;\r
852 \r
853         while (max - min >= 0)\r
854         {\r
855                 lexx = strcmp(tk_String, Keywords[probe].name);\r
856                 if(lexx == 0)\r
857                 {\r
858                         tk_Token = Keywords[probe].token;\r
859                         return TRUE;\r
860                 }\r
861                 else if(lexx < 0)\r
862                 {\r
863                         max = probe-1;\r
864                 }\r
865                 else\r
866                 {\r
867                         min = probe+1;\r
868                 }\r
869                 probe = (max-min)/2+min;\r
870         }\r
871         return FALSE;\r
872 }\r
873 \r
874 //==========================================================================\r
875 //\r
876 // CheckForLineSpecial\r
877 //\r
878 //==========================================================================\r
879 \r
880 static boolean CheckForLineSpecial(void)\r
881 {\r
882         symbolNode_t *sym;\r
883 \r
884         sym = SY_FindGlobal(tk_String);\r
885         if(sym == NULL)\r
886         {\r
887                 return FALSE;\r
888         }\r
889         if(sym->type != SY_SPECIAL)\r
890         {\r
891                 return FALSE;\r
892         }\r
893         tk_Token = TK_LINESPECIAL;\r
894         tk_SpecialValue = sym->info.special.value;\r
895         tk_SpecialArgCount = sym->info.special.argCount;\r
896         return TRUE;\r
897 }\r
898 \r
899 //==========================================================================\r
900 //\r
901 // CheckForConstant\r
902 //\r
903 //==========================================================================\r
904 \r
905 static boolean CheckForConstant(void)\r
906 {\r
907         symbolNode_t *sym;\r
908 \r
909         sym = SY_FindGlobal(tk_String);\r
910         if(sym == NULL)\r
911         {\r
912                 return FALSE;\r
913         }\r
914         if(sym->type != SY_CONSTANT)\r
915         {\r
916                 return FALSE;\r
917         }\r
918         tk_Token = TK_NUMBER;\r
919         tk_Number = sym->info.constant.value;\r
920         return TRUE;\r
921 }\r
922 \r
923 //==========================================================================\r
924 //\r
925 // ProcessNumberToken\r
926 //\r
927 //==========================================================================\r
928 \r
929 static void ProcessNumberToken(void)\r
930 {\r
931         char c;\r
932 \r
933         c = Chr;\r
934         NextChr();\r
935         if(c == '0' && (Chr == 'x' || Chr == 'X'))\r
936         { // Hexadecimal constant\r
937                 NextChr();\r
938                 EvalHexConstant();\r
939                 return;\r
940         }\r
941         tk_Number = c-'0';\r
942         while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER)\r
943         {\r
944                 tk_Number = 10*tk_Number+(Chr-'0');\r
945                 NextChr();\r
946         }\r
947         if(Chr == '.')\r
948         { // Fixed point\r
949                 NextChr(); // Skip period\r
950                 EvalFixedConstant(tk_Number);\r
951                 return;\r
952         }\r
953         if(Chr == ASCII_UNDERSCORE)\r
954         {\r
955                 NextChr(); // Skip underscore\r
956                 EvalRadixConstant();\r
957                 return;\r
958         }\r
959         tk_Token = TK_NUMBER;\r
960 }\r
961 \r
962 //==========================================================================\r
963 //\r
964 // EvalFixedConstant\r
965 //\r
966 //==========================================================================\r
967 \r
968 static void EvalFixedConstant(int whole)\r
969 {\r
970         double frac;\r
971         double divisor;\r
972 \r
973         frac = 0;\r
974         divisor = 1;\r
975         while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER)\r
976         {\r
977                 frac = 10*frac+(Chr-'0');\r
978                 divisor *= 10;\r
979                 NextChr();\r
980         }\r
981         tk_Number = (whole<<16)+(int)(65536.0*frac/divisor);\r
982         tk_Token = TK_NUMBER;\r
983 }\r
984 \r
985 //==========================================================================\r
986 //\r
987 // EvalHexConstant\r
988 //\r
989 //==========================================================================\r
990 \r
991 static void EvalHexConstant(void)\r
992 {\r
993         tk_Number = 0;\r
994         while(ASCIIToHexDigit[(byte)Chr] != NON_HEX_DIGIT)\r
995         {\r
996                 tk_Number = (tk_Number<<4)+ASCIIToHexDigit[(byte)Chr];\r
997                 NextChr();\r
998         }\r
999         tk_Token = TK_NUMBER;\r
1000 }\r
1001 \r
1002 //==========================================================================\r
1003 //\r
1004 // EvalRadixConstant\r
1005 //\r
1006 //==========================================================================\r
1007 \r
1008 static void EvalRadixConstant(void)\r
1009 {\r
1010         int radix;\r
1011         int digitVal;\r
1012 \r
1013         radix = tk_Number;\r
1014         if(radix < 2 || radix > 36)\r
1015         {\r
1016                 ERR_Error(ERR_BAD_RADIX_CONSTANT, YES, NULL);\r
1017                 radix = 36;\r
1018         }\r
1019         tk_Number = 0;\r
1020         while((digitVal = DigitValue(Chr, radix)) != -1)\r
1021         {\r
1022                 tk_Number = radix*tk_Number+digitVal;\r
1023                 NextChr();\r
1024         }\r
1025         tk_Token = TK_NUMBER;\r
1026 }\r
1027 \r
1028 //==========================================================================\r
1029 //\r
1030 // DigitValue\r
1031 //\r
1032 // Returns -1 if the digit is not allowed in the specified radix.\r
1033 //\r
1034 //==========================================================================\r
1035 \r
1036 static int DigitValue(char digit, int radix)\r
1037 {\r
1038         digit = toupper(digit);\r
1039         if(digit < '0' || (digit > '9' && digit < 'A') || digit > 'Z')\r
1040         {\r
1041                 return -1;\r
1042         }\r
1043         if(digit > '9')\r
1044         {\r
1045                 digit = 10+digit-'A';\r
1046         }\r
1047         else\r
1048         {\r
1049                 digit -= '0';\r
1050         }\r
1051         if(digit >= radix)\r
1052         {\r
1053                 return -1;\r
1054         }\r
1055         return digit;\r
1056 }\r
1057 \r
1058 //==========================================================================\r
1059 //\r
1060 // ProcessQuoteToken\r
1061 //\r
1062 //==========================================================================\r
1063 \r
1064 static void ProcessQuoteToken(void)\r
1065 {\r
1066         int i;\r
1067         char *text;\r
1068         boolean escaped;\r
1069 \r
1070         i = 0;\r
1071         escaped = FALSE;\r
1072         text = TokenStringBuffer;\r
1073         NextChr();\r
1074         while(Chr != EOF_CHARACTER)\r
1075         {\r
1076                 if(Chr == ASCII_QUOTE && escaped == 0) // [JB]\r
1077                 {\r
1078                         break;\r
1079                 }\r
1080                 if(++i == MAX_QUOTED_LENGTH)\r
1081                 {\r
1082                         ERR_Error(ERR_STRING_TOO_LONG, YES, NULL);\r
1083                 }\r
1084                 if(i < MAX_QUOTED_LENGTH)\r
1085                 {\r
1086                         *text++ = Chr;\r
1087                 }\r
1088                 // escape the character after a backslash [JB]\r
1089                 if(Chr == '\\')\r
1090                         escaped ^= (Chr == '\\');\r
1091                 else\r
1092                         escaped = FALSE;\r
1093                 NextChr();\r
1094         }\r
1095         *text = 0;\r
1096         if(Chr == ASCII_QUOTE)\r
1097         {\r
1098                 NextChr();\r
1099         }\r
1100         tk_Token = TK_STRING;\r
1101 }\r
1102 \r
1103 //==========================================================================\r
1104 //\r
1105 // ProcessSpecialToken\r
1106 //\r
1107 //==========================================================================\r
1108 \r
1109 static void ProcessSpecialToken(void)\r
1110 {\r
1111         char c;\r
1112 \r
1113         c = Chr;\r
1114         NextChr();\r
1115         switch(c)\r
1116         {\r
1117                 case '+':\r
1118                         switch(Chr)\r
1119                         {\r
1120                                 case '=':\r
1121                                         tk_Token = TK_ADDASSIGN;\r
1122                                         NextChr();\r
1123                                         break;\r
1124                                 case '+':\r
1125                                         tk_Token = TK_INC;\r
1126                                         NextChr();\r
1127                                         break;\r
1128                                 default:\r
1129                                         tk_Token = TK_PLUS;\r
1130                                         break;\r
1131                         }\r
1132                         break;\r
1133                 case '-':\r
1134                         switch(Chr)\r
1135                         {\r
1136                                 case '=':\r
1137                                         tk_Token = TK_SUBASSIGN;\r
1138                                         NextChr();\r
1139                                         break;\r
1140                                 case '-':\r
1141                                         tk_Token = TK_DEC;\r
1142                                         NextChr();\r
1143                                         break;\r
1144                                 default:\r
1145                                         tk_Token = TK_MINUS;\r
1146                                         break;\r
1147                         }\r
1148                         break;\r
1149                 case '*':\r
1150                         switch(Chr)\r
1151                         {\r
1152                                 case '=':\r
1153                                         tk_Token = TK_MULASSIGN;\r
1154                                         NextChr();\r
1155                                         break;\r
1156                                 case '/':\r
1157                                         tk_Token = TK_ENDCOMMENT;\r
1158                                         NextChr();\r
1159                                         break;\r
1160                                 default:\r
1161                                         tk_Token = TK_ASTERISK;\r
1162                                         break;\r
1163                         }\r
1164                         break;\r
1165                 case '/':\r
1166                         switch(Chr)\r
1167                         {\r
1168                                 case '=':\r
1169                                         tk_Token = TK_DIVASSIGN;\r
1170                                         NextChr();\r
1171                                         break;\r
1172                                 case '/':\r
1173                                         tk_Token = TK_CPPCOMMENT;\r
1174                                         break;\r
1175                                 case '*':\r
1176                                         tk_Token = TK_STARTCOMMENT;\r
1177                                         NextChr();\r
1178                                         break;\r
1179                                 default:\r
1180                                         tk_Token = TK_SLASH;\r
1181                                         break;\r
1182                         }\r
1183                         break;\r
1184                 case '%':\r
1185                         if(Chr == '=')\r
1186                         {\r
1187                                 tk_Token = TK_MODASSIGN;\r
1188                                 NextChr();\r
1189                         }\r
1190                         else\r
1191                         {\r
1192                                 tk_Token = TK_PERCENT;\r
1193                         }\r
1194                         break;\r
1195                 case '=':\r
1196                         if(Chr == '=')\r
1197                         {\r
1198                                 tk_Token = TK_EQ;\r
1199                                 NextChr();\r
1200                         }\r
1201                         else\r
1202                         {\r
1203                                 tk_Token = TK_ASSIGN;\r
1204                         }\r
1205                         break;\r
1206                 case '<':\r
1207                         if(Chr == '=')\r
1208                         {\r
1209                                 tk_Token = TK_LE;\r
1210                                 NextChr();\r
1211                         }\r
1212                         else if(Chr == '<')\r
1213                         {\r
1214                                 NextChr();\r
1215                                 if(Chr == '=')\r
1216                                 {\r
1217                                         tk_Token = TK_LSASSIGN;\r
1218                                         NextChr();\r
1219                                 }\r
1220                                 else\r
1221                                 {\r
1222                                         tk_Token = TK_LSHIFT;\r
1223                                 }\r
1224                                 \r
1225                         }\r
1226                         else\r
1227                         {\r
1228                                 tk_Token = TK_LT;\r
1229                         }\r
1230                         break;\r
1231                 case '>':\r
1232                         if(Chr == '=')\r
1233                         {\r
1234                                 tk_Token = TK_GE;\r
1235                                 NextChr();\r
1236                         }\r
1237                         else if(Chr == '>')\r
1238                         {\r
1239                                 NextChr();\r
1240                                 if(Chr == '=')\r
1241                                 {\r
1242                                         tk_Token = TK_RSASSIGN;\r
1243                                         NextChr();\r
1244                                 }\r
1245                                 else\r
1246                                 {\r
1247                                         tk_Token = TK_RSHIFT;\r
1248                                 }\r
1249                         }\r
1250                         else\r
1251                         {\r
1252                                 tk_Token = TK_GT;\r
1253                         }\r
1254                         break;\r
1255                 case '!':\r
1256                         if(Chr == '=')\r
1257                         {\r
1258                                 tk_Token = TK_NE;\r
1259                                 NextChr();\r
1260                         }\r
1261                         else\r
1262                         {\r
1263                                 tk_Token = TK_NOT;\r
1264                         }\r
1265                         break;\r
1266                 case '&':\r
1267                         if(Chr == '&')\r
1268                         {\r
1269                                 tk_Token = TK_ANDLOGICAL;\r
1270                                 NextChr();\r
1271                         }\r
1272                         else if(Chr == '=')\r
1273                         {\r
1274                                 tk_Token = TK_ANDASSIGN;\r
1275                                 NextChr();\r
1276                         }\r
1277                         else\r
1278                         {\r
1279                                 tk_Token = TK_ANDBITWISE;\r
1280                         }\r
1281                         break;\r
1282                 case '|':\r
1283                         if(Chr == '|')\r
1284                         {\r
1285                                 tk_Token = TK_ORLOGICAL;\r
1286                                 NextChr();\r
1287                         }\r
1288                         else if(Chr == '=')\r
1289                         {\r
1290                                 tk_Token = TK_ORASSIGN;\r
1291                                 NextChr();\r
1292                         }\r
1293                         else\r
1294                         {\r
1295                                 tk_Token = TK_ORBITWISE;\r
1296                         }\r
1297                         break;\r
1298                 case '(':\r
1299                         tk_Token = TK_LPAREN;\r
1300                         break;\r
1301                 case ')':\r
1302                         tk_Token = TK_RPAREN;\r
1303                         break;\r
1304                 case '{':\r
1305                         tk_Token = TK_LBRACE;\r
1306                         break;\r
1307                 case '}':\r
1308                         tk_Token = TK_RBRACE;\r
1309                         break;\r
1310                 case '[':\r
1311                         tk_Token = TK_LBRACKET;\r
1312                         break;\r
1313                 case ']':\r
1314                         tk_Token = TK_RBRACKET;\r
1315                         break;\r
1316                 case ':':\r
1317                         tk_Token = TK_COLON;\r
1318                         break;\r
1319                 case ';':\r
1320                         tk_Token = TK_SEMICOLON;\r
1321                         break;\r
1322                 case ',':\r
1323                         tk_Token = TK_COMMA;\r
1324                         break;\r
1325                 case '.':\r
1326                         tk_Token = TK_PERIOD;\r
1327                         break;\r
1328                 case '#':\r
1329                         tk_Token = TK_NUMBERSIGN;\r
1330                         break;\r
1331                 case '^':\r
1332                         if(Chr == '=')\r
1333                         {\r
1334                                 tk_Token = TK_EORASSIGN;\r
1335                                 NextChr();\r
1336                         }\r
1337                         else\r
1338                         {\r
1339                                 tk_Token = TK_EORBITWISE;\r
1340                         }\r
1341                         break;\r
1342                 case '~':\r
1343                         tk_Token = TK_TILDE;\r
1344                         break;\r
1345                 case '\'':\r
1346                         if(Chr == '\\')\r
1347                         {\r
1348                                 NextChr();\r
1349                                 switch(Chr)\r
1350                                 {\r
1351                                 case '0': case '1': case '2': case '3':\r
1352                                 case '4': case '5': case '6': case '7':\r
1353                                         tk_Number = OctalChar();\r
1354                                         break;\r
1355                                 case 'x': case 'X':\r
1356                                         NextChr();\r
1357                                         EvalHexConstant();\r
1358                                         if(Chr != '\'')\r
1359                                         {\r
1360                                                 ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL);\r
1361                                         }\r
1362                                         NextChr();\r
1363                                         break;\r
1364                                 case 'a':\r
1365                                         tk_Number = '\a';\r
1366                                         break;\r
1367                                 case 'b':\r
1368                                         tk_Number = '\b';\r
1369                                         break;\r
1370                                 case 't':\r
1371                                         tk_Number = '\t';\r
1372                                         break;\r
1373                                 case 'v':\r
1374                                         tk_Number = '\v';\r
1375                                         break;\r
1376                                 case 'n':\r
1377                                         tk_Number = '\n';\r
1378                                         break;\r
1379                                 case 'f':\r
1380                                         tk_Number = '\f';\r
1381                                         break;\r
1382                                 case 'r':\r
1383                                         tk_Number = '\r';\r
1384                                         break;\r
1385                                 case '\'':\r
1386                                 case '\\':\r
1387                                         tk_Number = Chr;\r
1388                                         break;\r
1389                                 default:\r
1390                                         ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL);\r
1391                                 }\r
1392                                 tk_Token = TK_NUMBER;\r
1393                         }\r
1394                         else if(Chr == '\'')\r
1395                         {\r
1396                                 ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL);\r
1397                         }\r
1398                         else\r
1399                         {\r
1400                                 tk_Number = Chr;\r
1401                                 tk_Token = TK_NUMBER;\r
1402                         }\r
1403                         NextChr();\r
1404                         if(Chr != '\'')\r
1405                         {\r
1406                                 ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL);\r
1407                         }\r
1408                         NextChr();\r
1409                         break;\r
1410                 default:\r
1411                         ERR_Exit(ERR_BAD_CHARACTER, YES, NULL);\r
1412                         break;\r
1413         }\r
1414 }\r
1415 \r
1416 //==========================================================================\r
1417 //\r
1418 // NextChr\r
1419 //\r
1420 //==========================================================================\r
1421 \r
1422 static void NextChr(void)\r
1423 {\r
1424         if(FilePtr >= FileEnd)\r
1425         {\r
1426                 Chr = EOF_CHARACTER;\r
1427                 return;\r
1428         }\r
1429         if(IncLineNumber == TRUE)\r
1430         {\r
1431                 tk_Line++;\r
1432                 IncLineNumber = FALSE;\r
1433                 BumpMasterSourceLine('x',TRUE); // dummy x\r
1434         }\r
1435         Chr = *FilePtr++;\r
1436         if(Chr < ASCII_SPACE && Chr >= 0)       // Allow high ASCII characters\r
1437         {\r
1438                 if(Chr == '\n')\r
1439                 {\r
1440                         IncLineNumber = TRUE;\r
1441                 }\r
1442                 Chr = ASCII_SPACE;\r
1443         }\r
1444         BumpMasterSourceLine(Chr,FALSE);\r
1445 }\r
1446 \r
1447 //==========================================================================\r
1448 //\r
1449 // PeekChr // [JB]\r
1450 //\r
1451 //==========================================================================\r
1452 \r
1453 static int PeekChr(void)\r
1454 {\r
1455         char ch;\r
1456         if(FilePtr >= FileEnd)\r
1457         {\r
1458                 return EOF_CHARACTER;\r
1459         }\r
1460         ch = *FilePtr-1;\r
1461         if(ch < ASCII_SPACE && ch >= 0) // Allow high ASCII characters\r
1462         {\r
1463                 ch = ASCII_SPACE;\r
1464         }\r
1465         return ch;\r
1466 }\r
1467 \r
1468 //==========================================================================\r
1469 //\r
1470 // OctalChar // [JB]\r
1471 //\r
1472 //==========================================================================\r
1473 \r
1474 static int OctalChar() \r
1475 {\r
1476         int digits = 1;\r
1477         int code = Chr - '0';\r
1478         while(digits < 4 && PeekChr() >= '0' && PeekChr() <= '7')\r
1479         {\r
1480                 NextChr();\r
1481                 code = (code << 3) + Chr - '0';\r
1482         }\r
1483         return code;\r
1484 }\r
1485 \r
1486 //==========================================================================\r
1487 //\r
1488 // SkipComment\r
1489 //\r
1490 //==========================================================================\r
1491 \r
1492 void SkipComment(void)\r
1493 {\r
1494         boolean first;\r
1495 \r
1496         first = FALSE;\r
1497         while(Chr != EOF_CHARACTER)\r
1498         {\r
1499                 if(first == TRUE && Chr == '/')\r
1500                 {\r
1501                         break;\r
1502                 }\r
1503                 first = (Chr == '*');\r
1504                 NextChr();\r
1505         }\r
1506         NextChr();\r
1507 }\r
1508 \r
1509 //==========================================================================\r
1510 //\r
1511 // SkipCPPComment\r
1512 //\r
1513 //==========================================================================\r
1514 \r
1515 void SkipCPPComment(void)\r
1516 {\r
1517         while(FilePtr < FileEnd)\r
1518         {\r
1519                 if(*FilePtr++ == '\n')\r
1520                 {\r
1521                         tk_Line++;\r
1522                         BumpMasterSourceLine('x',TRUE); // dummy x\r
1523                         break;\r
1524                 }\r
1525         }\r
1526         NextChr();\r
1527 }\r
1528 \r
1529 //==========================================================================\r
1530 //\r
1531 // BumpMasterSourceLine\r
1532 //\r
1533 //==========================================================================\r
1534 \r
1535 void BumpMasterSourceLine(char Chr, boolean clear) // master line - Ty 07jan2000\r
1536 {\r
1537         if (ClearMasterSourceLine)  // set to clear last time, clear now for first character\r
1538         {\r
1539                 *MasterSourceLine = '\0';\r
1540                 MasterSourcePos = 0;\r
1541                 ClearMasterSourceLine = FALSE;\r
1542         }\r
1543         if (clear)\r
1544         {\r
1545                 ClearMasterSourceLine = TRUE;\r
1546         }\r
1547         else\r
1548         {\r
1549                 if (MasterSourcePos < MAX_STATEMENT_LENGTH)\r
1550                         MasterSourceLine[MasterSourcePos++] = Chr;\r
1551         }\r
1552 }\r
1553 \r
1554 //==========================================================================\r
1555 //\r
1556 // TK_SkipLine\r
1557 //\r
1558 //==========================================================================\r
1559 \r
1560 void TK_SkipLine(void)\r
1561 {\r
1562         char *sourcenow = tk_SourceName;\r
1563         int linenow = tk_Line;\r
1564         do TK_NextToken(); while (tk_Line == linenow && tk_SourceName == sourcenow);\r
1565 }\r