]> git.sur5r.net Git - cc65/blob - src/cc65/scanner.c
Removed unused modules
[cc65] / src / cc65 / scanner.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 scanner.c                                 */
4 /*                                                                           */
5 /*                      Source file line info structure                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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
42 /* common */
43 #include "chartype.h"
44 #include "tgttrans.h"
45
46 /* cc65 */
47 #include "datatype.h"
48 #include "error.h"
49 #include "function.h"
50 #include "global.h"
51 #include "hexval.h"
52 #include "ident.h"
53 #include "input.h"
54 #include "litpool.h"
55 #include "preproc.h"
56 #include "symtab.h"
57 #include "util.h"
58 #include "scanner.h"
59
60
61
62 /*****************************************************************************/
63 /*                                   data                                    */
64 /*****************************************************************************/
65
66
67
68 Token CurTok;           /* The current token */
69 Token NextTok;          /* The next token */
70
71
72
73 /* Token types */
74 #define TT_C    0               /* ANSI C token */
75 #define TT_EXT  1               /* cc65 extension */
76
77 /* Token table */
78 static const struct Keyword {
79     char*           Key;        /* Keyword name */
80     unsigned char   Tok;        /* The token */
81     unsigned char   Type;       /* Token type */
82 } Keywords [] = {
83     { "_Pragma",        TOK_PRAGMA,     TT_C    },
84     { "__AX__",         TOK_AX,         TT_C    },
85     { "__A__",          TOK_A,          TT_C    },
86     { "__EAX__",        TOK_EAX,        TT_C    },
87     { "__X__",          TOK_X,          TT_C    },
88     { "__Y__",          TOK_Y,          TT_C    },
89     { "__asm__",        TOK_ASM,        TT_C    },
90     { "__attribute__",  TOK_ATTRIBUTE,  TT_C    },
91     { "__far__",        TOK_FAR,        TT_C    },
92     { "__fastcall__",   TOK_FASTCALL,   TT_C    },
93     { "__near__",       TOK_NEAR,       TT_C    },
94     { "asm",            TOK_ASM,        TT_EXT  },
95     { "auto",           TOK_AUTO,       TT_C    },
96     { "break",          TOK_BREAK,      TT_C    },
97     { "case",           TOK_CASE,       TT_C    },
98     { "char",           TOK_CHAR,       TT_C    },
99     { "const",          TOK_CONST,      TT_C    },
100     { "continue",       TOK_CONTINUE,   TT_C    },
101     { "default",        TOK_DEFAULT,    TT_C    },
102     { "do",             TOK_DO,         TT_C    },
103     { "double",         TOK_DOUBLE,     TT_C    },
104     { "else",           TOK_ELSE,       TT_C    },
105     { "enum",           TOK_ENUM,       TT_C    },
106     { "extern",         TOK_EXTERN,     TT_C    },
107     { "far",            TOK_FAR,        TT_EXT  },
108     { "fastcall",       TOK_FASTCALL,   TT_EXT  },
109     { "float",          TOK_FLOAT,      TT_C    },
110     { "for",            TOK_FOR,        TT_C    },
111     { "goto",           TOK_GOTO,       TT_C    },
112     { "if",             TOK_IF,         TT_C    },
113     { "int",            TOK_INT,        TT_C    },
114     { "long",           TOK_LONG,       TT_C    },
115     { "near",           TOK_NEAR,       TT_EXT  },
116     { "register",       TOK_REGISTER,   TT_C    },
117     { "restrict",       TOK_RESTRICT,   TT_C    },
118     { "return",         TOK_RETURN,     TT_C    },
119     { "short",          TOK_SHORT,      TT_C    },
120     { "signed",         TOK_SIGNED,     TT_C    },
121     { "sizeof",         TOK_SIZEOF,     TT_C    },
122     { "static",         TOK_STATIC,     TT_C    },
123     { "struct",         TOK_STRUCT,     TT_C    },
124     { "switch",         TOK_SWITCH,     TT_C    },
125     { "typedef",        TOK_TYPEDEF,    TT_C    },
126     { "union",          TOK_UNION,      TT_C    },
127     { "unsigned",       TOK_UNSIGNED,   TT_C    },
128     { "void",           TOK_VOID,       TT_C    },
129     { "volatile",       TOK_VOLATILE,   TT_C    },
130     { "while",          TOK_WHILE,      TT_C    },
131 };
132 #define KEY_COUNT       (sizeof (Keywords) / sizeof (Keywords [0]))
133
134
135
136 /* Stuff for determining the type of an integer constant */
137 #define IT_INT          0x01
138 #define IT_UINT         0x02
139 #define IT_LONG         0x04
140 #define IT_ULONG        0x08
141
142
143
144 /*****************************************************************************/
145 /*                                   code                                    */
146 /*****************************************************************************/
147
148
149
150 static int CmpKey (const void* Key, const void* Elem)
151 /* Compare function for bsearch */
152 {
153     return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
154 }
155
156
157
158 static int FindKey (const char* Key)
159 /* Find a keyword and return the token. Return IDENT if the token is not a
160  * keyword.
161  */
162 {
163     struct Keyword* K;
164     K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
165     if (K && (K->Type != TT_EXT || ANSI == 0)) {
166         return K->Tok;
167     } else {
168         return TOK_IDENT;
169     }
170 }
171
172
173
174 static int SkipWhite (void)
175 /* Skip white space in the input stream, reading and preprocessing new lines
176  * if necessary. Return 0 if end of file is reached, return 1 otherwise.
177  */
178 {
179     while (1) {
180         while (CurC == 0) {
181             if (NextLine () == 0) {
182                 return 0;
183             }
184             Preprocess ();
185         }
186         if (IsSpace (CurC)) {
187             NextChar ();
188         } else {
189             return 1;
190         }
191     }
192 }
193
194
195
196 void SymName (char* s)
197 /* Get symbol from input stream */
198 {
199     unsigned k = 0;
200     do {
201         if (k != MAX_IDENTLEN) {
202             ++k;
203             *s++ = CurC;
204         }
205         NextChar ();
206     } while (IsIdent (CurC) || IsDigit (CurC));
207     *s = '\0';
208 }
209
210
211
212 int IsSym (char *s)
213 /* Get symbol from input stream or return 0 if not a symbol. */
214 {
215     if (IsIdent (CurC)) {
216         SymName (s);
217         return 1;
218     } else {
219         return 0;
220     }
221 }
222
223
224
225 static void UnknownChar (char C)
226 /* Error message for unknown character */
227 {
228     Error ("Invalid input character with code %02X", C & 0xFF);
229     NextChar ();                        /* Skip */
230 }
231
232
233
234 static void SetTok (int tok)
235 /* Set NextTok.Tok and bump line ptr */
236 {
237     NextTok.Tok = tok;
238     NextChar ();
239 }
240
241
242
243 static int ParseChar (void)
244 /* Parse a character. Converts \n into EOL, etc. */
245 {
246     int I;
247     unsigned Val;
248     int C;
249
250     /* Check for escape chars */
251     if (CurC == '\\') {
252         NextChar ();
253         switch (CurC) {
254             case '?':
255                 C = '\?';
256                 break;
257             case 'a':
258                 C = '\a';
259                 break;
260             case 'b':
261                 C = '\b';
262                 break;
263             case 'f':
264                 C = '\f';
265                 break;
266             case 'r':
267                 C = '\r';
268                 break;
269             case 'n':
270                 C = '\n';
271                 break;
272             case 't':
273                 C = '\t';
274                 break;
275             case 'v':
276                 C = '\v';
277                 break;
278             case '\"':
279                 C = '\"';
280                 break;
281             case '\'':
282                 C = '\'';
283                 break;
284             case '\\':
285                 C = '\\';
286                 break;
287             case 'x':
288             case 'X':
289                 /* Hex character constant */
290                 NextChar ();
291                 Val = HexVal (CurC) << 4;
292                 NextChar ();
293                 C = Val | HexVal (CurC);        /* Do not translate */
294                 break;
295             case '0':
296             case '1':
297             case '2':
298             case '3':
299             case '4':
300             case '5':
301             case '6':
302             case '7':
303                 /* Octal constant */
304                 I = 0;
305                 Val = CurC - '0';
306                 while (NextC >= '0' && NextC <= '7' && ++I <= 3) {
307                     NextChar ();
308                     Val = (Val << 3) | (CurC - '0');
309                 }
310                 C = (int) Val;
311                 if (Val >= 256) {
312                     Error ("Character constant out of range");
313                     C = ' ';
314                 }
315                 break;
316             default:
317                 Error ("Illegal character constant");
318                 C = ' ';
319                 /* Try to do error recovery, otherwise the compiler will spit
320                  * out thousands of errors in this place and abort.
321                  */
322                 if (CurC != '\'' && CurC != '\0') {
323                     while (NextC != '\'' && NextC != '\"' && NextC != '\0') {
324                         NextChar ();
325                     }
326                 }
327                 break;
328         }
329     } else {
330         C = CurC;
331     }
332
333     /* Skip the character read */
334     NextChar ();
335
336     /* Do correct sign extension */
337     return SignExtendChar (C);
338 }
339
340
341
342 static void CharConst (void)
343 /* Parse a character constant. */
344 {
345     int C;
346
347     /* Skip the quote */
348     NextChar ();
349
350     /* Get character */
351     C = ParseChar ();
352
353     /* Check for closing quote */
354     if (CurC != '\'') {
355         Error ("`\'' expected");
356     } else {
357         /* Skip the quote */
358         NextChar ();
359     }
360
361     /* Setup values and attributes */
362     NextTok.Tok  = TOK_CCONST;
363
364     /* Translate into target charset */
365     NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
366
367     /* Character constants have type int */
368     NextTok.Type = type_int;
369 }
370
371
372
373 static void StringConst (void)
374 /* Parse a quoted string */
375 {
376     NextTok.IVal = GetLiteralPoolOffs ();
377     NextTok.Tok  = TOK_SCONST;
378
379     /* Be sure to concatenate strings */
380     while (CurC == '\"') {
381
382         /* Skip the quote char */
383         NextChar ();
384
385         while (CurC != '\"') {
386             if (CurC == '\0') {
387                 Error ("Unexpected newline");
388                 break;
389             }
390             AddLiteralChar (ParseChar ());
391         }
392
393         /* Skip closing quote char if there was one */
394         NextChar ();
395
396         /* Skip white space, read new input */
397         SkipWhite ();
398
399     }
400
401     /* Terminate the string */
402     AddLiteralChar ('\0');
403 }
404
405
406
407 void NextToken (void)
408 /* Get next token from input stream */
409 {
410     ident token;
411
412     /* We have to skip white space here before shifting tokens, since the
413      * tokens and the current line info is invalid at startup and will get
414      * initialized by reading the first time from the file. Remember if
415      * we were at end of input and handle that later.
416      */
417     int GotEOF = (SkipWhite() == 0);
418
419     /* Current token is the lookahead token */
420     if (CurTok.LI) {
421         ReleaseLineInfo (CurTok.LI);
422     }
423     CurTok = NextTok;
424
425     /* When reading the first time from the file, the line info in NextTok,
426      * which was copied to CurTok is invalid. Since the information from
427      * the token is used for error messages, we must make it valid.
428      */
429     if (CurTok.LI == 0) {
430         CurTok.LI = UseLineInfo (GetCurLineInfo ());
431     }
432
433     /* Remember the starting position of the next token */
434     NextTok.LI = UseLineInfo (GetCurLineInfo ());
435
436     /* Now handle end of input. */
437     if (GotEOF) {
438         /* End of file reached */
439         NextTok.Tok = TOK_CEOF;
440         return;
441     }
442
443     /* Determine the next token from the lookahead */
444     if (IsDigit (CurC)) {
445
446         /* A number */
447         int HaveSuffix;         /* True if we have a type suffix */
448         unsigned types;         /* Possible types */
449         unsigned Base;
450         unsigned DigitVal;
451         unsigned long k;        /* Value */
452
453         k     = 0;
454         Base  = 10;
455         types = IT_INT | IT_LONG | IT_ULONG;
456
457         if (CurC == '0') {
458             /* Octal or hex constants may also be of type unsigned int */
459             types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
460             /* gobble 0 and examin next char */
461             NextChar ();
462             if (toupper (CurC) == 'X') {
463                 Base = 16;
464                 NextTok.Type = type_uint;
465                 NextChar ();    /* gobble "x" */
466             } else {
467                 Base = 8;
468             }
469         }
470         while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
471             k = k * Base + DigitVal;
472             NextChar ();
473         }
474         /* Check for errorneous digits */
475         if (Base == 8 && IsDigit (CurC)) {
476             Error ("Numeric constant contains digits beyond the radix");
477             /* Do error recovery */
478             do {
479                 NextChar ();
480             } while (IsDigit (CurC));
481         } else if (Base != 16 && IsXDigit (CurC)) {
482             Error ("Nondigits in number and not hexadecimal");
483             do {
484                 NextChar ();
485             } while (IsXDigit (CurC));
486         }
487
488         /* Check for a suffix */
489         HaveSuffix = 1;
490         if (CurC == 'u' || CurC == 'U') {
491             /* Unsigned type */
492             NextChar ();
493             if (toupper (CurC) != 'L') {
494                 types = IT_UINT | IT_ULONG;
495             } else {
496                 NextChar ();
497                 types = IT_ULONG;
498             }
499         } else if (CurC == 'l' || CurC == 'L') {
500             /* Long type */
501             NextChar ();
502             if (toupper (CurC) != 'U') {
503                 types = IT_LONG | IT_ULONG;
504             } else {
505                 NextChar ();
506                 types = IT_ULONG;
507             }
508         } else {
509             HaveSuffix = 0;
510         }
511
512         /* Check the range to determine the type */
513         if (k > 0x7FFF) {
514             /* Out of range for int */
515             types &= ~IT_INT;
516             /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
517              * allowed, and we don't have a type specifying suffix, emit a
518              * warning.
519              */
520             if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
521                 Warning ("Constant is long");
522             }
523         }
524         if (k > 0xFFFF) {
525             /* Out of range for unsigned int */
526             types &= ~IT_UINT;
527         }
528         if (k > 0x7FFFFFFF) {
529             /* Out of range for long int */
530             types &= ~IT_LONG;
531         }
532
533         /* Now set the type string to the smallest type in types */
534         if (types & IT_INT) {
535             NextTok.Type = type_int;
536         } else if (types & IT_UINT) {
537             NextTok.Type = type_uint;
538         } else if (types & IT_LONG) {
539             NextTok.Type = type_long;
540         } else {
541             NextTok.Type = type_ulong;
542         }
543
544         /* Set the value and the token */
545         NextTok.IVal = k;
546         NextTok.Tok  = TOK_ICONST;
547         return;
548     }
549
550     if (IsSym (token)) {
551
552         /* Check for a keyword */
553         if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
554             /* Reserved word found */
555             return;
556         }
557         /* No reserved word, check for special symbols */
558         if (token [0] == '_') {
559             /* Special symbols */
560             if (strcmp (token, "__FILE__") == 0) {
561                 NextTok.IVal = AddLiteral (GetCurrentFile());
562                 NextTok.Tok  = TOK_SCONST;
563                 return;
564             } else if (strcmp (token, "__LINE__") == 0) {
565                 NextTok.Tok  = TOK_ICONST;
566                 NextTok.IVal = GetCurrentLine();
567                 NextTok.Type = type_int;
568                 return;
569             } else if (strcmp (token, "__func__") == 0) {
570                 /* __func__ is only defined in functions */
571                 if (CurrentFunc) {
572                     NextTok.IVal = AddLiteral (F_GetFuncName (CurrentFunc));
573                     NextTok.Tok  = TOK_SCONST;
574                     return;
575                 }
576             }
577         }
578
579         /* No reserved word but identifier */
580         strcpy (NextTok.Ident, token);
581         NextTok.Tok = TOK_IDENT;
582         return;
583     }
584
585     /* Monstrous switch statement ahead... */
586     switch (CurC) {
587
588         case '!':
589             NextChar ();
590             if (CurC == '=') {
591                 SetTok (TOK_NE);
592             } else {
593                 NextTok.Tok = TOK_BOOL_NOT;
594             }
595             break;
596
597         case '\"':
598             StringConst ();
599             break;
600
601         case '%':
602             NextChar ();
603             if (CurC == '=') {
604                 SetTok (TOK_MOD_ASSIGN);
605             } else {
606                 NextTok.Tok = TOK_MOD;
607             }
608             break;
609
610         case '&':
611             NextChar ();
612             switch (CurC) {
613                 case '&':
614                     SetTok (TOK_BOOL_AND);
615                     break;
616                 case '=':
617                     SetTok (TOK_AND_ASSIGN);
618                     break;
619                 default:
620                     NextTok.Tok = TOK_AND;
621             }
622             break;
623
624         case '\'':
625             CharConst ();
626             break;
627
628         case '(':
629             SetTok (TOK_LPAREN);
630             break;
631
632         case ')':
633             SetTok (TOK_RPAREN);
634             break;
635
636         case '*':
637             NextChar ();
638             if (CurC == '=') {
639                 SetTok (TOK_MUL_ASSIGN);
640             } else {
641                 NextTok.Tok = TOK_STAR;
642             }
643             break;
644
645         case '+':
646             NextChar ();
647             switch (CurC) {
648                 case '+':
649                     SetTok (TOK_INC);
650                     break;
651                 case '=':
652                     SetTok (TOK_PLUS_ASSIGN);
653                     break;
654                 default:
655                     NextTok.Tok = TOK_PLUS;
656             }
657             break;
658
659         case ',':
660             SetTok (TOK_COMMA);
661             break;
662
663         case '-':
664             NextChar ();
665             switch (CurC) {
666                 case '-':
667                     SetTok (TOK_DEC);
668                     break;
669                 case '=':
670                     SetTok (TOK_MINUS_ASSIGN);
671                     break;
672                 case '>':
673                     SetTok (TOK_PTR_REF);
674                     break;
675                 default:
676                     NextTok.Tok = TOK_MINUS;
677             }
678             break;
679
680         case '.':
681             NextChar ();
682             if (CurC == '.') {
683                 NextChar ();
684                 if (CurC == '.') {
685                     SetTok (TOK_ELLIPSIS);
686                 } else {
687                     UnknownChar (CurC);
688                 }
689             } else {
690                 NextTok.Tok = TOK_DOT;
691             }
692             break;
693
694         case '/':
695             NextChar ();
696             if (CurC == '=') {
697                 SetTok (TOK_DIV_ASSIGN);
698             } else {
699                 NextTok.Tok = TOK_DIV;
700             }
701             break;
702
703         case ':':
704             SetTok (TOK_COLON);
705             break;
706
707         case ';':
708             SetTok (TOK_SEMI);
709             break;
710
711         case '<':
712             NextChar ();
713             switch (CurC) {
714                 case '=':
715                     SetTok (TOK_LE);
716                     break;
717                 case '<':
718                     NextChar ();
719                     if (CurC == '=') {
720                         SetTok (TOK_SHL_ASSIGN);
721                     } else {
722                         NextTok.Tok = TOK_SHL;
723                     }
724                     break;
725                 default:
726                     NextTok.Tok = TOK_LT;
727             }
728             break;
729
730         case '=':
731             NextChar ();
732             if (CurC == '=') {
733                 SetTok (TOK_EQ);
734             } else {
735                 NextTok.Tok = TOK_ASSIGN;
736             }
737             break;
738
739         case '>':
740             NextChar ();
741             switch (CurC) {
742                 case '=':
743                     SetTok (TOK_GE);
744                     break;
745                 case '>':
746                     NextChar ();
747                     if (CurC == '=') {
748                         SetTok (TOK_SHR_ASSIGN);
749                     } else {
750                         NextTok.Tok = TOK_SHR;
751                     }
752                     break;
753                 default:
754                     NextTok.Tok = TOK_GT;
755             }
756             break;
757
758         case '?':
759             SetTok (TOK_QUEST);
760             break;
761
762         case '[':
763             SetTok (TOK_LBRACK);
764             break;
765
766         case ']':
767             SetTok (TOK_RBRACK);
768             break;
769
770         case '^':
771             NextChar ();
772             if (CurC == '=') {
773                 SetTok (TOK_XOR_ASSIGN);
774             } else {
775                 NextTok.Tok = TOK_XOR;
776             }
777             break;
778
779         case '{':
780             SetTok (TOK_LCURLY);
781             break;
782
783         case '|':
784             NextChar ();
785             switch (CurC) {
786                 case '|':
787                     SetTok (TOK_BOOL_OR);
788                     break;
789                 case '=':
790                     SetTok (TOK_OR_ASSIGN);
791                     break;
792                 default:
793                     NextTok.Tok = TOK_OR;
794             }
795             break;
796
797         case '}':
798             SetTok (TOK_RCURLY);
799             break;
800
801         case '~':
802             SetTok (TOK_COMP);
803             break;
804
805         default:
806             UnknownChar (CurC);
807
808     }
809
810 }
811
812
813
814 void SkipTokens (const token_t* TokenList, unsigned TokenCount)
815 /* Skip tokens until we reach TOK_CEOF or a token in the given token list.
816  * This routine is used for error recovery.
817  */
818 {
819     while (CurTok.Tok != TOK_CEOF) {
820
821         /* Check if the current token is in the token list */
822         unsigned I;
823         for (I = 0; I < TokenCount; ++I) {
824             if (CurTok.Tok == TokenList[I]) {
825                 /* Found a token in the list */
826                 return;
827             }
828         }
829
830         /* Not in the list: Skip it */
831         NextToken ();
832
833     }
834 }
835
836
837
838 int Consume (token_t Token, const char* ErrorMsg)
839 /* Eat token if it is the next in the input stream, otherwise print an error
840  * message. Returns true if the token was found and false otherwise.
841  */
842 {
843     if (CurTok.Tok == Token) {
844         NextToken ();
845         return 1;
846     } else {
847         Error (ErrorMsg);
848         return 0;
849     }
850 }
851
852
853
854 int ConsumeColon (void)
855 /* Check for a colon and skip it. */
856 {
857     return Consume (TOK_COLON, "`:' expected");
858 }
859
860
861
862 int ConsumeSemi (void)
863 /* Check for a semicolon and skip it. */
864 {
865     /* Try do be smart about typos... */
866     if (CurTok.Tok == TOK_SEMI) {
867         NextToken ();
868         return 1;
869     } else {
870         Error ("`;' expected");
871         if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
872             NextToken ();
873         }
874         return 0;
875     }
876 }
877
878
879
880 int ConsumeComma (void)
881 /* Check for a comma and skip it. */
882 {
883     /* Try do be smart about typos... */
884     if (CurTok.Tok == TOK_COMMA) {
885         NextToken ();
886         return 1;
887     } else {
888         Error ("`,' expected");
889         if (CurTok.Tok == TOK_SEMI) {
890             NextToken ();
891         }
892         return 0;
893     }
894 }
895
896
897
898 int ConsumeLParen (void)
899 /* Check for a left parenthesis and skip it */
900 {
901     return Consume (TOK_LPAREN, "`(' expected");
902 }
903
904
905
906 int ConsumeRParen (void)
907 /* Check for a right parenthesis and skip it */
908 {
909     return Consume (TOK_RPAREN, "`)' expected");
910 }
911
912
913
914 int ConsumeLBrack (void)
915 /* Check for a left bracket and skip it */
916 {
917     return Consume (TOK_LBRACK, "`[' expected");
918 }
919
920
921
922 int ConsumeRBrack (void)
923 /* Check for a right bracket and skip it */
924 {
925     return Consume (TOK_RBRACK, "`]' expected");
926 }
927
928
929
930 int ConsumeLCurly (void)
931 /* Check for a left curly brace and skip it */
932 {
933     return Consume (TOK_LCURLY, "`{' expected");
934 }
935
936
937
938 int ConsumeRCurly (void)
939 /* Check for a right curly brace and skip it */
940 {
941     return Consume (TOK_RCURLY, "`}' expected");
942 }
943
944
945