]> git.sur5r.net Git - cc65/blob - src/cc65/scanner.c
e87126f4101c9d6fb4d9566e248046ed2df1d479
[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 'b':
255                 C = '\b';
256                 break;
257             case 'f':
258                 C = '\f';
259                 break;
260             case 'r':
261                 C = '\r';
262                 break;
263             case 'n':
264                 C = '\n';
265                 break;
266             case 't':
267                 C = '\t';
268                 break;
269             case '\"':
270                 C = '\"';
271                 break;
272             case '\'':
273                 C = '\'';
274                 break;
275             case '\\':
276                 C = '\\';
277                 break;
278             case 'x':
279             case 'X':
280                 /* Hex character constant */
281                 NextChar ();
282                 val = HexVal (CurC) << 4;
283                 NextChar ();
284                 C = val | HexVal (CurC);        /* Do not translate */
285                 break;
286             case '0':
287             case '1':
288             case '2':
289             case '3':
290                 /* Octal constant */
291                 i = 0;
292                 C = CurC - '0';
293                 while (NextC >= '0' && NextC <= '7' && i++ < 4) {
294                     NextChar ();
295                     C = (C << 3) | (CurC - '0');
296                 }
297                 break;
298             default:
299                 Error ("Illegal character constant");
300                 C = ' ';
301                 break;
302         }
303     } else {
304         C = CurC;
305     }
306
307     /* Skip the character read */
308     NextChar ();
309
310     /* Do correct sign extension */
311     return SignExtendChar (C);
312 }
313
314
315
316 static void CharConst (void)
317 /* Parse a character constant. */
318 {
319     int C;
320
321     /* Skip the quote */
322     NextChar ();
323
324     /* Get character */
325     C = ParseChar ();
326
327     /* Check for closing quote */
328     if (CurC != '\'') {
329         Error ("`\'' expected");
330     } else {
331         /* Skip the quote */
332         NextChar ();
333     }
334
335     /* Setup values and attributes */
336     NextTok.Tok  = TOK_CCONST;
337
338     /* Translate into target charset */
339     NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
340
341     /* Character constants have type int */
342     NextTok.Type = type_int;
343 }
344
345
346
347 static void StringConst (void)
348 /* Parse a quoted string */
349 {
350     NextTok.IVal = GetLiteralPoolOffs ();
351     NextTok.Tok  = TOK_SCONST;
352
353     /* Be sure to concatenate strings */
354     while (CurC == '\"') {
355
356         /* Skip the quote char */
357         NextChar ();
358
359         while (CurC != '\"') {
360             if (CurC == '\0') {
361                 Error ("Unexpected newline");
362                 break;
363             }
364             AddLiteralChar (ParseChar ());
365         }
366
367         /* Skip closing quote char if there was one */
368         NextChar ();
369
370         /* Skip white space, read new input */
371         SkipWhite ();
372
373     }
374
375     /* Terminate the string */
376     AddLiteralChar ('\0');
377 }
378
379
380
381 void NextToken (void)
382 /* Get next token from input stream */
383 {
384     ident token;
385
386     /* We have to skip white space here before shifting tokens, since the
387      * tokens and the current line info is invalid at startup and will get
388      * initialized by reading the first time from the file. Remember if
389      * we were at end of input and handle that later.
390      */
391     int GotEOF = (SkipWhite() == 0);
392
393     /* Current token is the lookahead token */
394     if (CurTok.LI) {
395         ReleaseLineInfo (CurTok.LI);
396     }
397     CurTok = NextTok;
398
399     /* When reading the first time from the file, the line info in NextTok,
400      * which was copied to CurTok is invalid. Since the information from
401      * the token is used for error messages, we must make it valid.
402      */
403     if (CurTok.LI == 0) {
404         CurTok.LI = UseLineInfo (GetCurLineInfo ());
405     }
406
407     /* Remember the starting position of the next token */
408     NextTok.LI = UseLineInfo (GetCurLineInfo ());
409
410     /* Now handle end of input. */
411     if (GotEOF) {
412         /* End of file reached */
413         NextTok.Tok = TOK_CEOF;
414         return;
415     }
416
417     /* Determine the next token from the lookahead */
418     if (IsDigit (CurC)) {
419
420         /* A number */
421         int HaveSuffix;         /* True if we have a type suffix */
422         unsigned types;         /* Possible types */
423         unsigned Base;
424         unsigned DigitVal;
425         unsigned long k;        /* Value */
426
427         k     = 0;
428         Base  = 10;
429         types = IT_INT | IT_LONG | IT_ULONG;
430
431         if (CurC == '0') {
432             /* Octal or hex constants may also be of type unsigned int */
433             types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
434             /* gobble 0 and examin next char */
435             NextChar ();
436             if (toupper (CurC) == 'X') {
437                 Base = 16;
438                 NextTok.Type = type_uint;
439                 NextChar ();    /* gobble "x" */
440             } else {
441                 Base = 8;
442             }
443         }
444         while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
445             k = k * Base + DigitVal;
446             NextChar ();
447         }
448         /* Check for errorneous digits */
449         if (Base == 8 && IsDigit (CurC)) {
450             Error ("Numeric constant contains digits beyond the radix");
451             /* Do error recovery */
452             do {
453                 NextChar ();
454             } while (IsDigit (CurC));
455         } else if (Base != 16 && IsXDigit (CurC)) {
456             Error ("Nondigits in number and not hexadecimal");
457             do {
458                 NextChar ();
459             } while (IsXDigit (CurC));
460         }
461
462         /* Check for a suffix */
463         HaveSuffix = 1;
464         if (CurC == 'u' || CurC == 'U') {
465             /* Unsigned type */
466             NextChar ();
467             if (toupper (CurC) != 'L') {
468                 types = IT_UINT | IT_ULONG;
469             } else {
470                 NextChar ();
471                 types = IT_ULONG;
472             }
473         } else if (CurC == 'l' || CurC == 'L') {
474             /* Long type */
475             NextChar ();
476             if (toupper (CurC) != 'U') {
477                 types = IT_LONG | IT_ULONG;
478             } else {
479                 NextChar ();
480                 types = IT_ULONG;
481             }
482         } else {
483             HaveSuffix = 0;
484         }
485
486         /* Check the range to determine the type */
487         if (k > 0x7FFF) {
488             /* Out of range for int */
489             types &= ~IT_INT;
490             /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
491              * allowed, and we don't have a type specifying suffix, emit a
492              * warning.
493              */
494             if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
495                 Warning ("Constant is long");
496             }
497         }
498         if (k > 0xFFFF) {
499             /* Out of range for unsigned int */
500             types &= ~IT_UINT;
501         }
502         if (k > 0x7FFFFFFF) {
503             /* Out of range for long int */
504             types &= ~IT_LONG;
505         }
506
507         /* Now set the type string to the smallest type in types */
508         if (types & IT_INT) {
509             NextTok.Type = type_int;
510         } else if (types & IT_UINT) {
511             NextTok.Type = type_uint;
512         } else if (types & IT_LONG) {
513             NextTok.Type = type_long;
514         } else {
515             NextTok.Type = type_ulong;
516         }
517
518         /* Set the value and the token */
519         NextTok.IVal = k;
520         NextTok.Tok  = TOK_ICONST;
521         return;
522     }
523
524     if (IsSym (token)) {
525
526         /* Check for a keyword */
527         if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
528             /* Reserved word found */
529             return;
530         }
531         /* No reserved word, check for special symbols */
532         if (token [0] == '_') {
533             /* Special symbols */
534             if (strcmp (token, "__FILE__") == 0) {
535                 NextTok.IVal = AddLiteral (GetCurrentFile());
536                 NextTok.Tok  = TOK_SCONST;
537                 return;
538             } else if (strcmp (token, "__LINE__") == 0) {
539                 NextTok.Tok  = TOK_ICONST;
540                 NextTok.IVal = GetCurrentLine();
541                 NextTok.Type = type_int;
542                 return;
543             } else if (strcmp (token, "__func__") == 0) {
544                 /* __func__ is only defined in functions */
545                 if (CurrentFunc) {
546                     NextTok.IVal = AddLiteral (F_GetFuncName (CurrentFunc));
547                     NextTok.Tok  = TOK_SCONST;
548                     return;
549                 }
550             }
551         }
552
553         /* No reserved word but identifier */
554         strcpy (NextTok.Ident, token);
555         NextTok.Tok = TOK_IDENT;
556         return;
557     }
558
559     /* Monstrous switch statement ahead... */
560     switch (CurC) {
561
562         case '!':
563             NextChar ();
564             if (CurC == '=') {
565                 SetTok (TOK_NE);
566             } else {
567                 NextTok.Tok = TOK_BOOL_NOT;
568             }
569             break;
570
571         case '\"':
572             StringConst ();
573             break;
574
575         case '%':
576             NextChar ();
577             if (CurC == '=') {
578                 SetTok (TOK_MOD_ASSIGN);
579             } else {
580                 NextTok.Tok = TOK_MOD;
581             }
582             break;
583
584         case '&':
585             NextChar ();
586             switch (CurC) {
587                 case '&':
588                     SetTok (TOK_BOOL_AND);
589                     break;
590                 case '=':
591                     SetTok (TOK_AND_ASSIGN);
592                     break;
593                 default:
594                     NextTok.Tok = TOK_AND;
595             }
596             break;
597
598         case '\'':
599             CharConst ();
600             break;
601
602         case '(':
603             SetTok (TOK_LPAREN);
604             break;
605
606         case ')':
607             SetTok (TOK_RPAREN);
608             break;
609
610         case '*':
611             NextChar ();
612             if (CurC == '=') {
613                 SetTok (TOK_MUL_ASSIGN);
614             } else {
615                 NextTok.Tok = TOK_STAR;
616             }
617             break;
618
619         case '+':
620             NextChar ();
621             switch (CurC) {
622                 case '+':
623                     SetTok (TOK_INC);
624                     break;
625                 case '=':
626                     SetTok (TOK_PLUS_ASSIGN);
627                     break;
628                 default:
629                     NextTok.Tok = TOK_PLUS;
630             }
631             break;
632
633         case ',':
634             SetTok (TOK_COMMA);
635             break;
636
637         case '-':
638             NextChar ();
639             switch (CurC) {
640                 case '-':
641                     SetTok (TOK_DEC);
642                     break;
643                 case '=':
644                     SetTok (TOK_MINUS_ASSIGN);
645                     break;
646                 case '>':
647                     SetTok (TOK_PTR_REF);
648                     break;
649                 default:
650                     NextTok.Tok = TOK_MINUS;
651             }
652             break;
653
654         case '.':
655             NextChar ();
656             if (CurC == '.') {
657                 NextChar ();
658                 if (CurC == '.') {
659                     SetTok (TOK_ELLIPSIS);
660                 } else {
661                     UnknownChar (CurC);
662                 }
663             } else {
664                 NextTok.Tok = TOK_DOT;
665             }
666             break;
667
668         case '/':
669             NextChar ();
670             if (CurC == '=') {
671                 SetTok (TOK_DIV_ASSIGN);
672             } else {
673                 NextTok.Tok = TOK_DIV;
674             }
675             break;
676
677         case ':':
678             SetTok (TOK_COLON);
679             break;
680
681         case ';':
682             SetTok (TOK_SEMI);
683             break;
684
685         case '<':
686             NextChar ();
687             switch (CurC) {
688                 case '=':
689                     SetTok (TOK_LE);
690                     break;
691                 case '<':
692                     NextChar ();
693                     if (CurC == '=') {
694                         SetTok (TOK_SHL_ASSIGN);
695                     } else {
696                         NextTok.Tok = TOK_SHL;
697                     }
698                     break;
699                 default:
700                     NextTok.Tok = TOK_LT;
701             }
702             break;
703
704         case '=':
705             NextChar ();
706             if (CurC == '=') {
707                 SetTok (TOK_EQ);
708             } else {
709                 NextTok.Tok = TOK_ASSIGN;
710             }
711             break;
712
713         case '>':
714             NextChar ();
715             switch (CurC) {
716                 case '=':
717                     SetTok (TOK_GE);
718                     break;
719                 case '>':
720                     NextChar ();
721                     if (CurC == '=') {
722                         SetTok (TOK_SHR_ASSIGN);
723                     } else {
724                         NextTok.Tok = TOK_SHR;
725                     }
726                     break;
727                 default:
728                     NextTok.Tok = TOK_GT;
729             }
730             break;
731
732         case '?':
733             SetTok (TOK_QUEST);
734             break;
735
736         case '[':
737             SetTok (TOK_LBRACK);
738             break;
739
740         case ']':
741             SetTok (TOK_RBRACK);
742             break;
743
744         case '^':
745             NextChar ();
746             if (CurC == '=') {
747                 SetTok (TOK_XOR_ASSIGN);
748             } else {
749                 NextTok.Tok = TOK_XOR;
750             }
751             break;
752
753         case '{':
754             SetTok (TOK_LCURLY);
755             break;
756
757         case '|':
758             NextChar ();
759             switch (CurC) {
760                 case '|':
761                     SetTok (TOK_BOOL_OR);
762                     break;
763                 case '=':
764                     SetTok (TOK_OR_ASSIGN);
765                     break;
766                 default:
767                     NextTok.Tok = TOK_OR;
768             }
769             break;
770
771         case '}':
772             SetTok (TOK_RCURLY);
773             break;
774
775         case '~':
776             SetTok (TOK_COMP);
777             break;
778
779         default:
780             UnknownChar (CurC);
781
782     }
783
784 }
785
786
787
788 void SkipTokens (const token_t* TokenList, unsigned TokenCount)
789 /* Skip tokens until we reach TOK_CEOF or a token in the given token list.
790  * This routine is used for error recovery.
791  */
792 {
793     while (CurTok.Tok != TOK_CEOF) {
794
795         /* Check if the current token is in the token list */
796         unsigned I;
797         for (I = 0; I < TokenCount; ++I) {
798             if (CurTok.Tok == TokenList[I]) {
799                 /* Found a token in the list */
800                 return;
801             }
802         }
803
804         /* Not in the list: Skip it */
805         NextToken ();
806
807     }
808 }
809
810
811
812 int Consume (token_t Token, const char* ErrorMsg)
813 /* Eat token if it is the next in the input stream, otherwise print an error
814  * message. Returns true if the token was found and false otherwise.
815  */
816 {
817     if (CurTok.Tok == Token) {
818         NextToken ();
819         return 1;
820     } else {
821         Error (ErrorMsg);
822         return 0;
823     }
824 }
825
826
827
828 int ConsumeColon (void)
829 /* Check for a colon and skip it. */
830 {
831     return Consume (TOK_COLON, "`:' expected");
832 }
833
834
835
836 int ConsumeSemi (void)
837 /* Check for a semicolon and skip it. */
838 {
839     /* Try do be smart about typos... */
840     if (CurTok.Tok == TOK_SEMI) {
841         NextToken ();
842         return 1;
843     } else {
844         Error ("`;' expected");
845         if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
846             NextToken ();
847         }
848         return 0;
849     }
850 }
851
852
853
854 int ConsumeComma (void)
855 /* Check for a comma and skip it. */
856 {
857     /* Try do be smart about typos... */
858     if (CurTok.Tok == TOK_COMMA) {
859         NextToken ();
860         return 1;
861     } else {
862         Error ("`,' expected");
863         if (CurTok.Tok == TOK_SEMI) {
864             NextToken ();
865         }
866         return 0;
867     }
868 }
869
870
871
872 int ConsumeLParen (void)
873 /* Check for a left parenthesis and skip it */
874 {
875     return Consume (TOK_LPAREN, "`(' expected");
876 }
877
878
879
880 int ConsumeRParen (void)
881 /* Check for a right parenthesis and skip it */
882 {
883     return Consume (TOK_RPAREN, "`)' expected");
884 }
885
886
887
888 int ConsumeLBrack (void)
889 /* Check for a left bracket and skip it */
890 {
891     return Consume (TOK_LBRACK, "`[' expected");
892 }
893
894
895
896 int ConsumeRBrack (void)
897 /* Check for a right bracket and skip it */
898 {
899     return Consume (TOK_RBRACK, "`]' expected");
900 }
901
902
903
904 int ConsumeLCurly (void)
905 /* Check for a left curly brace and skip it */
906 {
907     return Consume (TOK_LCURLY, "`{' expected");
908 }
909
910
911
912 int ConsumeRCurly (void)
913 /* Check for a right curly brace and skip it */
914 {
915     return Consume (TOK_RCURLY, "`}' expected");
916 }
917
918
919