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