OSDN Git Service

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