]> git.sur5r.net Git - cc65/blob - src/cc65/declare.c
Track usage of the sreg and several other zero page registers and remove
[cc65] / src / cc65 / declare.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 declare.c                                 */
4 /*                                                                           */
5 /*                 Parse variable and function declarations                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2001 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 = SizeOf (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 (void)
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     }
754
755     /* Parse params */
756     if ((F->Flags & FD_OLDSTYLE) == 0) {
757         /* New style function */
758         ParseAnsiParamList (F);
759     } else {
760         /* Old style function */
761         ParseOldStyleParamList (F);
762     }
763
764     /* Assign offsets. If the function has a variable parameter list,
765      * there's one additional byte (the arg size).
766      */
767     Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
768     Sym = GetSymTab()->SymTail;
769     while (Sym) {
770         unsigned Size = SizeOf (Sym->Type);
771         Sym->V.Offs = Offs;
772         Offs += Size;
773         F->ParamSize += Size;
774         Sym = Sym->PrevSym;
775     }
776
777     /* Leave the lexical level remembering the symbol tables */
778     RememberFunctionLevel (F);
779
780     /* Return the function descriptor */
781     return F;
782 }
783
784
785
786 static void Decl (Declaration* D, unsigned Mode)
787 /* Recursively process declarators. Build a type array in reverse order. */
788 {
789
790     if (CurTok.Tok == TOK_STAR) {
791         type T = T_PTR;
792         NextToken ();
793         /* Allow optional const or volatile qualifiers */
794         T |= OptionalQualifiers (T_QUAL_NONE);
795         Decl (D, Mode);
796         *D->T++ = T;
797         return;
798     } else if (CurTok.Tok == TOK_LPAREN) {
799         NextToken ();
800         Decl (D, Mode);
801         ConsumeRParen ();
802     } else if (CurTok.Tok == TOK_FASTCALL) {
803         /* Remember the current type pointer */
804         type* T = D->T;
805         /* Skip the fastcall token */
806         NextToken ();
807         /* Parse the function */
808         Decl (D, Mode);
809         /* Set the fastcall flag */
810         if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
811             Error ("__fastcall__ modifier applied to non function");
812         } else if (IsVariadicFunc (T)) {
813             Error ("Cannot apply __fastcall__ to functions with variable parameter list");
814         } else {
815             FuncDesc* F = GetFuncDesc (T);
816             F->Flags |= FD_FASTCALL;
817         }
818         return;
819     } else {
820         /* Things depend on Mode now:
821          *  - Mode == DM_NEED_IDENT means:
822          *      we *must* have a type and a variable identifer.
823          *  - Mode == DM_NO_IDENT means:
824          *      we must have a type but no variable identifer
825          *      (if there is one, it's not read).
826          *  - Mode == DM_ACCEPT_IDENT means:
827          *      we *may* have an identifier. If there is an identifier,
828          *      it is read, but it is no error, if there is none.
829          */
830         if (Mode == DM_NO_IDENT) {
831             D->Ident[0] = '\0';
832         } else if (CurTok.Tok == TOK_IDENT) {
833             strcpy (D->Ident, CurTok.Ident);
834             NextToken ();
835         } else {
836             if (Mode == DM_NEED_IDENT) {
837                 Error ("Identifier expected");
838             }
839             D->Ident[0] = '\0';
840             return;
841         }
842     }
843
844     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
845         if (CurTok.Tok == TOK_LPAREN) {
846             /* Function declaration */
847             FuncDesc* F;
848             NextToken ();
849             /* Parse the function declaration */
850             F = ParseFuncDecl ();
851             *D->T++ = T_FUNC;
852             EncodePtr (D->T, F);
853             D->T += DECODE_SIZE;
854         } else {
855             /* Array declaration */
856             unsigned long Size = 0;
857             NextToken ();
858             /* Read the size if it is given */
859             if (CurTok.Tok != TOK_RBRACK) {
860                 ExprDesc lval;
861                 constexpr (&lval);
862                 Size = lval.ConstVal;
863             }
864             ConsumeRBrack ();
865             *D->T++ = T_ARRAY;
866             Encode (D->T, Size);
867             D->T += DECODE_SIZE;
868         }
869     }
870 }
871
872
873
874 /*****************************************************************************/
875 /*                                   code                                    */
876 /*****************************************************************************/
877
878
879
880 type* ParseType (type* Type)
881 /* Parse a complete type specification */
882 {
883     DeclSpec Spec;
884     Declaration Decl;
885
886     /* Get a type without a default */
887     InitDeclSpec (&Spec);
888     ParseTypeSpec (&Spec, -1);
889
890     /* Parse additional declarators */
891     InitDeclaration (&Decl);
892     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
893
894     /* Copy the type to the target buffer */
895     TypeCpy (Type, Decl.Type);
896
897     /* Return a pointer to the target buffer */
898     return Type;
899 }
900
901
902
903 void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
904 /* Parse a variable, type or function declaration */
905 {
906     /* Initialize the Declaration struct */
907     InitDeclaration (D);
908
909     /* Get additional declarators and the identifier */
910     Decl (D, Mode);
911
912     /* Add the base type. */
913     TypeCpy (D->T, Spec->Type);
914
915     /* Check the size of the generated type */
916     if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
917         if (D->Ident[0] != '\0') {
918             Error ("Size of `%s' is invalid", D->Ident);
919         } else {
920             Error ("Invalid size");
921         }
922     }
923 }
924
925
926
927 void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
928 /* Parse a declaration specification */
929 {
930     /* Initialize the DeclSpec struct */
931     InitDeclSpec (D);
932
933     /* First, get the storage class specifier for this declaration */
934     ParseStorageClass (D, DefStorage);
935
936     /* Parse the type specifiers */
937     ParseTypeSpec (D, DefType);
938 }
939
940
941
942 void CheckEmptyDecl (const DeclSpec* D)
943 /* Called after an empty type declaration (that is, a type declaration without
944  * a variable). Checks if the declaration does really make sense and issues a
945  * warning if not.
946  */
947 {
948     if ((D->Flags & DS_EXTRA_TYPE) == 0) {
949         Warning ("Useless declaration");
950     }
951 }
952
953
954
955 static void ParseVoidInit (void)
956 /* Parse an initialization of a void variable (special cc65 extension) */
957 {
958     ExprDesc lval;
959
960     /* Allow an arbitrary list of values */
961     ConsumeLCurly ();
962     do {
963         constexpr (&lval);
964         switch (lval.Type[0]) {
965
966             case T_SCHAR:
967             case T_UCHAR:
968                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
969                     /* Make it byte sized */
970                     lval.ConstVal &= 0xFF;
971                 }
972                 DefineData (&lval);
973                 break;
974
975             case T_SHORT:
976             case T_USHORT:
977             case T_INT:
978             case T_UINT:
979             case T_PTR:
980             case T_ARRAY:
981                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
982                     /* Make it word sized */
983                     lval.ConstVal &= 0xFFFF;
984                 }
985                 DefineData (&lval);
986                 break;
987
988             case T_LONG:
989             case T_ULONG:
990                 DefineData (&lval);
991                 break;
992
993             default:
994                 Error ("Illegal type in initialization");
995                 break;
996
997         }
998
999         if (CurTok.Tok != TOK_COMMA) {
1000             break;
1001         }
1002         NextToken ();
1003
1004     } while (CurTok.Tok != TOK_RCURLY);
1005
1006     ConsumeRCurly ();
1007 }
1008
1009
1010
1011 static void ParseStructInit (type* Type)
1012 /* Parse initialization of a struct or union */
1013 {
1014     SymEntry* Entry;
1015     SymTable* Tab;
1016
1017     /* Consume the opening curly brace */
1018     ConsumeLCurly ();
1019
1020     /* Get a pointer to the struct entry from the type */
1021     Entry = (SymEntry*) Decode (Type + 1);
1022
1023     /* Check if this struct definition has a field table. If it doesn't, it
1024      * is an incomplete definition.
1025      */
1026     Tab = Entry->V.S.SymTab;
1027     if (Tab == 0) {
1028         Error ("Cannot initialize variables with incomplete type");
1029         /* Returning here will cause lots of errors, but recovery is difficult */
1030         return;
1031     }
1032
1033     /* Get a pointer to the list of symbols */
1034     Entry = Tab->SymHead;
1035     while (CurTok.Tok != TOK_RCURLY) {
1036         if (Entry == 0) {
1037             Error ("Too many initializers");
1038             return;
1039         }
1040         ParseInit (Entry->Type);
1041         Entry = Entry->NextSym;
1042         if (CurTok.Tok != TOK_COMMA)
1043             break;
1044         NextToken ();
1045     }
1046
1047     /* Consume the closing curly brace */
1048     ConsumeRCurly ();
1049
1050     /* If there are struct fields left, reserve additional storage */
1051     while (Entry) {
1052         g_zerobytes (SizeOf (Entry->Type));
1053         Entry = Entry->NextSym;
1054     }
1055 }
1056
1057
1058
1059 void ParseInit (type* T)
1060 /* Parse initialization of variables. */
1061 {
1062     ExprDesc lval;
1063     type* t;
1064     const char* str;
1065     int Count;
1066     int Size;
1067
1068     switch (UnqualifiedType (*T)) {
1069
1070         case T_SCHAR:
1071         case T_UCHAR:
1072             constexpr (&lval);
1073             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1074                 /* Make it byte sized */
1075                 lval.ConstVal &= 0xFF;
1076             }
1077             assignadjust (T, &lval);
1078             DefineData (&lval);
1079             break;
1080
1081         case T_SHORT:
1082         case T_USHORT:
1083         case T_INT:
1084         case T_UINT:
1085         case T_PTR:
1086             constexpr (&lval);
1087             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1088                 /* Make it word sized */
1089                 lval.ConstVal &= 0xFFFF;
1090             }
1091             assignadjust (T, &lval);
1092             DefineData (&lval);
1093             break;
1094
1095         case T_LONG:
1096         case T_ULONG:
1097             constexpr (&lval);
1098             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1099                 /* Make it long sized */
1100                 lval.ConstVal &= 0xFFFFFFFF;
1101             }
1102             assignadjust (T, &lval);
1103             DefineData (&lval);
1104             break;
1105
1106         case T_ARRAY:
1107             Size = Decode (T + 1);
1108             t = T + DECODE_SIZE + 1;
1109             if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) {
1110                 str = GetLiteral (CurTok.IVal);
1111                 Count = strlen (str) + 1;
1112                 TranslateLiteralPool (CurTok.IVal);     /* Translate into target charset */
1113                 g_defbytes (str, Count);
1114                 ResetLiteralPoolOffs (CurTok.IVal);     /* Remove string from pool */
1115                 NextToken ();
1116             } else {
1117                 ConsumeLCurly ();
1118                 Count = 0;
1119                 while (CurTok.Tok != TOK_RCURLY) {
1120                     ParseInit (T + DECODE_SIZE + 1);
1121                     ++Count;
1122                     if (CurTok.Tok != TOK_COMMA)
1123                         break;
1124                     NextToken ();
1125                 }
1126                 ConsumeRCurly ();
1127             }
1128             if (Size == 0) {
1129                 Encode (T + 1, Count);
1130             } else if (Count < Size) {
1131                 g_zerobytes ((Size - Count) * SizeOf (T + DECODE_SIZE + 1));
1132             } else if (Count > Size) {
1133                 Error ("Too many initializers");
1134             }
1135             break;
1136
1137         case T_STRUCT:
1138         case T_UNION:
1139             ParseStructInit (T);
1140             break;
1141
1142         case T_VOID:
1143             if (!ANSI) {
1144                 /* Special cc65 extension in non ANSI mode */
1145                 ParseVoidInit ();
1146                 break;
1147             }
1148             /* FALLTHROUGH */
1149
1150         default:
1151             Error ("Illegal type");
1152             break;
1153
1154     }
1155 }
1156
1157
1158