]> git.sur5r.net Git - cc65/blob - src/cc65/declare.c
Improved implementation of OptPushPop
[cc65] / src / cc65 / declare.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 declare.c                                 */
4 /*                                                                           */
5 /*                 Parse variable and function declarations                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 <string.h>
38 #include <errno.h>
39
40 /* common */
41 #include "xmalloc.h"
42
43 /* cc65 */
44 #include "anonname.h"
45 #include "codegen.h"
46 #include "datatype.h"
47 #include "declattr.h"
48 #include "error.h"
49 #include "expr.h"
50 #include "funcdesc.h"
51 #include "function.h"
52 #include "global.h"
53 #include "litpool.h"
54 #include "pragma.h"
55 #include "scanner.h"
56 #include "symtab.h"
57 #include "declare.h"
58
59
60
61 /*****************************************************************************/
62 /*                                 Forwards                                  */
63 /*****************************************************************************/
64
65
66
67 static void ParseTypeSpec (DeclSpec* D, int Default);
68 /* Parse a type specificier */
69
70
71
72 /*****************************************************************************/
73 /*                            internal functions                             */
74 /*****************************************************************************/
75
76
77
78 static type OptionalQualifiers (type Q)
79 /* Read type qualifiers if we have any */
80 {
81     while (CurTok.Tok == TOK_CONST || CurTok.Tok == TOK_VOLATILE) {
82
83         switch (CurTok.Tok) {
84
85             case TOK_CONST:
86                 if (Q & T_QUAL_CONST) {
87                     Error ("Duplicate qualifier: `const'");
88                 }
89                 Q |= T_QUAL_CONST;
90                 break;
91
92             case TOK_VOLATILE:
93                 if (Q & T_QUAL_VOLATILE) {
94                     Error ("Duplicate qualifier: `volatile'");
95                 }
96                 Q |= T_QUAL_VOLATILE;
97                 break;
98
99             default:
100                 /* Keep gcc silent */
101                 break;
102
103         }
104
105         /* Skip the token */
106         NextToken ();
107     }
108
109     /* Return the qualifiers read */
110     return Q;
111 }
112
113
114
115 static void optionalint (void)
116 /* Eat an optional "int" token */
117 {
118     if (CurTok.Tok == TOK_INT) {
119         /* Skip it */
120         NextToken ();
121     }
122 }
123
124
125
126 static void optionalsigned (void)
127 /* Eat an optional "signed" token */
128 {
129     if (CurTok.Tok == TOK_SIGNED) {
130         /* Skip it */
131         NextToken ();
132     }
133 }
134
135
136
137 static void InitDeclSpec (DeclSpec* D)
138 /* Initialize the DeclSpec struct for use */
139 {
140     D->StorageClass     = 0;
141     D->Type[0]          = T_END;
142     D->Flags            = 0;
143 }
144
145
146
147 static void InitDeclaration (Declaration* D)
148 /* Initialize the Declaration struct for use */
149 {
150     D->Ident[0]         = '\0';
151     D->Type[0]          = T_END;
152     D->T                = D->Type;
153 }
154
155
156
157 static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
158 /* Parse a storage class */
159 {
160     /* Assume we're using an explicit storage class */
161     D->Flags &= ~DS_DEF_STORAGE;
162
163     /* Check the storage class given */
164     switch (CurTok.Tok) {
165
166         case TOK_EXTERN:
167             D->StorageClass = SC_EXTERN | SC_STATIC;
168             NextToken ();
169             break;
170
171         case TOK_STATIC:
172             D->StorageClass = SC_STATIC;
173             NextToken ();
174             break;
175
176         case TOK_REGISTER:
177             D->StorageClass = SC_REGISTER | SC_STATIC;
178             NextToken ();
179             break;
180
181         case TOK_AUTO:
182             D->StorageClass = SC_AUTO;
183             NextToken ();
184             break;
185
186         case TOK_TYPEDEF:
187             D->StorageClass = SC_TYPEDEF;
188             NextToken ();
189             break;
190
191         default:
192             /* No storage class given, use default */
193             D->Flags |= DS_DEF_STORAGE;
194             D->StorageClass = DefStorage;
195             break;
196     }
197 }
198
199
200
201 static void ParseEnumDecl (void)
202 /* Process an enum declaration . */
203 {
204     int EnumVal;
205     ident Ident;
206
207     /* Accept forward definitions */
208     if (CurTok.Tok != TOK_LCURLY) {
209         return;
210     }
211
212     /* Skip the opening curly brace */
213     NextToken ();
214
215     /* Read the enum tags */
216     EnumVal = 0;
217     while (CurTok.Tok != TOK_RCURLY) {
218
219         /* We expect an identifier */
220         if (CurTok.Tok != TOK_IDENT) {
221             Error ("Identifier expected");
222             continue;
223         }
224
225         /* Remember the identifier and skip it */
226         strcpy (Ident, CurTok.Ident);
227         NextToken ();
228
229         /* Check for an assigned value */
230         if (CurTok.Tok == TOK_ASSIGN) {
231             ExprDesc lval;
232             NextToken ();
233             ConstExpr (&lval);
234             EnumVal = lval.ConstVal;
235         }
236
237         /* Add an entry to the symbol table */
238         AddConstSym (Ident, type_int, SC_ENUM, EnumVal++);
239
240         /* Check for end of definition */
241         if (CurTok.Tok != TOK_COMMA)
242             break;
243         NextToken ();
244     }
245     ConsumeRCurly ();
246 }
247
248
249
250 static SymEntry* ParseStructDecl (const char* Name, type StructType)
251 /* Parse a struct/union declaration. */
252 {
253
254     unsigned Size;
255     unsigned Offs;
256     SymTable* FieldTab;
257     SymEntry* Entry;
258
259
260     if (CurTok.Tok != TOK_LCURLY) {
261         /* Just a forward declaration. Try to find a struct with the given
262          * name. If there is none, insert a forward declaration into the
263          * current lexical level.
264          */
265         Entry = FindTagSym (Name);
266         if (Entry == 0) {
267             Entry = AddStructSym (Name, 0, 0);
268         } else if (SymIsLocal (Entry) && (Entry->Flags & SC_STRUCT) == 0) {
269             /* Already defined in the level but no struct */
270             Error ("Symbol `%s' is already different kind", Name);
271         }
272         return Entry;
273     }
274
275     /* Add a forward declaration for the struct in the current lexical level */
276     Entry = AddStructSym (Name, 0, 0);
277
278     /* Skip the curly brace */
279     NextToken ();
280
281     /* Enter a new lexical level for the struct */
282     EnterStructLevel ();
283
284     /* Parse struct fields */
285     Size = 0;
286     while (CurTok.Tok != TOK_RCURLY) {
287
288         /* Get the type of the entry */
289         DeclSpec Spec;
290         InitDeclSpec (&Spec);
291         ParseTypeSpec (&Spec, -1);
292
293         /* Read fields with this type */
294         while (1) {
295
296             /* Get type and name of the struct field */
297             Declaration Decl;
298             ParseDecl (&Spec, &Decl, 0);
299
300             /* Add a field entry to the table */
301             AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
302
303             /* Calculate offset of next field/size of the union */
304             Offs = CheckedSizeOf (Decl.Type);
305             if (StructType == T_STRUCT) {
306                 Size += Offs;
307             } else {
308                 if (Offs > Size) {
309                     Size = Offs;
310                 }
311             }
312
313             if (CurTok.Tok != TOK_COMMA)
314                 break;
315             NextToken ();
316         }
317         ConsumeSemi ();
318     }
319
320     /* Skip the closing brace */
321     NextToken ();
322
323     /* Remember the symbol table and leave the struct level */
324     FieldTab = GetSymTab ();
325     LeaveStructLevel ();
326
327     /* Make a real entry from the forward decl and return it */
328     return AddStructSym (Name, Size, FieldTab);
329 }
330
331
332
333 static void ParseTypeSpec (DeclSpec* D, int Default)
334 /* Parse a type specificier */
335 {
336     ident       Ident;
337     SymEntry*   Entry;
338     type        StructType;
339     type        Qualifiers;     /* Type qualifiers */
340
341     /* Assume we have an explicit type */
342     D->Flags &= ~DS_DEF_TYPE;
343
344     /* Read type qualifiers if we have any */
345     Qualifiers = OptionalQualifiers (T_QUAL_NONE);
346
347     /* Look at the data type */
348     switch (CurTok.Tok) {
349
350         case TOK_VOID:
351             NextToken ();
352             D->Type[0] = T_VOID;
353             D->Type[1] = T_END;
354             break;
355
356         case TOK_CHAR:
357             NextToken ();
358             D->Type[0] = GetDefaultChar();
359             D->Type[1] = T_END;
360             break;
361
362         case TOK_LONG:
363             NextToken ();
364             if (CurTok.Tok == TOK_UNSIGNED) {
365                 NextToken ();
366                 optionalint ();
367                 D->Type[0] = T_ULONG;
368                 D->Type[1] = T_END;
369             } else {
370                 optionalsigned ();
371                 optionalint ();
372                 D->Type[0] = T_LONG;
373                 D->Type[1] = T_END;
374             }
375             break;
376
377         case TOK_SHORT:
378             NextToken ();
379             if (CurTok.Tok == TOK_UNSIGNED) {
380                 NextToken ();
381                 optionalint ();
382                 D->Type[0] = T_USHORT;
383                 D->Type[1] = T_END;
384             } else {
385                 optionalsigned ();
386                 optionalint ();
387                 D->Type[0] = T_SHORT;
388                 D->Type[1] = T_END;
389             }
390             break;
391
392         case TOK_INT:
393             NextToken ();
394             D->Type[0] = T_INT;
395             D->Type[1] = T_END;
396             break;
397
398        case TOK_SIGNED:
399             NextToken ();
400             switch (CurTok.Tok) {
401
402                 case TOK_CHAR:
403                     NextToken ();
404                     D->Type[0] = T_SCHAR;
405                     D->Type[1] = T_END;
406                     break;
407
408                 case TOK_SHORT:
409                     NextToken ();
410                     optionalint ();
411                     D->Type[0] = T_SHORT;
412                     D->Type[1] = T_END;
413                     break;
414
415                 case TOK_LONG:
416                     NextToken ();
417                     optionalint ();
418                     D->Type[0] = T_LONG;
419                     D->Type[1] = T_END;
420                     break;
421
422                 case TOK_INT:
423                     NextToken ();
424                     /* FALL THROUGH */
425
426                 default:
427                     D->Type[0] = T_INT;
428                     D->Type[1] = T_END;
429                     break;
430             }
431             break;
432
433         case TOK_UNSIGNED:
434             NextToken ();
435             switch (CurTok.Tok) {
436
437                 case TOK_CHAR:
438                     NextToken ();
439                     D->Type[0] = T_UCHAR;
440                     D->Type[1] = T_END;
441                     break;
442
443                 case TOK_SHORT:
444                     NextToken ();
445                     optionalint ();
446                     D->Type[0] = T_USHORT;
447                     D->Type[1] = T_END;
448                     break;
449
450                 case TOK_LONG:
451                     NextToken ();
452                     optionalint ();
453                     D->Type[0] = T_ULONG;
454                     D->Type[1] = T_END;
455                     break;
456
457                 case TOK_INT:
458                     NextToken ();
459                     /* FALL THROUGH */
460
461                 default:
462                     D->Type[0] = T_UINT;
463                     D->Type[1] = T_END;
464                     break;
465             }
466             break;
467
468         case TOK_STRUCT:
469         case TOK_UNION:
470             StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
471             NextToken ();
472             /* */
473             if (CurTok.Tok == TOK_IDENT) {
474                 strcpy (Ident, CurTok.Ident);
475                 NextToken ();
476             } else {
477                 AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
478             }
479             /* Remember we have an extra type decl */
480             D->Flags |= DS_EXTRA_TYPE;
481             /* Declare the struct in the current scope */
482             Entry = ParseStructDecl (Ident, StructType);
483             /* Encode the struct entry into the type */
484             D->Type[0] = StructType;
485             EncodePtr (D->Type+1, Entry);
486             D->Type[DECODE_SIZE+1] = T_END;
487             break;
488
489         case TOK_ENUM:
490             NextToken ();
491             if (CurTok.Tok != TOK_LCURLY) {
492                 /* Named enum */
493                 if (CurTok.Tok == TOK_IDENT) {
494                     /* Find an entry with this name */
495                     Entry = FindTagSym (CurTok.Ident);
496                     if (Entry) {
497                         if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
498                             Error ("Symbol `%s' is already different kind", Entry->Name);
499                         }
500                     } else {
501                         /* Insert entry into table ### */
502                     }
503                     /* Skip the identifier */
504                     NextToken ();
505                 } else {
506                     Error ("Identifier expected");
507                 }
508             }
509             /* Remember we have an extra type decl */
510             D->Flags |= DS_EXTRA_TYPE;
511             /* Parse the enum decl */
512             ParseEnumDecl ();
513             D->Type[0] = T_INT;
514             D->Type[1] = T_END;
515             break;
516
517         case TOK_IDENT:
518             Entry = FindSym (CurTok.Ident);
519             if (Entry && IsTypeDef (Entry)) {
520                 /* It's a typedef */
521                 NextToken ();
522                 TypeCpy (D->Type, Entry->Type);
523                 break;
524             }
525             /* FALL THROUGH */
526
527         default:
528             if (Default < 0) {
529                 Error ("Type expected");
530                 D->Type[0] = T_INT;
531                 D->Type[1] = T_END;
532             } else {
533                 D->Flags  |= DS_DEF_TYPE;
534                 D->Type[0] = (type) Default;
535                 D->Type[1] = T_END;
536             }
537             break;
538     }
539
540     /* There may also be qualifiers *after* the initial type */
541     D->Type[0] |= OptionalQualifiers (Qualifiers);
542 }
543
544
545
546 static type* ParamTypeCvt (type* T)
547 /* If T is an array, convert it to a pointer else do nothing. Return the
548  * resulting type.
549  */
550 {
551     if (IsTypeArray (T)) {
552         T += DECODE_SIZE;
553         T[0] = T_PTR;
554     }
555     return T;
556 }
557
558
559
560 static void ParseOldStyleParamList (FuncDesc* F)
561 /* Parse an old style (K&R) parameter list */
562 {
563     /* Parse params */
564     while (CurTok.Tok != TOK_RPAREN) {
565
566         /* List of identifiers expected */
567         if (CurTok.Tok != TOK_IDENT) {
568             Error ("Identifier expected");
569         }
570
571         /* Create a symbol table entry with type int */
572         AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF, 0);
573
574         /* Count arguments */
575         ++F->ParamCount;
576
577         /* Skip the identifier */
578         NextToken ();
579
580         /* Check for more parameters */
581         if (CurTok.Tok == TOK_COMMA) {
582             NextToken ();
583         } else {
584             break;
585         }
586     }
587
588     /* Skip right paren. We must explicitly check for one here, since some of
589      * the breaks above bail out without checking.
590      */
591     ConsumeRParen ();
592
593     /* An optional list of type specifications follows */
594     while (CurTok.Tok != TOK_LCURLY) {
595
596         DeclSpec        Spec;
597
598         /* Read the declaration specifier */
599         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
600
601         /* We accept only auto and register as storage class specifiers, but
602          * we ignore all this, since we use auto anyway.
603          */
604         if ((Spec.StorageClass & SC_AUTO) == 0 &&
605             (Spec.StorageClass & SC_REGISTER) == 0) {
606             Error ("Illegal storage class");
607         }
608
609         /* Parse a comma separated variable list */
610         while (1) {
611
612             Declaration         Decl;
613
614             /* Read the parameter */
615             ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
616             if (Decl.Ident[0] != '\0') {
617
618                 /* We have a name given. Search for the symbol */
619                 SymEntry* Sym = FindLocalSym (Decl.Ident);
620                 if (Sym) {
621                     /* Found it, change the default type to the one given */
622                     ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
623                 } else {
624                     Error ("Unknown identifier: `%s'", Decl.Ident);
625                 }
626             }
627
628             if (CurTok.Tok == TOK_COMMA) {
629                 NextToken ();
630             } else {
631                 break;
632             }
633
634         }
635
636         /* Variable list must be semicolon terminated */
637         ConsumeSemi ();
638     }
639 }
640
641
642
643 static void ParseAnsiParamList (FuncDesc* F)
644 /* Parse a new style (ANSI) parameter list */
645 {
646     /* Parse params */
647     while (CurTok.Tok != TOK_RPAREN) {
648
649         DeclSpec        Spec;
650         Declaration     Decl;
651         DeclAttr        Attr;
652
653         /* Allow an ellipsis as last parameter */
654         if (CurTok.Tok == TOK_ELLIPSIS) {
655             NextToken ();
656             F->Flags |= FD_VARIADIC;
657             break;
658         }
659
660         /* Read the declaration specifier */
661         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
662
663         /* We accept only auto and register as storage class specifiers, but
664          * we ignore all this and use auto.
665          */
666         if ((Spec.StorageClass & SC_AUTO) == 0 &&
667             (Spec.StorageClass & SC_REGISTER) == 0) {
668             Error ("Illegal storage class");
669         }
670         Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
671
672         /* Allow parameters without a name, but remember if we had some to
673          * eventually print an error message later.
674          */
675         ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
676         if (Decl.Ident[0] == '\0') {
677
678             /* Unnamed symbol. Generate a name that is not user accessible,
679              * then handle the symbol normal.
680              */
681             AnonName (Decl.Ident, "param");
682             F->Flags |= FD_UNNAMED_PARAMS;
683
684             /* Clear defined bit on nonames */
685             Spec.StorageClass &= ~SC_DEF;
686         }
687
688         /* Parse an attribute ### */
689         ParseAttribute (&Decl, &Attr);
690
691         /* Create a symbol table entry */
692         AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Spec.StorageClass, 0);
693
694         /* Count arguments */
695         ++F->ParamCount;
696
697         /* Check for more parameters */
698         if (CurTok.Tok == TOK_COMMA) {
699             NextToken ();
700         } else {
701             break;
702         }
703     }
704
705     /* Skip right paren. We must explicitly check for one here, since some of
706      * the breaks above bail out without checking.
707      */
708     ConsumeRParen ();
709
710     /* Check if this is a function definition */
711     if (CurTok.Tok == TOK_LCURLY) {
712         /* Print an error if in strict ANSI mode and we have unnamed
713          * parameters.
714          */
715         if (ANSI && (F->Flags & FD_UNNAMED_PARAMS) != 0) {
716             Error ("Parameter name omitted");
717         }
718     }
719 }
720
721
722
723 static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
724 /* Parse the argument list of a function. */
725 {
726     unsigned Offs;
727     SymEntry* Sym;
728
729     /* Create a new function descriptor */
730     FuncDesc* F = NewFuncDesc ();
731
732     /* Enter a new lexical level */
733     EnterFunctionLevel ();
734
735     /* Check for several special parameter lists */
736     if (CurTok.Tok == TOK_RPAREN) {
737         /* Parameter list is empty */
738         F->Flags |= (FD_EMPTY | FD_VARIADIC);
739     } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) {
740         /* Parameter list declared as void */
741         NextToken ();
742         F->Flags |= FD_VOID_PARAM;
743     } else if (CurTok.Tok == TOK_IDENT &&
744                (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) {
745         /* If the identifier is a typedef, we have a new style parameter list,
746          * if it's some other identifier, it's an old style parameter list.
747          */
748         Sym = FindSym (CurTok.Ident);
749         if (Sym == 0 || !IsTypeDef (Sym)) {
750             /* Old style (K&R) function. Assume variable param list. */
751             F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
752
753             /* Check for an implicit int return in the K&R function */
754             if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
755                 Spec->Type[0] == T_INT   &&
756                 Spec->Type[1] == T_END) {
757                 /* Function has an implicit int return */
758                 F->Flags |= FD_OLDSTYLE_INTRET;
759             }
760         }
761     }
762
763     /* Parse params */
764     if ((F->Flags & FD_OLDSTYLE) == 0) {
765         /* New style function */
766         ParseAnsiParamList (F);
767     } else {
768         /* Old style function */
769         ParseOldStyleParamList (F);
770     }
771
772     /* Assign offsets. If the function has a variable parameter list,
773      * there's one additional byte (the arg size).
774      */
775     Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
776     Sym = GetSymTab()->SymTail;
777     while (Sym) {
778         unsigned Size = CheckedSizeOf (Sym->Type);
779         Sym->V.Offs = Offs;
780         Offs += Size;
781         F->ParamSize += Size;
782         Sym = Sym->PrevSym;
783     }
784
785     /* Leave the lexical level remembering the symbol tables */
786     RememberFunctionLevel (F);
787
788     /* Return the function descriptor */
789     return F;
790 }
791
792
793
794 static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
795 /* Recursively process declarators. Build a type array in reverse order. */
796 {
797
798     if (CurTok.Tok == TOK_STAR) {
799         type T = T_PTR;
800         NextToken ();
801         /* Allow optional const or volatile qualifiers */
802         T |= OptionalQualifiers (T_QUAL_NONE);
803         Decl (Spec, D, Mode);
804         *D->T++ = T;
805         return;
806     } else if (CurTok.Tok == TOK_LPAREN) {
807         NextToken ();
808         Decl (Spec, D, Mode);
809         ConsumeRParen ();
810     } else if (CurTok.Tok == TOK_FASTCALL) {
811         /* Remember the current type pointer */
812         type* T = D->T;
813         /* Skip the fastcall token */
814         NextToken ();
815         /* Parse the function */
816         Decl (Spec, D, Mode);
817         /* Set the fastcall flag */
818         if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
819             Error ("__fastcall__ modifier applied to non function");
820         } else if (IsVariadicFunc (T)) {
821             Error ("Cannot apply __fastcall__ to functions with variable parameter list");
822         } else {
823             FuncDesc* F = GetFuncDesc (T);
824             F->Flags |= FD_FASTCALL;
825         }
826         return;
827     } else {
828         /* Things depend on Mode now:
829          *  - Mode == DM_NEED_IDENT means:
830          *      we *must* have a type and a variable identifer.
831          *  - Mode == DM_NO_IDENT means:
832          *      we must have a type but no variable identifer
833          *      (if there is one, it's not read).
834          *  - Mode == DM_ACCEPT_IDENT means:
835          *      we *may* have an identifier. If there is an identifier,
836          *      it is read, but it is no error, if there is none.
837          */
838         if (Mode == DM_NO_IDENT) {
839             D->Ident[0] = '\0';
840         } else if (CurTok.Tok == TOK_IDENT) {
841             strcpy (D->Ident, CurTok.Ident);
842             NextToken ();
843         } else {
844             if (Mode == DM_NEED_IDENT) {
845                 Error ("Identifier expected");
846             }
847             D->Ident[0] = '\0';
848         }
849     }
850
851     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
852         if (CurTok.Tok == TOK_LPAREN) {
853             /* Function declaration */
854             FuncDesc* F;
855             NextToken ();
856             /* Parse the function declaration */
857             F = ParseFuncDecl (Spec);
858             *D->T++ = T_FUNC;
859             EncodePtr (D->T, F);
860             D->T += DECODE_SIZE;
861         } else {
862             /* Array declaration */
863             unsigned long Size = 0;
864             NextToken ();
865             /* Read the size if it is given */
866             if (CurTok.Tok != TOK_RBRACK) {
867                 ExprDesc lval;
868                 ConstExpr (&lval);
869                 Size = lval.ConstVal;
870             }
871             ConsumeRBrack ();
872             *D->T++ = T_ARRAY;
873             Encode (D->T, Size);
874             D->T += DECODE_SIZE;
875         }
876     }
877 }
878
879
880
881 /*****************************************************************************/
882 /*                                   code                                    */
883 /*****************************************************************************/
884
885
886
887 type* ParseType (type* Type)
888 /* Parse a complete type specification */
889 {
890     DeclSpec Spec;
891     Declaration Decl;
892
893     /* Get a type without a default */
894     InitDeclSpec (&Spec);
895     ParseTypeSpec (&Spec, -1);
896
897     /* Parse additional declarators */
898     InitDeclaration (&Decl);
899     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
900
901     /* Copy the type to the target buffer */
902     TypeCpy (Type, Decl.Type);
903
904     /* Return a pointer to the target buffer */
905     return Type;
906 }
907
908
909
910 void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
911 /* Parse a variable, type or function declaration */
912 {
913     /* Initialize the Declaration struct */
914     InitDeclaration (D);
915
916     /* Get additional declarators and the identifier */
917     Decl (Spec, D, Mode);
918
919     /* Add the base type. */
920     TypeCpy (D->T, Spec->Type);
921
922     /* Check the size of the generated type */
923     if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
924         if (D->Ident[0] != '\0') {
925             Error ("Size of `%s' is invalid", D->Ident);
926         } else {
927             Error ("Invalid size");
928         }
929     }
930 }
931
932
933
934 void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
935 /* Parse a declaration specification */
936 {
937     /* Initialize the DeclSpec struct */
938     InitDeclSpec (D);
939
940     /* First, get the storage class specifier for this declaration */
941     ParseStorageClass (D, DefStorage);
942
943     /* Parse the type specifiers */
944     ParseTypeSpec (D, DefType);
945 }
946
947
948
949 void CheckEmptyDecl (const DeclSpec* D)
950 /* Called after an empty type declaration (that is, a type declaration without
951  * a variable). Checks if the declaration does really make sense and issues a
952  * warning if not.
953  */
954 {
955     if ((D->Flags & DS_EXTRA_TYPE) == 0) {
956         Warning ("Useless declaration");
957     }
958 }
959
960
961
962 static void ParseVoidInit (void)
963 /* Parse an initialization of a void variable (special cc65 extension) */
964 {
965     ExprDesc lval;
966
967     /* Allow an arbitrary list of values */
968     ConsumeLCurly ();
969     do {
970         ConstExpr (&lval);
971         switch (lval.Type[0]) {
972
973             case T_SCHAR:
974             case T_UCHAR:
975                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
976                     /* Make it byte sized */
977                     lval.ConstVal &= 0xFF;
978                 }
979                 DefineData (&lval);
980                 break;
981
982             case T_SHORT:
983             case T_USHORT:
984             case T_INT:
985             case T_UINT:
986             case T_PTR:
987             case T_ARRAY:
988                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
989                     /* Make it word sized */
990                     lval.ConstVal &= 0xFFFF;
991                 }
992                 DefineData (&lval);
993                 break;
994
995             case T_LONG:
996             case T_ULONG:
997                 DefineData (&lval);
998                 break;
999
1000             default:
1001                 Error ("Illegal type in initialization");
1002                 break;
1003
1004         }
1005
1006         if (CurTok.Tok != TOK_COMMA) {
1007             break;
1008         }
1009         NextToken ();
1010
1011     } while (CurTok.Tok != TOK_RCURLY);
1012
1013     ConsumeRCurly ();
1014 }
1015
1016
1017
1018 static void ParseStructInit (type* Type)
1019 /* Parse initialization of a struct or union */
1020 {
1021     SymEntry* Entry;
1022     SymTable* Tab;
1023
1024     /* Consume the opening curly brace */
1025     ConsumeLCurly ();
1026
1027     /* Get a pointer to the struct entry from the type */
1028     Entry = (SymEntry*) Decode (Type + 1);
1029
1030     /* Check if this struct definition has a field table. If it doesn't, it
1031      * is an incomplete definition.
1032      */
1033     Tab = Entry->V.S.SymTab;
1034     if (Tab == 0) {
1035         Error ("Cannot initialize variables with incomplete type");
1036         /* Returning here will cause lots of errors, but recovery is difficult */
1037         return;
1038     }
1039
1040     /* Get a pointer to the list of symbols */
1041     Entry = Tab->SymHead;
1042     while (CurTok.Tok != TOK_RCURLY) {
1043         if (Entry == 0) {
1044             Error ("Too many initializers");
1045             return;
1046         }
1047         ParseInit (Entry->Type);
1048         Entry = Entry->NextSym;
1049         if (CurTok.Tok != TOK_COMMA)
1050             break;
1051         NextToken ();
1052     }
1053
1054     /* Consume the closing curly brace */
1055     ConsumeRCurly ();
1056
1057     /* If there are struct fields left, reserve additional storage */
1058     while (Entry) {
1059         g_zerobytes (CheckedSizeOf (Entry->Type));
1060         Entry = Entry->NextSym;
1061     }
1062 }
1063
1064
1065
1066 void ParseInit (type* T)
1067 /* Parse initialization of variables. */
1068 {
1069     ExprDesc lval;
1070     type* t;
1071     const char* str;
1072     int Count;
1073     int Size;
1074
1075     switch (UnqualifiedType (*T)) {
1076
1077         case T_SCHAR:
1078         case T_UCHAR:
1079             ConstExpr (&lval);
1080             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1081                 /* Make it byte sized */
1082                 lval.ConstVal &= 0xFF;
1083             }
1084             assignadjust (T, &lval);
1085             DefineData (&lval);
1086             break;
1087
1088         case T_SHORT:
1089         case T_USHORT:
1090         case T_INT:
1091         case T_UINT:
1092         case T_PTR:
1093             ConstExpr (&lval);
1094             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1095                 /* Make it word sized */
1096                 lval.ConstVal &= 0xFFFF;
1097             }
1098             assignadjust (T, &lval);
1099             DefineData (&lval);
1100             break;
1101
1102         case T_LONG:
1103         case T_ULONG:
1104             ConstExpr (&lval);
1105             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1106                 /* Make it long sized */
1107                 lval.ConstVal &= 0xFFFFFFFF;
1108             }
1109             assignadjust (T, &lval);
1110             DefineData (&lval);
1111             break;
1112
1113         case T_ARRAY:
1114             Size = Decode (T + 1);
1115             t = T + DECODE_SIZE + 1;
1116             if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) {
1117                 str = GetLiteral (CurTok.IVal);
1118                 Count = strlen (str) + 1;
1119                 TranslateLiteralPool (CurTok.IVal);     /* Translate into target charset */
1120                 g_defbytes (str, Count);
1121                 ResetLiteralPoolOffs (CurTok.IVal);     /* Remove string from pool */
1122                 NextToken ();
1123             } else {
1124                 ConsumeLCurly ();
1125                 Count = 0;
1126                 while (CurTok.Tok != TOK_RCURLY) {
1127                     ParseInit (T + DECODE_SIZE + 1);
1128                     ++Count;
1129                     if (CurTok.Tok != TOK_COMMA)
1130                         break;
1131                     NextToken ();
1132                 }
1133                 ConsumeRCurly ();
1134             }
1135             if (Size == 0) {
1136                 Encode (T + 1, Count);
1137             } else if (Count < Size) {
1138                 g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1));
1139             } else if (Count > Size) {
1140                 Error ("Too many initializers");
1141             }
1142             break;
1143
1144         case T_STRUCT:
1145         case T_UNION:
1146             ParseStructInit (T);
1147             break;
1148
1149         case T_VOID:
1150             if (!ANSI) {
1151                 /* Special cc65 extension in non ANSI mode */
1152                 ParseVoidInit ();
1153                 break;
1154             }
1155             /* FALLTHROUGH */
1156
1157         default:
1158             Error ("Illegal type");
1159             break;
1160
1161     }
1162 }
1163
1164
1165