]> git.sur5r.net Git - cc65/blob - src/cc65/scanner.c
More preparations for an extension of the calling conventions.
[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
271     /* Check for escape chars */
272     if (CurC == '\\') {
273         NextChar ();
274         switch (CurC) {
275             case '?':
276                 C = '\?';
277                 break;
278             case 'a':
279                 C = '\a';
280                 break;
281             case 'b':
282                 C = '\b';
283                 break;
284             case 'f':
285                 C = '\f';
286                 break;
287             case 'r':
288                 C = '\r';
289                 break;
290             case 'n':
291                 C = '\n';
292                 break;
293             case 't':
294                 C = '\t';
295                 break;
296             case 'v':
297                 C = '\v';
298                 break;
299             case '\"':
300                 C = '\"';
301                 break;
302             case '\'':
303                 C = '\'';
304                 break;
305             case '\\':
306                 C = '\\';
307                 break;
308             case 'x':
309             case 'X':
310                 /* Hex character constant */
311                 if (!IsXDigit (NextC)) {
312                     Error ("\\x used with no following hex digits");
313                     C = ' ';
314                 } else {
315                     HadError = 0;
316                     C = 0;
317                     while (IsXDigit (NextC)) {
318                         if ((C << 4) >= 256) {
319                             if (!HadError) {
320                                 Error ("Hex character constant out of range");
321                                 HadError = 1;
322                             }
323                         } else {
324                             C = (C << 4) | HexVal (NextC);
325                         }
326                         NextChar ();
327                     }
328                 }
329                 break;
330             case '0':
331             case '1':
332             case '2':
333             case '3':
334             case '4':
335             case '5':
336             case '6':
337             case '7':
338                 /* Octal constant */
339                 HadError = 0;
340                 C = HexVal (CurC);
341                 while (IsODigit (NextC)) {
342                     if ((C << 3) >= 256) {
343                         if (!HadError) {
344                             Error ("Octal character constant out of range");
345                             HadError = 1;
346                         }
347                     } else {
348                         C = (C << 3) | HexVal (NextC);
349                     }
350                     NextChar ();
351                 }
352                 break;
353             default:
354                 Error ("Illegal character constant");
355                 C = ' ';
356                 /* Try to do error recovery, otherwise the compiler will spit
357                  * out thousands of errors in this place and abort.
358                  */
359                 if (CurC != '\'' && CurC != '\0') {
360                     while (NextC != '\'' && NextC != '\"' && NextC != '\0') {
361                         NextChar ();
362                     }
363                 }
364                 break;
365         }
366     } else {
367         C = CurC;
368     }
369
370     /* Skip the character read */
371     NextChar ();
372
373     /* Do correct sign extension */
374     return SignExtendChar (C);
375 }
376
377
378
379 static void CharConst (void)
380 /* Parse a character constant. */
381 {
382     int C;
383
384     /* Skip the quote */
385     NextChar ();
386
387     /* Get character */
388     C = ParseChar ();
389
390     /* Check for closing quote */
391     if (CurC != '\'') {
392         Error ("`\'' expected");
393     } else {
394         /* Skip the quote */
395         NextChar ();
396     }
397
398     /* Setup values and attributes */
399     NextTok.Tok  = TOK_CCONST;
400
401     /* Translate into target charset */
402     NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
403
404     /* Character constants have type int */
405     NextTok.Type = type_int;
406 }
407
408
409
410 static void StringConst (void)
411 /* Parse a quoted string */
412 {
413     /* String buffer */
414     StrBuf S = AUTO_STRBUF_INITIALIZER;
415
416     /* Assume next token is a string constant */
417     NextTok.Tok  = TOK_SCONST;
418
419     /* Concatenate strings. If at least one of the concenated strings is a wide
420      * character literal, the whole string is a wide char literal, otherwise
421      * it's a normal string literal.
422      */
423     while (1) {
424
425         /* Check if this is a normal or a wide char string */
426         if (CurC == 'L' && NextC == '\"') {
427             /* Wide character literal */
428             NextTok.Tok = TOK_WCSCONST;
429             NextChar ();
430             NextChar ();
431         } else if (CurC == '\"') {
432             /* Skip the quote char */
433             NextChar ();
434         } else {
435             /* No string */
436             break;
437         }
438
439         /* Read until end of string */
440         while (CurC != '\"') {
441             if (CurC == '\0') {
442                 Error ("Unexpected newline");
443                 break;
444             }
445             SB_AppendChar (&S, ParseChar ());
446         }
447
448         /* Skip closing quote char if there was one */
449         NextChar ();
450
451         /* Skip white space, read new input */
452         SkipWhite ();
453
454     }
455
456     /* Terminate the string */
457     SB_AppendChar (&S, '\0');
458
459     /* Add the whole string to the literal pool */
460     NextTok.SVal = AddLiteralStr (&S);
461
462     /* Free the buffer */
463     SB_Done (&S);
464 }
465
466
467
468 static void NumericConst (void)
469 /* Parse a numeric constant */
470 {
471     unsigned Base;              /* Temporary number base */
472     unsigned Prefix;            /* Base according to prefix */
473     StrBuf   S = STATIC_STRBUF_INITIALIZER;
474     int      IsFloat;
475     char     C;
476     unsigned DigitVal;
477     unsigned long IVal;         /* Value */
478
479     /* Check for a leading hex or octal prefix and determine the possible
480      * integer types.
481      */
482     if (CurC == '0') {
483         /* Gobble 0 and examine next char */
484         NextChar ();
485         if (toupper (CurC) == 'X') {
486             Base = Prefix = 16;
487             NextChar ();        /* gobble "x" */
488         } else {
489             Base = 10;          /* Assume 10 for now - see below */
490             Prefix = 8;         /* Actual prefix says octal */
491         }
492     } else {
493         Base  = Prefix = 10;
494     }
495
496     /* Because floating point numbers don't have octal prefixes (a number
497      * with a leading zero is decimal), we first have to read the number
498      * before converting it, so we can determine if it's a float or an
499      * integer.
500      */
501     while (IsXDigit (CurC) && HexVal (CurC) < Base) {
502         SB_AppendChar (&S, CurC);
503         NextChar ();
504     }
505     SB_Terminate (&S);
506
507     /* The following character tells us if we have an integer or floating
508      * point constant. Note: Hexadecimal floating point constants aren't
509      * supported in C89.
510      */
511     IsFloat = (CurC == '.' ||
512                (Base == 10 && toupper (CurC) == 'E') ||
513                (Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));
514
515     /* If we don't have a floating point type, an octal prefix results in an
516      * octal base.
517      */
518     if (!IsFloat && Prefix == 8) {
519         Base = 8;
520     }
521
522     /* Since we do now know the correct base, convert the remembered input
523      * into a number.
524      */
525     SB_Reset (&S);
526     IVal = 0;
527     while ((C = SB_Get (&S)) != '\0') {
528         DigitVal = HexVal (C);
529         if (DigitVal >= Base) {
530             Error ("Numeric constant contains digits beyond the radix");
531         }
532         IVal = (IVal * Base) + DigitVal;
533     }
534
535     /* We don't need the string buffer any longer */
536     SB_Done (&S);
537
538     /* Distinguish between integer and floating point constants */
539     if (!IsFloat) {
540
541         unsigned Types;
542         int      HaveSuffix;
543
544         /* Check for a suffix and determine the possible types */
545         HaveSuffix = 1;
546         if (toupper (CurC) == 'U') {
547             /* Unsigned type */
548             NextChar ();
549             if (toupper (CurC) != 'L') {
550                 Types = IT_UINT | IT_ULONG;
551             } else {
552                 NextChar ();
553                 Types = IT_ULONG;
554             }
555         } else if (toupper (CurC) == 'L') {
556             /* Long type */
557             NextChar ();
558             if (toupper (CurC) != 'U') {
559                 Types = IT_LONG | IT_ULONG;
560             } else {
561                 NextChar ();
562                 Types = IT_ULONG;
563             }
564         } else {
565             HaveSuffix = 0;
566             if (Prefix == 10) {
567                 /* Decimal constants are of any type but uint */
568                 Types = IT_INT | IT_LONG | IT_ULONG;
569             } else {
570                 /* Octal or hex constants are of any type */
571                 Types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
572             }
573         }
574
575         /* Check the range to determine the type */
576         if (IVal > 0x7FFF) {
577             /* Out of range for int */
578             Types &= ~IT_INT;
579             /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
580              * allowed, and we don't have a type specifying suffix, emit a
581              * warning, because the constant is of type long.
582              */
583             if (IVal <= 0xFFFF && (Types & IT_UINT) == 0 && !HaveSuffix) {
584                 Warning ("Constant is long");
585             }
586         }
587         if (IVal > 0xFFFF) {
588             /* Out of range for unsigned int */
589             Types &= ~IT_UINT;
590         }
591         if (IVal > 0x7FFFFFFF) {
592             /* Out of range for long int */
593             Types &= ~IT_LONG;
594         }
595
596         /* Now set the type string to the smallest type in types */
597         if (Types & IT_INT) {
598             NextTok.Type = type_int;
599         } else if (Types & IT_UINT) {
600             NextTok.Type = type_uint;
601         } else if (Types & IT_LONG) {
602             NextTok.Type = type_long;
603         } else {
604             NextTok.Type = type_ulong;
605         }
606
607         /* Set the value and the token */
608         NextTok.IVal = IVal;
609         NextTok.Tok  = TOK_ICONST;
610
611     } else {
612
613         /* Float constant */
614         Double FVal = FP_D_FromInt (IVal);      /* Convert to double */
615
616         /* Check for a fractional part and read it */
617         if (CurC == '.') {
618
619             Double Scale;
620
621             /* Skip the dot */
622             NextChar ();
623
624             /* Read fractional digits */
625             Scale  = FP_D_Make (1.0);
626             while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
627                 /* Get the value of this digit */
628                 Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
629                 /* Add it to the float value */
630                 FVal = FP_D_Add (FVal, FracVal);
631                 /* Scale base */
632                 Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
633                 /* Skip the digit */
634                 NextChar ();
635             }
636         }
637
638         /* Check for an exponent and read it */
639         if ((Base == 16 && toupper (CurC) == 'F') ||
640             (Base == 10 && toupper (CurC) == 'E')) {
641
642             int Sign;
643             unsigned Digits;
644             unsigned Exp;
645
646             /* Skip the exponent notifier */
647             NextChar ();
648
649             /* Read an optional sign */
650             Sign = 1;
651             if (CurC == '-') {
652                 Sign = -1;
653                 NextChar ();
654             } else if (CurC == '+') {
655                 NextChar ();
656             }
657
658             /* Read exponent digits. Since we support only 32 bit floats
659              * with a maximum exponent of +-/127, we read the exponent
660              * part as integer with up to 3 digits and drop the remainder.
661              * This avoids an overflow of Exp. The exponent is always
662              * decimal, even for hex float consts.
663              */
664             Digits = 0;
665             Exp    = 0;
666             while (IsDigit (CurC)) {
667                 if (++Digits <= 3) {
668                     Exp = Exp * 10 + HexVal (CurC);
669                 }
670                 NextChar ();
671             }
672
673             /* Check for errors: We must have exponent digits, and not more
674              * than three.
675              */
676             if (Digits == 0) {
677                 Error ("Floating constant exponent has no digits");
678             } else if (Digits > 3) {
679                 Warning ("Floating constant exponent is too large");
680             }
681
682             /* Scale the exponent and adjust the value accordingly */
683             if (Exp) {
684                 FVal = FP_D_Mul (FVal, FP_D_Make (pow (10, Exp)));
685             }
686         }
687
688         /* Check for a suffix and determine the type of the constant */
689         if (toupper (CurC) == 'F') {
690             NextChar ();
691             NextTok.Type = type_float;
692         } else {
693             NextTok.Type = type_double;
694         }
695
696         /* Set the value and the token */
697         NextTok.FVal = FVal;
698         NextTok.Tok  = TOK_FCONST;
699
700     }
701 }
702
703
704
705 void NextToken (void)
706 /* Get next token from input stream */
707 {
708     ident token;
709
710     /* We have to skip white space here before shifting tokens, since the
711      * tokens and the current line info is invalid at startup and will get
712      * initialized by reading the first time from the file. Remember if
713      * we were at end of input and handle that later.
714      */
715     int GotEOF = (SkipWhite() == 0);
716
717     /* Current token is the lookahead token */
718     if (CurTok.LI) {
719         ReleaseLineInfo (CurTok.LI);
720     }
721     CurTok = NextTok;
722
723     /* When reading the first time from the file, the line info in NextTok,
724      * which was copied to CurTok is invalid. Since the information from
725      * the token is used for error messages, we must make it valid.
726      */
727     if (CurTok.LI == 0) {
728         CurTok.LI = UseLineInfo (GetCurLineInfo ());
729     }
730
731     /* Remember the starting position of the next token */
732     NextTok.LI = UseLineInfo (GetCurLineInfo ());
733
734     /* Now handle end of input. */
735     if (GotEOF) {
736         /* End of file reached */
737         NextTok.Tok = TOK_CEOF;
738         return;
739     }
740
741     /* Determine the next token from the lookahead */
742     if (IsDigit (CurC) || (CurC == '.' && IsDigit (NextC))) {
743         /* A number */
744         NumericConst ();
745         return;
746     }
747
748     /* Check for wide character literals */
749     if (CurC == 'L' && NextC == '\"') {
750         StringConst ();
751         return;
752     }
753
754     /* Check for keywords and identifiers */
755     if (IsSym (token)) {
756
757         /* Check for a keyword */
758         if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
759             /* Reserved word found */
760             return;
761         }
762         /* No reserved word, check for special symbols */
763         if (token[0] == '_' && token[1] == '_') {
764             /* Special symbols */
765             if (strcmp (token+2, "FILE__") == 0) {
766                 NextTok.SVal = AddLiteral (GetCurrentFile());
767                 NextTok.Tok  = TOK_SCONST;
768                 return;
769             } else if (strcmp (token+2, "LINE__") == 0) {
770                 NextTok.Tok  = TOK_ICONST;
771                 NextTok.IVal = GetCurrentLine();
772                 NextTok.Type = type_int;
773                 return;
774             } else if (strcmp (token+2, "func__") == 0) {
775                 /* __func__ is only defined in functions */
776                 if (CurrentFunc) {
777                     NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
778                     NextTok.Tok  = TOK_SCONST;
779                     return;
780                 }
781             }
782         }
783
784         /* No reserved word but identifier */
785         strcpy (NextTok.Ident, token);
786         NextTok.Tok = TOK_IDENT;
787         return;
788     }
789
790     /* Monstrous switch statement ahead... */
791     switch (CurC) {
792
793         case '!':
794             NextChar ();
795             if (CurC == '=') {
796                 SetTok (TOK_NE);
797             } else {
798                 NextTok.Tok = TOK_BOOL_NOT;
799             }
800             break;
801
802         case '\"':
803             StringConst ();
804             break;
805
806         case '%':
807             NextChar ();
808             if (CurC == '=') {
809                 SetTok (TOK_MOD_ASSIGN);
810             } else {
811                 NextTok.Tok = TOK_MOD;
812             }
813             break;
814
815         case '&':
816             NextChar ();
817             switch (CurC) {
818                 case '&':
819                     SetTok (TOK_BOOL_AND);
820                     break;
821                 case '=':
822                     SetTok (TOK_AND_ASSIGN);
823                     break;
824                 default:
825                     NextTok.Tok = TOK_AND;
826             }
827             break;
828
829         case '\'':
830             CharConst ();
831             break;
832
833         case '(':
834             SetTok (TOK_LPAREN);
835             break;
836
837         case ')':
838             SetTok (TOK_RPAREN);
839             break;
840
841         case '*':
842             NextChar ();
843             if (CurC == '=') {
844                 SetTok (TOK_MUL_ASSIGN);
845             } else {
846                 NextTok.Tok = TOK_STAR;
847             }
848             break;
849
850         case '+':
851             NextChar ();
852             switch (CurC) {
853                 case '+':
854                     SetTok (TOK_INC);
855                     break;
856                 case '=':
857                     SetTok (TOK_PLUS_ASSIGN);
858                     break;
859                 default:
860                     NextTok.Tok = TOK_PLUS;
861             }
862             break;
863
864         case ',':
865             SetTok (TOK_COMMA);
866             break;
867
868         case '-':
869             NextChar ();
870             switch (CurC) {
871                 case '-':
872                     SetTok (TOK_DEC);
873                     break;
874                 case '=':
875                     SetTok (TOK_MINUS_ASSIGN);
876                     break;
877                 case '>':
878                     SetTok (TOK_PTR_REF);
879                     break;
880                 default:
881                     NextTok.Tok = TOK_MINUS;
882             }
883             break;
884
885         case '.':
886             NextChar ();
887             if (CurC == '.') {
888                 NextChar ();
889                 if (CurC == '.') {
890                     SetTok (TOK_ELLIPSIS);
891                 } else {
892                     UnknownChar (CurC);
893                 }
894             } else {
895                 NextTok.Tok = TOK_DOT;
896             }
897             break;
898
899         case '/':
900             NextChar ();
901             if (CurC == '=') {
902                 SetTok (TOK_DIV_ASSIGN);
903             } else {
904                 NextTok.Tok = TOK_DIV;
905             }
906             break;
907
908         case ':':
909             SetTok (TOK_COLON);
910             break;
911
912         case ';':
913             SetTok (TOK_SEMI);
914             break;
915
916         case '<':
917             NextChar ();
918             switch (CurC) {
919                 case '=':
920                     SetTok (TOK_LE);
921                     break;
922                 case '<':
923                     NextChar ();
924                     if (CurC == '=') {
925                         SetTok (TOK_SHL_ASSIGN);
926                     } else {
927                         NextTok.Tok = TOK_SHL;
928                     }
929                     break;
930                 default:
931                     NextTok.Tok = TOK_LT;
932             }
933             break;
934
935         case '=':
936             NextChar ();
937             if (CurC == '=') {
938                 SetTok (TOK_EQ);
939             } else {
940                 NextTok.Tok = TOK_ASSIGN;
941             }
942             break;
943
944         case '>':
945             NextChar ();
946             switch (CurC) {
947                 case '=':
948                     SetTok (TOK_GE);
949                     break;
950                 case '>':
951                     NextChar ();
952                     if (CurC == '=') {
953                         SetTok (TOK_SHR_ASSIGN);
954                     } else {
955                         NextTok.Tok = TOK_SHR;
956                     }
957                     break;
958                 default:
959                     NextTok.Tok = TOK_GT;
960             }
961             break;
962
963         case '?':
964             SetTok (TOK_QUEST);
965             break;
966
967         case '[':
968             SetTok (TOK_LBRACK);
969             break;
970
971         case ']':
972             SetTok (TOK_RBRACK);
973             break;
974
975         case '^':
976             NextChar ();
977             if (CurC == '=') {
978                 SetTok (TOK_XOR_ASSIGN);
979             } else {
980                 NextTok.Tok = TOK_XOR;
981             }
982             break;
983
984         case '{':
985             SetTok (TOK_LCURLY);
986             break;
987
988         case '|':
989             NextChar ();
990             switch (CurC) {
991                 case '|':
992                     SetTok (TOK_BOOL_OR);
993                     break;
994                 case '=':
995                     SetTok (TOK_OR_ASSIGN);
996                     break;
997                 default:
998                     NextTok.Tok = TOK_OR;
999             }
1000             break;
1001
1002         case '}':
1003             SetTok (TOK_RCURLY);
1004             break;
1005
1006         case '~':
1007             SetTok (TOK_COMP);
1008             break;
1009
1010         default:
1011             UnknownChar (CurC);
1012
1013     }
1014
1015 }
1016
1017
1018
1019 void SkipTokens (const token_t* TokenList, unsigned TokenCount)
1020 /* Skip tokens until we reach TOK_CEOF or a token in the given token list.
1021  * This routine is used for error recovery.
1022  */
1023 {
1024     while (CurTok.Tok != TOK_CEOF) {
1025
1026         /* Check if the current token is in the token list */
1027         unsigned I;
1028         for (I = 0; I < TokenCount; ++I) {
1029             if (CurTok.Tok == TokenList[I]) {
1030                 /* Found a token in the list */
1031                 return;
1032             }
1033         }
1034
1035         /* Not in the list: Skip it */
1036         NextToken ();
1037
1038     }
1039 }
1040
1041
1042
1043 int Consume (token_t Token, const char* ErrorMsg)
1044 /* Eat token if it is the next in the input stream, otherwise print an error
1045  * message. Returns true if the token was found and false otherwise.
1046  */
1047 {
1048     if (CurTok.Tok == Token) {
1049         NextToken ();
1050         return 1;
1051     } else {
1052         Error ("%s", ErrorMsg);
1053         return 0;
1054     }
1055 }
1056
1057
1058
1059 int ConsumeColon (void)
1060 /* Check for a colon and skip it. */
1061 {
1062     return Consume (TOK_COLON, "`:' expected");
1063 }
1064
1065
1066
1067 int ConsumeSemi (void)
1068 /* Check for a semicolon and skip it. */
1069 {
1070     /* Try do be smart about typos... */
1071     if (CurTok.Tok == TOK_SEMI) {
1072         NextToken ();
1073         return 1;
1074     } else {
1075         Error ("`;' expected");
1076         if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
1077             NextToken ();
1078         }
1079         return 0;
1080     }
1081 }
1082
1083
1084
1085 int ConsumeComma (void)
1086 /* Check for a comma and skip it. */
1087 {
1088     /* Try do be smart about typos... */
1089     if (CurTok.Tok == TOK_COMMA) {
1090         NextToken ();
1091         return 1;
1092     } else {
1093         Error ("`,' expected");
1094         if (CurTok.Tok == TOK_SEMI) {
1095             NextToken ();
1096         }
1097         return 0;
1098     }
1099 }
1100
1101
1102
1103 int ConsumeLParen (void)
1104 /* Check for a left parenthesis and skip it */
1105 {
1106     return Consume (TOK_LPAREN, "`(' expected");
1107 }
1108
1109
1110
1111 int ConsumeRParen (void)
1112 /* Check for a right parenthesis and skip it */
1113 {
1114     return Consume (TOK_RPAREN, "`)' expected");
1115 }
1116
1117
1118
1119 int ConsumeLBrack (void)
1120 /* Check for a left bracket and skip it */
1121 {
1122     return Consume (TOK_LBRACK, "`[' expected");
1123 }
1124
1125
1126
1127 int ConsumeRBrack (void)
1128 /* Check for a right bracket and skip it */
1129 {
1130     return Consume (TOK_RBRACK, "`]' expected");
1131 }
1132
1133
1134
1135 int ConsumeLCurly (void)
1136 /* Check for a left curly brace and skip it */
1137 {
1138     return Consume (TOK_LCURLY, "`{' expected");
1139 }
1140
1141
1142
1143 int ConsumeRCurly (void)
1144 /* Check for a right curly brace and skip it */
1145 {
1146     return Consume (TOK_RCURLY, "`}' expected");
1147 }
1148
1149
1150