]> git.sur5r.net Git - cc65/blob - src/cc65/declare.c
9989cd4cee8151a726337034afe10ee86cba2075
[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             return;
849         }
850     }
851
852     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
853         if (CurTok.Tok == TOK_LPAREN) {
854             /* Function declaration */
855             FuncDesc* F;
856             NextToken ();
857             /* Parse the function declaration */
858             F = ParseFuncDecl (Spec);
859             *D->T++ = T_FUNC;
860             EncodePtr (D->T, F);
861             D->T += DECODE_SIZE;
862         } else {
863             /* Array declaration */
864             unsigned long Size = 0;
865             NextToken ();
866             /* Read the size if it is given */
867             if (CurTok.Tok != TOK_RBRACK) {
868                 ExprDesc lval;
869                 ConstExpr (&lval);
870                 Size = lval.ConstVal;
871             }
872             ConsumeRBrack ();
873             *D->T++ = T_ARRAY;
874             Encode (D->T, Size);
875             D->T += DECODE_SIZE;
876         }
877     }
878 }
879
880
881
882 /*****************************************************************************/
883 /*                                   code                                    */
884 /*****************************************************************************/
885
886
887
888 type* ParseType (type* Type)
889 /* Parse a complete type specification */
890 {
891     DeclSpec Spec;
892     Declaration Decl;
893
894     /* Get a type without a default */
895     InitDeclSpec (&Spec);
896     ParseTypeSpec (&Spec, -1);
897
898     /* Parse additional declarators */
899     InitDeclaration (&Decl);
900     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
901
902     /* Copy the type to the target buffer */
903     TypeCpy (Type, Decl.Type);
904
905     /* Return a pointer to the target buffer */
906     return Type;
907 }
908
909
910
911 void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
912 /* Parse a variable, type or function declaration */
913 {
914     /* Initialize the Declaration struct */
915     InitDeclaration (D);
916
917     /* Get additional declarators and the identifier */
918     Decl (Spec, D, Mode);
919
920     /* Add the base type. */
921     TypeCpy (D->T, Spec->Type);
922
923     /* Check the size of the generated type */
924     if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
925         if (D->Ident[0] != '\0') {
926             Error ("Size of `%s' is invalid", D->Ident);
927         } else {
928             Error ("Invalid size");
929         }
930     }
931 }
932
933
934
935 void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
936 /* Parse a declaration specification */
937 {
938     /* Initialize the DeclSpec struct */
939     InitDeclSpec (D);
940
941     /* First, get the storage class specifier for this declaration */
942     ParseStorageClass (D, DefStorage);
943
944     /* Parse the type specifiers */
945     ParseTypeSpec (D, DefType);
946 }
947
948
949
950 void CheckEmptyDecl (const DeclSpec* D)
951 /* Called after an empty type declaration (that is, a type declaration without
952  * a variable). Checks if the declaration does really make sense and issues a
953  * warning if not.
954  */
955 {
956     if ((D->Flags & DS_EXTRA_TYPE) == 0) {
957         Warning ("Useless declaration");
958     }
959 }
960
961
962
963 static void ParseVoidInit (void)
964 /* Parse an initialization of a void variable (special cc65 extension) */
965 {
966     ExprDesc lval;
967
968     /* Allow an arbitrary list of values */
969     ConsumeLCurly ();
970     do {
971         ConstExpr (&lval);
972         switch (lval.Type[0]) {
973
974             case T_SCHAR:
975             case T_UCHAR:
976                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
977                     /* Make it byte sized */
978                     lval.ConstVal &= 0xFF;
979                 }
980                 DefineData (&lval);
981                 break;
982
983             case T_SHORT:
984             case T_USHORT:
985             case T_INT:
986             case T_UINT:
987             case T_PTR:
988             case T_ARRAY:
989                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
990                     /* Make it word sized */
991                     lval.ConstVal &= 0xFFFF;
992                 }
993                 DefineData (&lval);
994                 break;
995
996             case T_LONG:
997             case T_ULONG:
998                 DefineData (&lval);
999                 break;
1000
1001             default:
1002                 Error ("Illegal type in initialization");
1003                 break;
1004
1005         }
1006
1007         if (CurTok.Tok != TOK_COMMA) {
1008             break;
1009         }
1010         NextToken ();
1011
1012     } while (CurTok.Tok != TOK_RCURLY);
1013
1014     ConsumeRCurly ();
1015 }
1016
1017
1018
1019 static void ParseStructInit (type* Type)
1020 /* Parse initialization of a struct or union */
1021 {
1022     SymEntry* Entry;
1023     SymTable* Tab;
1024
1025     /* Consume the opening curly brace */
1026     ConsumeLCurly ();
1027
1028     /* Get a pointer to the struct entry from the type */
1029     Entry = (SymEntry*) Decode (Type + 1);
1030
1031     /* Check if this struct definition has a field table. If it doesn't, it
1032      * is an incomplete definition.
1033      */
1034     Tab = Entry->V.S.SymTab;
1035     if (Tab == 0) {
1036         Error ("Cannot initialize variables with incomplete type");
1037         /* Returning here will cause lots of errors, but recovery is difficult */
1038         return;
1039     }
1040
1041     /* Get a pointer to the list of symbols */
1042     Entry = Tab->SymHead;
1043     while (CurTok.Tok != TOK_RCURLY) {
1044         if (Entry == 0) {
1045             Error ("Too many initializers");
1046             return;
1047         }
1048         ParseInit (Entry->Type);
1049         Entry = Entry->NextSym;
1050         if (CurTok.Tok != TOK_COMMA)
1051             break;
1052         NextToken ();
1053     }
1054
1055     /* Consume the closing curly brace */
1056     ConsumeRCurly ();
1057
1058     /* If there are struct fields left, reserve additional storage */
1059     while (Entry) {
1060         g_zerobytes (CheckedSizeOf (Entry->Type));
1061         Entry = Entry->NextSym;
1062     }
1063 }
1064
1065
1066
1067 void ParseInit (type* T)
1068 /* Parse initialization of variables. */
1069 {
1070     ExprDesc lval;
1071     type* t;
1072     const char* str;
1073     int Count;
1074     int Size;
1075
1076     switch (UnqualifiedType (*T)) {
1077
1078         case T_SCHAR:
1079         case T_UCHAR:
1080             ConstExpr (&lval);
1081             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1082                 /* Make it byte sized */
1083                 lval.ConstVal &= 0xFF;
1084             }
1085             assignadjust (T, &lval);
1086             DefineData (&lval);
1087             break;
1088
1089         case T_SHORT:
1090         case T_USHORT:
1091         case T_INT:
1092         case T_UINT:
1093         case T_PTR:
1094             ConstExpr (&lval);
1095             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1096                 /* Make it word sized */
1097                 lval.ConstVal &= 0xFFFF;
1098             }
1099             assignadjust (T, &lval);
1100             DefineData (&lval);
1101             break;
1102
1103         case T_LONG:
1104         case T_ULONG:
1105             ConstExpr (&lval);
1106             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1107                 /* Make it long sized */
1108                 lval.ConstVal &= 0xFFFFFFFF;
1109             }
1110             assignadjust (T, &lval);
1111             DefineData (&lval);
1112             break;
1113
1114         case T_ARRAY:
1115             Size = Decode (T + 1);
1116             t = T + DECODE_SIZE + 1;
1117             if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) {
1118                 str = GetLiteral (CurTok.IVal);
1119                 Count = strlen (str) + 1;
1120                 TranslateLiteralPool (CurTok.IVal);     /* Translate into target charset */
1121                 g_defbytes (str, Count);
1122                 ResetLiteralPoolOffs (CurTok.IVal);     /* Remove string from pool */
1123                 NextToken ();
1124             } else {
1125                 ConsumeLCurly ();
1126                 Count = 0;
1127                 while (CurTok.Tok != TOK_RCURLY) {
1128                     ParseInit (T + DECODE_SIZE + 1);
1129                     ++Count;
1130                     if (CurTok.Tok != TOK_COMMA)
1131                         break;
1132                     NextToken ();
1133                 }
1134                 ConsumeRCurly ();
1135             }
1136             if (Size == 0) {
1137                 Encode (T + 1, Count);
1138             } else if (Count < Size) {
1139                 g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1));
1140             } else if (Count > Size) {
1141                 Error ("Too many initializers");
1142             }
1143             break;
1144
1145         case T_STRUCT:
1146         case T_UNION:
1147             ParseStructInit (T);
1148             break;
1149
1150         case T_VOID:
1151             if (!ANSI) {
1152                 /* Special cc65 extension in non ANSI mode */
1153                 ParseVoidInit ();
1154                 break;
1155             }
1156             /* FALLTHROUGH */
1157
1158         default:
1159             Error ("Illegal type");
1160             break;
1161
1162     }
1163 }
1164
1165
1166