]> git.sur5r.net Git - cc65/blob - src/cc65/scanner.c
Merge branch 'master' into kbrepeat
[cc65] / src / cc65 / scanner.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 scanner.c                                 */
4 /*                                                                           */
5 /*                      Source file line info structure                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2010, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <math.h>
42
43 /* common */
44 #include "chartype.h"
45 #include "fp.h"
46 #include "tgttrans.h"
47
48 /* cc65 */
49 #include "datatype.h"
50 #include "error.h"
51 #include "function.h"
52 #include "global.h"
53 #include "hexval.h"
54 #include "ident.h"
55 #include "input.h"
56 #include "litpool.h"
57 #include "preproc.h"
58 #include "scanner.h"
59 #include "standard.h"
60 #include "symtab.h"
61
62
63
64 /*****************************************************************************/
65 /*                                   data                                    */
66 /*****************************************************************************/
67
68
69
70 Token CurTok;           /* The current token */
71 Token NextTok;          /* The next token */
72
73
74
75 /* Token types */
76 enum {
77     TT_C89      = 0x01 << STD_C89,      /* Token valid in C89 */
78     TT_C99      = 0x01 << STD_C99,      /* Token valid in C99 */
79     TT_CC65     = 0x01 << STD_CC65      /* Token valid in cc65 */
80 };
81
82 /* Token table */
83 static const struct Keyword {
84     char*           Key;        /* Keyword name */
85     unsigned char   Tok;        /* The token */
86     unsigned char   Std;        /* Token supported in which standards? */
87 } Keywords [] = {
88     { "_Pragma",        TOK_PRAGMA,     TT_C89 | TT_C99 | TT_CC65  },   /* !! */
89     { "__AX__",         TOK_AX,         TT_C89 | TT_C99 | TT_CC65  },
90     { "__A__",          TOK_A,          TT_C89 | TT_C99 | TT_CC65  },
91     { "__EAX__",        TOK_EAX,        TT_C89 | TT_C99 | TT_CC65  },
92     { "__X__",          TOK_X,          TT_C89 | TT_C99 | TT_CC65  },
93     { "__Y__",          TOK_Y,          TT_C89 | TT_C99 | TT_CC65  },
94     { "__asm__",        TOK_ASM,        TT_C89 | TT_C99 | TT_CC65  },
95     { "__attribute__",  TOK_ATTRIBUTE,  TT_C89 | TT_C99 | TT_CC65  },
96     { "__cdecl__",      TOK_CDECL,      TT_C89 | TT_C99 | TT_CC65  },
97     { "__far__",        TOK_FAR,        TT_C89 | TT_C99 | TT_CC65  },
98     { "__fastcall__",   TOK_FASTCALL,   TT_C89 | TT_C99 | TT_CC65  },
99     { "__inline__",     TOK_INLINE,     TT_C89 | TT_C99 | TT_CC65  },
100     { "__near__",       TOK_NEAR,       TT_C89 | TT_C99 | TT_CC65  },
101     { "asm",            TOK_ASM,                          TT_CC65  },
102     { "auto",           TOK_AUTO,       TT_C89 | TT_C99 | TT_CC65  },
103     { "break",          TOK_BREAK,      TT_C89 | TT_C99 | TT_CC65  },
104     { "case",           TOK_CASE,       TT_C89 | TT_C99 | TT_CC65  },
105     { "cdecl",          TOK_CDECL,                        TT_CC65  },
106     { "char",           TOK_CHAR,       TT_C89 | TT_C99 | TT_CC65  },
107     { "const",          TOK_CONST,      TT_C89 | TT_C99 | TT_CC65  },
108     { "continue",       TOK_CONTINUE,   TT_C89 | TT_C99 | TT_CC65  },
109     { "default",        TOK_DEFAULT,    TT_C89 | TT_C99 | TT_CC65  },
110     { "do",             TOK_DO,         TT_C89 | TT_C99 | TT_CC65  },
111     { "double",         TOK_DOUBLE,     TT_C89 | TT_C99 | TT_CC65  },
112     { "else",           TOK_ELSE,       TT_C89 | TT_C99 | TT_CC65  },
113     { "enum",           TOK_ENUM,       TT_C89 | TT_C99 | TT_CC65  },
114     { "extern",         TOK_EXTERN,     TT_C89 | TT_C99 | TT_CC65  },
115     { "far",            TOK_FAR,                          TT_CC65  },
116     { "fastcall",       TOK_FASTCALL,                     TT_CC65  },
117     { "float",          TOK_FLOAT,      TT_C89 | TT_C99 | TT_CC65  },
118     { "for",            TOK_FOR,        TT_C89 | TT_C99 | TT_CC65  },
119     { "goto",           TOK_GOTO,       TT_C89 | TT_C99 | TT_CC65  },
120     { "if",             TOK_IF,         TT_C89 | TT_C99 | TT_CC65  },
121     { "inline",         TOK_INLINE,              TT_C99 | TT_CC65  },
122     { "int",            TOK_INT,        TT_C89 | TT_C99 | TT_CC65  },
123     { "long",           TOK_LONG,       TT_C89 | TT_C99 | TT_CC65  },
124     { "near",           TOK_NEAR,                         TT_CC65  },
125     { "register",       TOK_REGISTER,   TT_C89 | TT_C99 | TT_CC65  },
126     { "restrict",       TOK_RESTRICT,            TT_C99 | TT_CC65  },
127     { "return",         TOK_RETURN,     TT_C89 | TT_C99 | TT_CC65  },
128     { "short",          TOK_SHORT,      TT_C89 | TT_C99 | TT_CC65  },
129     { "signed",         TOK_SIGNED,     TT_C89 | TT_C99 | TT_CC65  },
130     { "sizeof",         TOK_SIZEOF,     TT_C89 | TT_C99 | TT_CC65  },
131     { "static",         TOK_STATIC,     TT_C89 | TT_C99 | TT_CC65  },
132     { "struct",         TOK_STRUCT,     TT_C89 | TT_C99 | TT_CC65  },
133     { "switch",         TOK_SWITCH,     TT_C89 | TT_C99 | TT_CC65  },
134     { "typedef",        TOK_TYPEDEF,    TT_C89 | TT_C99 | TT_CC65  },
135     { "union",          TOK_UNION,      TT_C89 | TT_C99 | TT_CC65  },
136     { "unsigned",       TOK_UNSIGNED,   TT_C89 | TT_C99 | TT_CC65  },
137     { "void",           TOK_VOID,       TT_C89 | TT_C99 | TT_CC65  },
138     { "volatile",       TOK_VOLATILE,   TT_C89 | TT_C99 | TT_CC65  },
139     { "while",          TOK_WHILE,      TT_C89 | TT_C99 | TT_CC65  },
140 };
141 #define KEY_COUNT       (sizeof (Keywords) / sizeof (Keywords [0]))
142
143
144
145 /* Stuff for determining the type of an integer constant */
146 #define IT_INT          0x01
147 #define IT_UINT         0x02
148 #define IT_LONG         0x04
149 #define IT_ULONG        0x08
150
151
152
153 /*****************************************************************************/
154 /*                                   code                                    */
155 /*****************************************************************************/
156
157
158
159 static int CmpKey (const void* Key, const void* Elem)
160 /* Compare function for bsearch */
161 {
162     return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
163 }
164
165
166
167 static token_t FindKey (const char* Key)
168 /* Find a keyword and return the token. Return IDENT if the token is not a
169 ** keyword.
170 */
171 {
172     struct Keyword* K;
173     K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
174     if (K && (K->Std & (0x01 << IS_Get (&Standard))) != 0) {
175         return K->Tok;
176     } else {
177         return TOK_IDENT;
178     }
179 }
180
181
182
183 static int SkipWhite (void)
184 /* Skip white space in the input stream, reading and preprocessing new lines
185 ** if necessary. Return 0 if end of file is reached, return 1 otherwise.
186 */
187 {
188     while (1) {
189         while (CurC == '\0') {
190             if (NextLine () == 0) {
191                 return 0;
192             }
193             Preprocess ();
194         }
195         if (IsSpace (CurC)) {
196             NextChar ();
197         } else {
198             return 1;
199         }
200     }
201 }
202
203
204
205 int TokIsFuncSpec (const Token* T)
206 /* Return true if the token is a function specifier */
207 {
208     return (T->Tok == TOK_INLINE)   ||
209            (T->Tok == TOK_FASTCALL) || (T->Tok == TOK_CDECL) ||
210            (T->Tok == TOK_NEAR)     || (T->Tok == TOK_FAR);
211 }
212
213
214
215 void SymName (char* S)
216 /* Read a symbol from the input stream. The first character must have been
217 ** checked before calling this function. The buffer is expected to be at
218 ** least of size MAX_IDENTLEN+1.
219 */
220 {
221     unsigned Len = 0;
222     do {
223         if (Len < MAX_IDENTLEN) {
224             ++Len;
225             *S++ = CurC;
226         }
227         NextChar ();
228     } while (IsIdent (CurC) || IsDigit (CurC));
229     *S = '\0';
230 }
231
232
233
234 int IsSym (char* S)
235 /* If a symbol follows, read it and return 1, otherwise return 0 */
236 {
237     if (IsIdent (CurC)) {
238         SymName (S);
239         return 1;
240     } else {
241         return 0;
242     }
243 }
244
245
246
247 static void UnknownChar (char C)
248 /* Error message for unknown character */
249 {
250     Error ("Invalid input character with code %02X", C & 0xFF);
251     NextChar ();                        /* Skip */
252 }
253
254
255
256 static void SetTok (int tok)
257 /* Set NextTok.Tok and bump line ptr */
258 {
259     NextTok.Tok = tok;
260     NextChar ();
261 }
262
263
264
265 static int ParseChar (void)
266 /* Parse a character. Converts escape chars into character codes. */
267 {
268     int C;
269     int HadError;
270     int Count;
271
272     /* Check for escape chars */
273     if (CurC == '\\') {
274         NextChar ();
275         switch (CurC) {
276             case '?':
277                 C = '\?';
278                 break;
279             case 'a':
280                 C = '\a';
281                 break;
282             case 'b':
283                 C = '\b';
284                 break;
285             case 'f':
286                 C = '\f';
287                 break;
288             case 'r':
289                 C = '\r';
290                 break;
291             case 'n':
292                 C = '\n';
293                 break;
294             case 't':
295                 C = '\t';
296                 break;
297             case 'v':
298                 C = '\v';
299                 break;
300             case '\"':
301                 C = '\"';
302                 break;
303             case '\'':
304                 C = '\'';
305                 break;
306             case '\\':
307                 C = '\\';
308                 break;
309             case 'x':
310             case 'X':
311                 /* Hex character constant */
312                 if (!IsXDigit (NextC)) {
313                     Error ("\\x used with no following hex digits");
314                     C = ' ';
315                 } else {
316                     HadError = 0;
317                     C = 0;
318                     while (IsXDigit (NextC)) {
319                         if ((C << 4) >= 256) {
320                             if (!HadError) {
321                                 Error ("Hex character constant out of range");
322                                 HadError = 1;
323                             }
324                         } else {
325                             C = (C << 4) | HexVal (NextC);
326                         }
327                         NextChar ();
328                     }
329                 }
330                 break;
331             case '0':
332             case '1':
333             case '2':
334             case '3':
335             case '4':
336             case '5':
337             case '6':
338             case '7':
339                 /* Octal constant */
340                 Count = 1;
341                 C = HexVal (CurC);
342                 while (IsODigit (NextC) && Count++ < 3) {
343                     C = (C << 3) | HexVal (NextC);
344                     NextChar ();
345                 }
346                 if (C >= 256)
347                     Error ("Octal character constant out of range");
348                 break;
349             default:
350                 Error ("Illegal character constant");
351                 C = ' ';
352                 /* Try to do error recovery, otherwise the compiler will spit
353                 ** out thousands of errors in this place and abort.
354                 */
355                 if (CurC != '\'' && CurC != '\0') {
356                     while (NextC != '\'' && NextC != '\"' && NextC != '\0') {
357                         NextChar ();
358                     }
359                 }
360                 break;
361         }
362     } else {
363         C = CurC;
364     }
365
366     /* Skip the character read */
367     NextChar ();
368
369     /* Do correct sign extension */
370     return SignExtendChar (C);
371 }
372
373
374
375 static void CharConst (void)
376 /* Parse a character constant. */
377 {
378     int C;
379
380     /* Skip the quote */
381     NextChar ();
382
383     /* Get character */
384     C = ParseChar ();
385
386     /* Check for closing quote */
387     if (CurC != '\'') {
388         Error ("`\'' expected");
389     } else {
390         /* Skip the quote */
391         NextChar ();
392     }
393
394     /* Setup values and attributes */
395     NextTok.Tok  = TOK_CCONST;
396
397     /* Translate into target charset */
398     NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
399
400     /* Character constants have type int */
401     NextTok.Type = type_int;
402 }
403
404
405
406 static void StringConst (void)
407 /* Parse a quoted string */
408 {
409     /* String buffer */
410     StrBuf S = AUTO_STRBUF_INITIALIZER;
411
412     /* Assume next token is a string constant */
413     NextTok.Tok  = TOK_SCONST;
414
415     /* Concatenate strings. If at least one of the concenated strings is a wide
416     ** character literal, the whole string is a wide char literal, otherwise
417     ** it's a normal string literal.
418     */
419     while (1) {
420
421         /* Check if this is a normal or a wide char string */
422         if (CurC == 'L' && NextC == '\"') {
423             /* Wide character literal */
424             NextTok.Tok = TOK_WCSCONST;
425             NextChar ();
426             NextChar ();
427         } else if (CurC == '\"') {
428             /* Skip the quote char */
429             NextChar ();
430         } else {
431             /* No string */
432             break;
433         }
434
435         /* Read until end of string */
436         while (CurC != '\"') {
437             if (CurC == '\0') {
438                 Error ("Unexpected newline");
439                 break;
440             }
441             SB_AppendChar (&S, ParseChar ());
442         }
443
444         /* Skip closing quote char if there was one */
445         NextChar ();
446
447         /* Skip white space, read new input */
448         SkipWhite ();
449
450     }
451
452     /* Terminate the string */
453     SB_AppendChar (&S, '\0');
454
455     /* Add the whole string to the literal pool */
456     NextTok.SVal = AddLiteralStr (&S);
457
458     /* Free the buffer */
459     SB_Done (&S);
460 }
461
462
463
464 static void NumericConst (void)
465 /* Parse a numeric constant */
466 {
467     unsigned Base;              /* Temporary number base */
468     unsigned Prefix;            /* Base according to prefix */
469     StrBuf   S = STATIC_STRBUF_INITIALIZER;
470     int      IsFloat;
471     char     C;
472     unsigned DigitVal;
473     unsigned long IVal;         /* Value */
474
475     /* Check for a leading hex or octal prefix and determine the possible
476     ** integer types.
477     */
478     if (CurC == '0') {
479         /* Gobble 0 and examine next char */
480         NextChar ();
481         if (toupper (CurC) == 'X') {
482             Base = Prefix = 16;
483             NextChar ();        /* gobble "x" */
484         } else {
485             Base = 10;          /* Assume 10 for now - see below */
486             Prefix = 8;         /* Actual prefix says octal */
487         }
488     } else {
489         Base  = Prefix = 10;
490     }
491
492     /* Because floating point numbers don't have octal prefixes (a number
493     ** with a leading zero is decimal), we first have to read the number
494     ** before converting it, so we can determine if it's a float or an
495     ** integer.
496     */
497     while (IsXDigit (CurC) && HexVal (CurC) < Base) {
498         SB_AppendChar (&S, CurC);
499         NextChar ();
500     }
501     SB_Terminate (&S);
502
503     /* The following character tells us if we have an integer or floating
504     ** point constant. Note: Hexadecimal floating point constants aren't
505     ** supported in C89.
506     */
507     IsFloat = (CurC == '.' ||
508                (Base == 10 && toupper (CurC) == 'E') ||
509                (Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));
510
511     /* If we don't have a floating point type, an octal prefix results in an
512     ** octal base.
513     */
514     if (!IsFloat && Prefix == 8) {
515         Base = 8;
516     }
517
518     /* Since we do now know the correct base, convert the remembered input
519     ** into a number.
520     */
521     SB_Reset (&S);
522     IVal = 0;
523     while ((C = SB_Get (&S)) != '\0') {
524         DigitVal = HexVal (C);
525         if (DigitVal >= Base) {
526             Error ("Numeric constant contains digits beyond the radix");
527         }
528         IVal = (IVal * Base) + DigitVal;
529     }
530
531     /* We don't need the string buffer any longer */
532     SB_Done (&S);
533
534     /* Distinguish between integer and floating point constants */
535     if (!IsFloat) {
536
537         unsigned Types;
538         int      HaveSuffix;
539
540         /* Check for a suffix and determine the possible types */
541         HaveSuffix = 1;
542         if (toupper (CurC) == 'U') {
543             /* Unsigned type */
544             NextChar ();
545             if (toupper (CurC) != 'L') {
546                 Types = IT_UINT | IT_ULONG;
547             } else {
548                 NextChar ();
549                 Types = IT_ULONG;
550             }
551         } else if (toupper (CurC) == 'L') {
552             /* Long type */
553             NextChar ();
554             if (toupper (CurC) != 'U') {
555                 Types = IT_LONG | IT_ULONG;
556             } else {
557                 NextChar ();
558                 Types = IT_ULONG;
559             }
560         } else {
561             HaveSuffix = 0;
562             if (Prefix == 10) {
563                 /* Decimal constants are of any type but uint */
564                 Types = IT_INT | IT_LONG | IT_ULONG;
565             } else {
566                 /* Octal or hex constants are of any type */
567                 Types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
568             }
569         }
570
571         /* Check the range to determine the type */
572         if (IVal > 0x7FFF) {
573             /* Out of range for int */
574             Types &= ~IT_INT;
575             /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
576             ** allowed, and we don't have a type specifying suffix, emit a
577             ** warning, because the constant is of type long.
578             */
579             if (IVal <= 0xFFFF && (Types & IT_UINT) == 0 && !HaveSuffix) {
580                 Warning ("Constant is long");
581             }
582         }
583         if (IVal > 0xFFFF) {
584             /* Out of range for unsigned int */
585             Types &= ~IT_UINT;
586         }
587         if (IVal > 0x7FFFFFFF) {
588             /* Out of range for long int */
589             Types &= ~IT_LONG;
590         }
591
592         /* Now set the type string to the smallest type in types */
593         if (Types & IT_INT) {
594             NextTok.Type = type_int;
595         } else if (Types & IT_UINT) {
596             NextTok.Type = type_uint;
597         } else if (Types & IT_LONG) {
598             NextTok.Type = type_long;
599         } else {
600             NextTok.Type = type_ulong;
601         }
602
603         /* Set the value and the token */
604         NextTok.IVal = IVal;
605         NextTok.Tok  = TOK_ICONST;
606
607     } else {
608
609         /* Float constant */
610         Double FVal = FP_D_FromInt (IVal);      /* Convert to double */
611
612         /* Check for a fractional part and read it */
613         if (CurC == '.') {
614
615             Double Scale;
616
617             /* Skip the dot */
618             NextChar ();
619
620             /* Read fractional digits */
621             Scale  = FP_D_Make (1.0);
622             while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
623                 /* Get the value of this digit */
624                 Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
625                 /* Add it to the float value */
626                 FVal = FP_D_Add (FVal, FracVal);
627                 /* Scale base */
628                 Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
629                 /* Skip the digit */
630                 NextChar ();
631             }
632         }
633
634         /* Check for an exponent and read it */
635         if ((Base == 16 && toupper (CurC) == 'F') ||
636             (Base == 10 && toupper (CurC) == 'E')) {
637
638             unsigned Digits;
639             unsigned Exp;
640
641             /* Skip the exponent notifier */
642             NextChar ();
643
644             /* Read an optional sign */
645             if (CurC == '-') {
646                 NextChar ();
647             } else if (CurC == '+') {
648                 NextChar ();
649             }
650
651             /* Read exponent digits. Since we support only 32 bit floats
652             ** with a maximum exponent of +-/127, we read the exponent
653             ** part as integer with up to 3 digits and drop the remainder.
654             ** This avoids an overflow of Exp. The exponent is always
655             ** decimal, even for hex float consts.
656             */
657             Digits = 0;
658             Exp    = 0;
659             while (IsDigit (CurC)) {
660                 if (++Digits <= 3) {
661                     Exp = Exp * 10 + HexVal (CurC);
662                 }
663                 NextChar ();
664             }
665
666             /* Check for errors: We must have exponent digits, and not more
667             ** than three.
668             */
669             if (Digits == 0) {
670                 Error ("Floating constant exponent has no digits");
671             } else if (Digits > 3) {
672                 Warning ("Floating constant exponent is too large");
673             }
674
675             /* Scale the exponent and adjust the value accordingly */
676             if (Exp) {
677                 FVal = FP_D_Mul (FVal, FP_D_Make (pow (10, Exp)));
678             }
679         }
680
681         /* Check for a suffix and determine the type of the constant */
682         if (toupper (CurC) == 'F') {
683             NextChar ();
684             NextTok.Type = type_float;
685         } else {
686             NextTok.Type = type_double;
687         }
688
689         /* Set the value and the token */
690         NextTok.FVal = FVal;
691         NextTok.Tok  = TOK_FCONST;
692
693     }
694 }
695
696
697
698 void NextToken (void)
699 /* Get next token from input stream */
700 {
701     ident token;
702
703     /* We have to skip white space here before shifting tokens, since the
704     ** tokens and the current line info is invalid at startup and will get
705     ** initialized by reading the first time from the file. Remember if
706     ** we were at end of input and handle that later.
707     */
708     int GotEOF = (SkipWhite() == 0);
709
710     /* Current token is the lookahead token */
711     if (CurTok.LI) {
712         ReleaseLineInfo (CurTok.LI);
713     }
714     CurTok = NextTok;
715
716     /* When reading the first time from the file, the line info in NextTok,
717     ** which was copied to CurTok is invalid. Since the information from
718     ** the token is used for error messages, we must make it valid.
719     */
720     if (CurTok.LI == 0) {
721         CurTok.LI = UseLineInfo (GetCurLineInfo ());
722     }
723
724     /* Remember the starting position of the next token */
725     NextTok.LI = UseLineInfo (GetCurLineInfo ());
726
727     /* Now handle end of input. */
728     if (GotEOF) {
729         /* End of file reached */
730         NextTok.Tok = TOK_CEOF;
731         return;
732     }
733
734     /* Determine the next token from the lookahead */
735     if (IsDigit (CurC) || (CurC == '.' && IsDigit (NextC))) {
736         /* A number */
737         NumericConst ();
738         return;
739     }
740
741     /* Check for wide character literals */
742     if (CurC == 'L' && NextC == '\"') {
743         StringConst ();
744         return;
745     }
746
747     /* Check for keywords and identifiers */
748     if (IsSym (token)) {
749
750         /* Check for a keyword */
751         if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
752             /* Reserved word found */
753             return;
754         }
755         /* No reserved word, check for special symbols */
756         if (token[0] == '_' && token[1] == '_') {
757             /* Special symbols */
758             if (strcmp (token+2, "FILE__") == 0) {
759                 NextTok.SVal = AddLiteral (GetCurrentFile());
760                 NextTok.Tok  = TOK_SCONST;
761                 return;
762             } else if (strcmp (token+2, "LINE__") == 0) {
763                 NextTok.Tok  = TOK_ICONST;
764                 NextTok.IVal = GetCurrentLine();
765                 NextTok.Type = type_int;
766                 return;
767             } else if (strcmp (token+2, "func__") == 0) {
768                 /* __func__ is only defined in functions */
769                 if (CurrentFunc) {
770                     NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
771                     NextTok.Tok  = TOK_SCONST;
772                     return;
773                 }
774             }
775         }
776
777         /* No reserved word but identifier */
778         strcpy (NextTok.Ident, token);
779         NextTok.Tok = TOK_IDENT;
780         return;
781     }
782
783     /* Monstrous switch statement ahead... */
784     switch (CurC) {
785
786         case '!':
787             NextChar ();
788             if (CurC == '=') {
789                 SetTok (TOK_NE);
790             } else {
791                 NextTok.Tok = TOK_BOOL_NOT;
792             }
793             break;
794
795         case '\"':
796             StringConst ();
797             break;
798
799         case '%':
800             NextChar ();
801             if (CurC == '=') {
802                 SetTok (TOK_MOD_ASSIGN);
803             } else {
804                 NextTok.Tok = TOK_MOD;
805             }
806             break;
807
808         case '&':
809             NextChar ();
810             switch (CurC) {
811                 case '&':
812                     SetTok (TOK_BOOL_AND);
813                     break;
814                 case '=':
815                     SetTok (TOK_AND_ASSIGN);
816                     break;
817                 default:
818                     NextTok.Tok = TOK_AND;
819             }
820             break;
821
822         case '\'':
823             CharConst ();
824             break;
825
826         case '(':
827             SetTok (TOK_LPAREN);
828             break;
829
830         case ')':
831             SetTok (TOK_RPAREN);
832             break;
833
834         case '*':
835             NextChar ();
836             if (CurC == '=') {
837                 SetTok (TOK_MUL_ASSIGN);
838             } else {
839                 NextTok.Tok = TOK_STAR;
840             }
841             break;
842
843         case '+':
844             NextChar ();
845             switch (CurC) {
846                 case '+':
847                     SetTok (TOK_INC);
848                     break;
849                 case '=':
850                     SetTok (TOK_PLUS_ASSIGN);
851                     break;
852                 default:
853                     NextTok.Tok = TOK_PLUS;
854             }
855             break;
856
857         case ',':
858             SetTok (TOK_COMMA);
859             break;
860
861         case '-':
862             NextChar ();
863             switch (CurC) {
864                 case '-':
865                     SetTok (TOK_DEC);
866                     break;
867                 case '=':
868                     SetTok (TOK_MINUS_ASSIGN);
869                     break;
870                 case '>':
871                     SetTok (TOK_PTR_REF);
872                     break;
873                 default:
874                     NextTok.Tok = TOK_MINUS;
875             }
876             break;
877
878         case '.':
879             NextChar ();
880             if (CurC == '.') {
881                 NextChar ();
882                 if (CurC == '.') {
883                     SetTok (TOK_ELLIPSIS);
884                 } else {
885                     UnknownChar (CurC);
886                 }
887             } else {
888                 NextTok.Tok = TOK_DOT;
889             }
890             break;
891
892         case '/':
893             NextChar ();
894             if (CurC == '=') {
895                 SetTok (TOK_DIV_ASSIGN);
896             } else {
897                 NextTok.Tok = TOK_DIV;
898             }
899             break;
900
901         case ':':
902             SetTok (TOK_COLON);
903             break;
904
905         case ';':
906             SetTok (TOK_SEMI);
907             break;
908
909         case '<':
910             NextChar ();
911             switch (CurC) {
912                 case '=':
913                     SetTok (TOK_LE);
914                     break;
915                 case '<':
916                     NextChar ();
917                     if (CurC == '=') {
918                         SetTok (TOK_SHL_ASSIGN);
919                     } else {
920                         NextTok.Tok = TOK_SHL;
921                     }
922                     break;
923                 default:
924                     NextTok.Tok = TOK_LT;
925             }
926             break;
927
928         case '=':
929             NextChar ();
930             if (CurC == '=') {
931                 SetTok (TOK_EQ);
932             } else {
933                 NextTok.Tok = TOK_ASSIGN;
934             }
935             break;
936
937         case '>':
938             NextChar ();
939             switch (CurC) {
940                 case '=':
941                     SetTok (TOK_GE);
942                     break;
943                 case '>':
944                     NextChar ();
945                     if (CurC == '=') {
946                         SetTok (TOK_SHR_ASSIGN);
947                     } else {
948                         NextTok.Tok = TOK_SHR;
949                     }
950                     break;
951                 default:
952                     NextTok.Tok = TOK_GT;
953             }
954             break;
955
956         case '?':
957             SetTok (TOK_QUEST);
958             break;
959
960         case '[':
961             SetTok (TOK_LBRACK);
962             break;
963
964         case ']':
965             SetTok (TOK_RBRACK);
966             break;
967
968         case '^':
969             NextChar ();
970             if (CurC == '=') {
971                 SetTok (TOK_XOR_ASSIGN);
972             } else {
973                 NextTok.Tok = TOK_XOR;
974             }
975             break;
976
977         case '{':
978             SetTok (TOK_LCURLY);
979             break;
980
981         case '|':
982             NextChar ();
983             switch (CurC) {
984                 case '|':
985                     SetTok (TOK_BOOL_OR);
986                     break;
987                 case '=':
988                     SetTok (TOK_OR_ASSIGN);
989                     break;
990                 default:
991                     NextTok.Tok = TOK_OR;
992             }
993             break;
994
995         case '}':
996             SetTok (TOK_RCURLY);
997             break;
998
999         case '~':
1000             SetTok (TOK_COMP);
1001             break;
1002
1003         default:
1004             UnknownChar (CurC);
1005
1006     }
1007
1008 }
1009
1010
1011
1012 void SkipTokens (const token_t* TokenList, unsigned TokenCount)
1013 /* Skip tokens until we reach TOK_CEOF or a token in the given token list.
1014 ** This routine is used for error recovery.
1015 */
1016 {
1017     while (CurTok.Tok != TOK_CEOF) {
1018
1019         /* Check if the current token is in the token list */
1020         unsigned I;
1021         for (I = 0; I < TokenCount; ++I) {
1022             if (CurTok.Tok == TokenList[I]) {
1023                 /* Found a token in the list */
1024                 return;
1025             }
1026         }
1027
1028         /* Not in the list: Skip it */
1029         NextToken ();
1030
1031     }
1032 }
1033
1034
1035
1036 int Consume (token_t Token, const char* ErrorMsg)
1037 /* Eat token if it is the next in the input stream, otherwise print an error
1038 ** message. Returns true if the token was found and false otherwise.
1039 */
1040 {
1041     if (CurTok.Tok == Token) {
1042         NextToken ();
1043         return 1;
1044     } else {
1045         Error ("%s", ErrorMsg);
1046         return 0;
1047     }
1048 }
1049
1050
1051
1052 int ConsumeColon (void)
1053 /* Check for a colon and skip it. */
1054 {
1055     return Consume (TOK_COLON, "`:' expected");
1056 }
1057
1058
1059
1060 int ConsumeSemi (void)
1061 /* Check for a semicolon and skip it. */
1062 {
1063     /* Try do be smart about typos... */
1064     if (CurTok.Tok == TOK_SEMI) {
1065         NextToken ();
1066         return 1;
1067     } else {
1068         Error ("`;' expected");
1069         if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
1070             NextToken ();
1071         }
1072         return 0;
1073     }
1074 }
1075
1076
1077
1078 int ConsumeComma (void)
1079 /* Check for a comma and skip it. */
1080 {
1081     /* Try do be smart about typos... */
1082     if (CurTok.Tok == TOK_COMMA) {
1083         NextToken ();
1084         return 1;
1085     } else {
1086         Error ("`,' expected");
1087         if (CurTok.Tok == TOK_SEMI) {
1088             NextToken ();
1089         }
1090         return 0;
1091     }
1092 }
1093
1094
1095
1096 int ConsumeLParen (void)
1097 /* Check for a left parenthesis and skip it */
1098 {
1099     return Consume (TOK_LPAREN, "`(' expected");
1100 }
1101
1102
1103
1104 int ConsumeRParen (void)
1105 /* Check for a right parenthesis and skip it */
1106 {
1107     return Consume (TOK_RPAREN, "`)' expected");
1108 }
1109
1110
1111
1112 int ConsumeLBrack (void)
1113 /* Check for a left bracket and skip it */
1114 {
1115     return Consume (TOK_LBRACK, "`[' expected");
1116 }
1117
1118
1119
1120 int ConsumeRBrack (void)
1121 /* Check for a right bracket and skip it */
1122 {
1123     return Consume (TOK_RBRACK, "`]' expected");
1124 }
1125
1126
1127
1128 int ConsumeLCurly (void)
1129 /* Check for a left curly brace and skip it */
1130 {
1131     return Consume (TOK_LCURLY, "`{' expected");
1132 }
1133
1134
1135
1136 int ConsumeRCurly (void)
1137 /* Check for a right curly brace and skip it */
1138 {
1139     return Consume (TOK_RCURLY, "`}' expected");
1140 }