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