]> git.sur5r.net Git - cc65/blob - src/cc65/declare.c
Check for implicit int return in all cases
[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             /* Get the offset of this field */
301             Offs = (StructType == T_STRUCT)? Size : 0;
302
303             /* Add a field entry to the table */
304             AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
305
306             /* Calculate offset of next field/size of the union */
307             Offs = CheckedSizeOf (Decl.Type);
308             if (StructType == T_STRUCT) {
309                 Size += Offs;
310             } else {
311                 if (Offs > Size) {
312                     Size = Offs;
313                 }
314             }
315
316             if (CurTok.Tok != TOK_COMMA)
317                 break;
318             NextToken ();
319         }
320         ConsumeSemi ();
321     }
322
323     /* Skip the closing brace */
324     NextToken ();
325
326     /* Remember the symbol table and leave the struct level */
327     FieldTab = GetSymTab ();
328     LeaveStructLevel ();
329
330     /* Make a real entry from the forward decl and return it */
331     return AddStructSym (Name, Size, FieldTab);
332 }
333
334
335
336 static void ParseTypeSpec (DeclSpec* D, int Default)
337 /* Parse a type specificier */
338 {
339     ident       Ident;
340     SymEntry*   Entry;
341     type        StructType;
342     type        Qualifiers;     /* Type qualifiers */
343
344     /* Assume we have an explicit type */
345     D->Flags &= ~DS_DEF_TYPE;
346
347     /* Read type qualifiers if we have any */
348     Qualifiers = OptionalQualifiers (T_QUAL_NONE);
349
350     /* Look at the data type */
351     switch (CurTok.Tok) {
352
353         case TOK_VOID:
354             NextToken ();
355             D->Type[0] = T_VOID;
356             D->Type[1] = T_END;
357             break;
358
359         case TOK_CHAR:
360             NextToken ();
361             D->Type[0] = GetDefaultChar();
362             D->Type[1] = T_END;
363             break;
364
365         case TOK_LONG:
366             NextToken ();
367             if (CurTok.Tok == TOK_UNSIGNED) {
368                 NextToken ();
369                 optionalint ();
370                 D->Type[0] = T_ULONG;
371                 D->Type[1] = T_END;
372             } else {
373                 optionalsigned ();
374                 optionalint ();
375                 D->Type[0] = T_LONG;
376                 D->Type[1] = T_END;
377             }
378             break;
379
380         case TOK_SHORT:
381             NextToken ();
382             if (CurTok.Tok == TOK_UNSIGNED) {
383                 NextToken ();
384                 optionalint ();
385                 D->Type[0] = T_USHORT;
386                 D->Type[1] = T_END;
387             } else {
388                 optionalsigned ();
389                 optionalint ();
390                 D->Type[0] = T_SHORT;
391                 D->Type[1] = T_END;
392             }
393             break;
394
395         case TOK_INT:
396             NextToken ();
397             D->Type[0] = T_INT;
398             D->Type[1] = T_END;
399             break;
400
401        case TOK_SIGNED:
402             NextToken ();
403             switch (CurTok.Tok) {
404
405                 case TOK_CHAR:
406                     NextToken ();
407                     D->Type[0] = T_SCHAR;
408                     D->Type[1] = T_END;
409                     break;
410
411                 case TOK_SHORT:
412                     NextToken ();
413                     optionalint ();
414                     D->Type[0] = T_SHORT;
415                     D->Type[1] = T_END;
416                     break;
417
418                 case TOK_LONG:
419                     NextToken ();
420                     optionalint ();
421                     D->Type[0] = T_LONG;
422                     D->Type[1] = T_END;
423                     break;
424
425                 case TOK_INT:
426                     NextToken ();
427                     /* FALL THROUGH */
428
429                 default:
430                     D->Type[0] = T_INT;
431                     D->Type[1] = T_END;
432                     break;
433             }
434             break;
435
436         case TOK_UNSIGNED:
437             NextToken ();
438             switch (CurTok.Tok) {
439
440                 case TOK_CHAR:
441                     NextToken ();
442                     D->Type[0] = T_UCHAR;
443                     D->Type[1] = T_END;
444                     break;
445
446                 case TOK_SHORT:
447                     NextToken ();
448                     optionalint ();
449                     D->Type[0] = T_USHORT;
450                     D->Type[1] = T_END;
451                     break;
452
453                 case TOK_LONG:
454                     NextToken ();
455                     optionalint ();
456                     D->Type[0] = T_ULONG;
457                     D->Type[1] = T_END;
458                     break;
459
460                 case TOK_INT:
461                     NextToken ();
462                     /* FALL THROUGH */
463
464                 default:
465                     D->Type[0] = T_UINT;
466                     D->Type[1] = T_END;
467                     break;
468             }
469             break;
470
471         case TOK_STRUCT:
472         case TOK_UNION:
473             StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
474             NextToken ();
475             /* */
476             if (CurTok.Tok == TOK_IDENT) {
477                 strcpy (Ident, CurTok.Ident);
478                 NextToken ();
479             } else {
480                 AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
481             }
482             /* Remember we have an extra type decl */
483             D->Flags |= DS_EXTRA_TYPE;
484             /* Declare the struct in the current scope */
485             Entry = ParseStructDecl (Ident, StructType);
486             /* Encode the struct entry into the type */
487             D->Type[0] = StructType;
488             EncodePtr (D->Type+1, Entry);
489             D->Type[DECODE_SIZE+1] = T_END;
490             break;
491
492         case TOK_ENUM:
493             NextToken ();
494             if (CurTok.Tok != TOK_LCURLY) {
495                 /* Named enum */
496                 if (CurTok.Tok == TOK_IDENT) {
497                     /* Find an entry with this name */
498                     Entry = FindTagSym (CurTok.Ident);
499                     if (Entry) {
500                         if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
501                             Error ("Symbol `%s' is already different kind", Entry->Name);
502                         }
503                     } else {
504                         /* Insert entry into table ### */
505                     }
506                     /* Skip the identifier */
507                     NextToken ();
508                 } else {
509                     Error ("Identifier expected");
510                 }
511             }
512             /* Remember we have an extra type decl */
513             D->Flags |= DS_EXTRA_TYPE;
514             /* Parse the enum decl */
515             ParseEnumDecl ();
516             D->Type[0] = T_INT;
517             D->Type[1] = T_END;
518             break;
519
520         case TOK_IDENT:
521             Entry = FindSym (CurTok.Ident);
522             if (Entry && SymIsTypeDef (Entry)) {
523                 /* It's a typedef */
524                 NextToken ();
525                 TypeCpy (D->Type, Entry->Type);
526                 break;
527             }
528             /* FALL THROUGH */
529
530         default:
531             if (Default < 0) {
532                 Error ("Type expected");
533                 D->Type[0] = T_INT;
534                 D->Type[1] = T_END;
535             } else {
536                 D->Flags  |= DS_DEF_TYPE;
537                 D->Type[0] = (type) Default;
538                 D->Type[1] = T_END;
539             }
540             break;
541     }
542
543     /* There may also be qualifiers *after* the initial type */
544     D->Type[0] |= OptionalQualifiers (Qualifiers);
545 }
546
547
548
549 static type* ParamTypeCvt (type* T)
550 /* If T is an array, convert it to a pointer else do nothing. Return the
551  * resulting type.
552  */
553 {
554     if (IsTypeArray (T)) {
555         T += DECODE_SIZE;
556         T[0] = T_PTR;
557     }
558     return T;
559 }
560
561
562
563 static void ParseOldStyleParamList (FuncDesc* F)
564 /* Parse an old style (K&R) parameter list */
565 {
566     /* Parse params */
567     while (CurTok.Tok != TOK_RPAREN) {
568
569         /* List of identifiers expected */
570         if (CurTok.Tok != TOK_IDENT) {
571             Error ("Identifier expected");
572         }
573
574         /* Create a symbol table entry with type int */
575         AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF, 0);
576
577         /* Count arguments */
578         ++F->ParamCount;
579
580         /* Skip the identifier */
581         NextToken ();
582
583         /* Check for more parameters */
584         if (CurTok.Tok == TOK_COMMA) {
585             NextToken ();
586         } else {
587             break;
588         }
589     }
590
591     /* Skip right paren. We must explicitly check for one here, since some of
592      * the breaks above bail out without checking.
593      */
594     ConsumeRParen ();
595
596     /* An optional list of type specifications follows */
597     while (CurTok.Tok != TOK_LCURLY) {
598
599         DeclSpec        Spec;
600
601         /* Read the declaration specifier */
602         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
603
604         /* We accept only auto and register as storage class specifiers, but
605          * we ignore all this, since we use auto anyway.
606          */
607         if ((Spec.StorageClass & SC_AUTO) == 0 &&
608             (Spec.StorageClass & SC_REGISTER) == 0) {
609             Error ("Illegal storage class");
610         }
611
612         /* Parse a comma separated variable list */
613         while (1) {
614
615             Declaration         Decl;
616
617             /* Read the parameter */
618             ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
619             if (Decl.Ident[0] != '\0') {
620
621                 /* We have a name given. Search for the symbol */
622                 SymEntry* Sym = FindLocalSym (Decl.Ident);
623                 if (Sym) {
624                     /* Found it, change the default type to the one given */
625                     ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
626                 } else {
627                     Error ("Unknown identifier: `%s'", Decl.Ident);
628                 }
629             }
630
631             if (CurTok.Tok == TOK_COMMA) {
632                 NextToken ();
633             } else {
634                 break;
635             }
636
637         }
638
639         /* Variable list must be semicolon terminated */
640         ConsumeSemi ();
641     }
642 }
643
644
645
646 static void ParseAnsiParamList (FuncDesc* F)
647 /* Parse a new style (ANSI) parameter list */
648 {
649     /* Parse params */
650     while (CurTok.Tok != TOK_RPAREN) {
651
652         DeclSpec        Spec;
653         Declaration     Decl;
654         DeclAttr        Attr;
655
656         /* Allow an ellipsis as last parameter */
657         if (CurTok.Tok == TOK_ELLIPSIS) {
658             NextToken ();
659             F->Flags |= FD_VARIADIC;
660             break;
661         }
662
663         /* Read the declaration specifier */
664         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
665
666         /* We accept only auto and register as storage class specifiers */
667         if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
668             Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
669         } else if ((Spec.StorageClass & SC_REGISTER) == SC_REGISTER) {
670             Spec.StorageClass = SC_REGISTER | SC_STATIC | SC_PARAM | SC_DEF;
671         } else {
672             Error ("Illegal storage class");
673             Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
674         }
675
676         /* Allow parameters without a name, but remember if we had some to
677          * eventually print an error message later.
678          */
679         ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
680         if (Decl.Ident[0] == '\0') {
681
682             /* Unnamed symbol. Generate a name that is not user accessible,
683              * then handle the symbol normal.
684              */
685             AnonName (Decl.Ident, "param");
686             F->Flags |= FD_UNNAMED_PARAMS;
687
688             /* Clear defined bit on nonames */
689             Spec.StorageClass &= ~SC_DEF;
690         }
691
692         /* Parse an attribute ### */
693         ParseAttribute (&Decl, &Attr);
694
695         /* Create a symbol table entry */
696         AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Spec.StorageClass, 0);
697
698         /* Count arguments */
699         ++F->ParamCount;
700
701         /* Check for more parameters */
702         if (CurTok.Tok == TOK_COMMA) {
703             NextToken ();
704         } else {
705             break;
706         }
707     }
708
709     /* Skip right paren. We must explicitly check for one here, since some of
710      * the breaks above bail out without checking.
711      */
712     ConsumeRParen ();
713
714     /* Check if this is a function definition */
715     if (CurTok.Tok == TOK_LCURLY) {
716         /* Print an error if in strict ANSI mode and we have unnamed
717          * parameters.
718          */
719         if (ANSI && (F->Flags & FD_UNNAMED_PARAMS) != 0) {
720             Error ("Parameter name omitted");
721         }
722     }
723 }
724
725
726
727 static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
728 /* Parse the argument list of a function. */
729 {
730     unsigned Offs;
731     SymEntry* Sym;
732
733     /* Create a new function descriptor */
734     FuncDesc* F = NewFuncDesc ();
735
736     /* Enter a new lexical level */
737     EnterFunctionLevel ();
738
739     /* Check for several special parameter lists */
740     if (CurTok.Tok == TOK_RPAREN) {
741         /* Parameter list is empty */
742         F->Flags |= (FD_EMPTY | FD_VARIADIC);
743     } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) {
744         /* Parameter list declared as void */
745         NextToken ();
746         F->Flags |= FD_VOID_PARAM;
747     } else if (CurTok.Tok == TOK_IDENT &&
748                (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) {
749         /* If the identifier is a typedef, we have a new style parameter list,
750          * if it's some other identifier, it's an old style parameter list.
751          */
752         Sym = FindSym (CurTok.Ident);
753         if (Sym == 0 || !SymIsTypeDef (Sym)) {
754             /* Old style (K&R) function. Assume variable param list. */
755             F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
756         }
757     }
758
759     /* Check for an implicit int return in the function */
760     if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
761         Spec->Type[0] == T_INT           &&
762         Spec->Type[1] == T_END) {
763         /* Function has an implicit int return */
764         F->Flags |= FD_OLDSTYLE_INTRET;
765     }
766
767     /* Parse params */
768     if ((F->Flags & FD_OLDSTYLE) == 0) {
769         /* New style function */
770         ParseAnsiParamList (F);
771     } else {
772         /* Old style function */
773         ParseOldStyleParamList (F);
774     }
775
776     /* Assign offsets. If the function has a variable parameter list,
777      * there's one additional byte (the arg size).
778      */
779     Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
780     Sym = GetSymTab()->SymTail;
781     while (Sym) {
782         unsigned Size = CheckedSizeOf (Sym->Type);
783         if (SymIsRegVar (Sym)) {
784             Sym->V.R.SaveOffs = Offs;
785         } else {
786             Sym->V.Offs = Offs;
787         }
788         Offs += Size;
789         F->ParamSize += Size;
790         Sym = Sym->PrevSym;
791     }
792
793     /* Leave the lexical level remembering the symbol tables */
794     RememberFunctionLevel (F);
795
796     /* Return the function descriptor */
797     return F;
798 }
799
800
801
802 static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
803 /* Recursively process declarators. Build a type array in reverse order. */
804 {
805
806     if (CurTok.Tok == TOK_STAR) {
807         type T = T_PTR;
808         NextToken ();
809         /* Allow optional const or volatile qualifiers */
810         T |= OptionalQualifiers (T_QUAL_NONE);
811         Decl (Spec, D, Mode);
812         *D->T++ = T;
813         return;
814     } else if (CurTok.Tok == TOK_LPAREN) {
815         NextToken ();
816         Decl (Spec, D, Mode);
817         ConsumeRParen ();
818     } else if (CurTok.Tok == TOK_FASTCALL) {
819         /* Remember the current type pointer */
820         type* T = D->T;
821         /* Skip the fastcall token */
822         NextToken ();
823         /* Parse the function */
824         Decl (Spec, D, Mode);
825         /* Set the fastcall flag */
826         if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
827             Error ("__fastcall__ modifier applied to non function");
828         } else if (IsVariadicFunc (T)) {
829             Error ("Cannot apply __fastcall__ to functions with variable parameter list");
830         } else {
831             FuncDesc* F = GetFuncDesc (T);
832             F->Flags |= FD_FASTCALL;
833         }
834         return;
835     } else {
836         /* Things depend on Mode now:
837          *  - Mode == DM_NEED_IDENT means:
838          *      we *must* have a type and a variable identifer.
839          *  - Mode == DM_NO_IDENT means:
840          *      we must have a type but no variable identifer
841          *      (if there is one, it's not read).
842          *  - Mode == DM_ACCEPT_IDENT means:
843          *      we *may* have an identifier. If there is an identifier,
844          *      it is read, but it is no error, if there is none.
845          */
846         if (Mode == DM_NO_IDENT) {
847             D->Ident[0] = '\0';
848         } else if (CurTok.Tok == TOK_IDENT) {
849             strcpy (D->Ident, CurTok.Ident);
850             NextToken ();
851         } else {
852             if (Mode == DM_NEED_IDENT) {
853                 Error ("Identifier expected");
854             }
855             D->Ident[0] = '\0';
856         }
857     }
858
859     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
860         if (CurTok.Tok == TOK_LPAREN) {
861             /* Function declaration */
862             FuncDesc* F;
863             NextToken ();
864             /* Parse the function declaration */
865             F = ParseFuncDecl (Spec);
866             *D->T++ = T_FUNC;
867             EncodePtr (D->T, F);
868             D->T += DECODE_SIZE;
869         } else {
870             /* Array declaration */
871             unsigned long Size = 0;
872             NextToken ();
873             /* Read the size if it is given */
874             if (CurTok.Tok != TOK_RBRACK) {
875                 ExprDesc lval;
876                 ConstExpr (&lval);
877                 Size = lval.ConstVal;
878             }
879             ConsumeRBrack ();
880             *D->T++ = T_ARRAY;
881             Encode (D->T, Size);
882             D->T += DECODE_SIZE;
883         }
884     }
885 }
886
887
888
889 /*****************************************************************************/
890 /*                                   code                                    */
891 /*****************************************************************************/
892
893
894
895 type* ParseType (type* Type)
896 /* Parse a complete type specification */
897 {
898     DeclSpec Spec;
899     Declaration Decl;
900
901     /* Get a type without a default */
902     InitDeclSpec (&Spec);
903     ParseTypeSpec (&Spec, -1);
904
905     /* Parse additional declarators */
906     InitDeclaration (&Decl);
907     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
908
909     /* Copy the type to the target buffer */
910     TypeCpy (Type, Decl.Type);
911
912     /* Return a pointer to the target buffer */
913     return Type;
914 }
915
916
917
918 void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
919 /* Parse a variable, type or function declaration */
920 {
921     /* Initialize the Declaration struct */
922     InitDeclaration (D);
923
924     /* Get additional declarators and the identifier */
925     Decl (Spec, D, Mode);
926
927     /* Add the base type. */
928     TypeCpy (D->T, Spec->Type);
929
930     /* Check the size of the generated type */
931     if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
932         if (D->Ident[0] != '\0') {
933             Error ("Size of `%s' is invalid", D->Ident);
934         } else {
935             Error ("Invalid size");
936         }
937     }
938 }
939
940
941
942 void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
943 /* Parse a declaration specification */
944 {
945     /* Initialize the DeclSpec struct */
946     InitDeclSpec (D);
947
948     /* First, get the storage class specifier for this declaration */
949     ParseStorageClass (D, DefStorage);
950
951     /* Parse the type specifiers */
952     ParseTypeSpec (D, DefType);
953 }
954
955
956
957 void CheckEmptyDecl (const DeclSpec* D)
958 /* Called after an empty type declaration (that is, a type declaration without
959  * a variable). Checks if the declaration does really make sense and issues a
960  * warning if not.
961  */
962 {
963     if ((D->Flags & DS_EXTRA_TYPE) == 0) {
964         Warning ("Useless declaration");
965     }
966 }
967
968
969
970 static void ParseVoidInit (void)
971 /* Parse an initialization of a void variable (special cc65 extension) */
972 {
973     ExprDesc lval;
974
975     /* Allow an arbitrary list of values */
976     ConsumeLCurly ();
977     do {
978         ConstExpr (&lval);
979         switch (lval.Type[0]) {
980
981             case T_SCHAR:
982             case T_UCHAR:
983                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
984                     /* Make it byte sized */
985                     lval.ConstVal &= 0xFF;
986                 }
987                 DefineData (&lval);
988                 break;
989
990             case T_SHORT:
991             case T_USHORT:
992             case T_INT:
993             case T_UINT:
994             case T_PTR:
995             case T_ARRAY:
996                 if ((lval.Flags & E_MCTYPE) == E_TCONST) {
997                     /* Make it word sized */
998                     lval.ConstVal &= 0xFFFF;
999                 }
1000                 DefineData (&lval);
1001                 break;
1002
1003             case T_LONG:
1004             case T_ULONG:
1005                 DefineData (&lval);
1006                 break;
1007
1008             default:
1009                 Error ("Illegal type in initialization");
1010                 break;
1011
1012         }
1013
1014         if (CurTok.Tok != TOK_COMMA) {
1015             break;
1016         }
1017         NextToken ();
1018
1019     } while (CurTok.Tok != TOK_RCURLY);
1020
1021     ConsumeRCurly ();
1022 }
1023
1024
1025
1026 static void ParseStructInit (type* Type)
1027 /* Parse initialization of a struct or union */
1028 {
1029     SymEntry* Entry;
1030     SymTable* Tab;
1031
1032     /* Consume the opening curly brace */
1033     ConsumeLCurly ();
1034
1035     /* Get a pointer to the struct entry from the type */
1036     Entry = (SymEntry*) Decode (Type + 1);
1037
1038     /* Check if this struct definition has a field table. If it doesn't, it
1039      * is an incomplete definition.
1040      */
1041     Tab = Entry->V.S.SymTab;
1042     if (Tab == 0) {
1043         Error ("Cannot initialize variables with incomplete type");
1044         /* Returning here will cause lots of errors, but recovery is difficult */
1045         return;
1046     }
1047
1048     /* Get a pointer to the list of symbols */
1049     Entry = Tab->SymHead;
1050     while (CurTok.Tok != TOK_RCURLY) {
1051         if (Entry == 0) {
1052             Error ("Too many initializers");
1053             return;
1054         }
1055         ParseInit (Entry->Type);
1056         Entry = Entry->NextSym;
1057         if (CurTok.Tok != TOK_COMMA)
1058             break;
1059         NextToken ();
1060     }
1061
1062     /* Consume the closing curly brace */
1063     ConsumeRCurly ();
1064
1065     /* If there are struct fields left, reserve additional storage */
1066     while (Entry) {
1067         g_zerobytes (CheckedSizeOf (Entry->Type));
1068         Entry = Entry->NextSym;
1069     }
1070 }
1071
1072
1073
1074 void ParseInit (type* T)
1075 /* Parse initialization of variables. */
1076 {
1077     ExprDesc lval;
1078     type* t;
1079     const char* str;
1080     int Count;
1081     int Size;
1082
1083     switch (UnqualifiedType (*T)) {
1084
1085         case T_SCHAR:
1086         case T_UCHAR:
1087             ConstExpr (&lval);
1088             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1089                 /* Make it byte sized */
1090                 lval.ConstVal &= 0xFF;
1091             }
1092             assignadjust (T, &lval);
1093             DefineData (&lval);
1094             break;
1095
1096         case T_SHORT:
1097         case T_USHORT:
1098         case T_INT:
1099         case T_UINT:
1100         case T_PTR:
1101             ConstExpr (&lval);
1102             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1103                 /* Make it word sized */
1104                 lval.ConstVal &= 0xFFFF;
1105             }
1106             assignadjust (T, &lval);
1107             DefineData (&lval);
1108             break;
1109
1110         case T_LONG:
1111         case T_ULONG:
1112             ConstExpr (&lval);
1113             if ((lval.Flags & E_MCTYPE) == E_TCONST) {
1114                 /* Make it long sized */
1115                 lval.ConstVal &= 0xFFFFFFFF;
1116             }
1117             assignadjust (T, &lval);
1118             DefineData (&lval);
1119             break;
1120
1121         case T_ARRAY:
1122             Size = Decode (T + 1);
1123             t = T + DECODE_SIZE + 1;
1124             if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) {
1125                 str = GetLiteral (CurTok.IVal);
1126                 Count = strlen (str) + 1;
1127                 TranslateLiteralPool (CurTok.IVal);     /* Translate into target charset */
1128                 g_defbytes (str, Count);
1129                 ResetLiteralPoolOffs (CurTok.IVal);     /* Remove string from pool */
1130                 NextToken ();
1131             } else {
1132                 ConsumeLCurly ();
1133                 Count = 0;
1134                 while (CurTok.Tok != TOK_RCURLY) {
1135                     ParseInit (T + DECODE_SIZE + 1);
1136                     ++Count;
1137                     if (CurTok.Tok != TOK_COMMA)
1138                         break;
1139                     NextToken ();
1140                 }
1141                 ConsumeRCurly ();
1142             }
1143             if (Size == 0) {
1144                 Encode (T + 1, Count);
1145             } else if (Count < Size) {
1146                 g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1));
1147             } else if (Count > Size) {
1148                 Error ("Too many initializers");
1149             }
1150             break;
1151
1152         case T_STRUCT:
1153         case T_UNION:
1154             ParseStructInit (T);
1155             break;
1156
1157         case T_VOID:
1158             if (!ANSI) {
1159                 /* Special cc65 extension in non ANSI mode */
1160                 ParseVoidInit ();
1161                 break;
1162             }
1163             /* FALLTHROUGH */
1164
1165         default:
1166             Error ("Illegal type");
1167             break;
1168
1169     }
1170 }
1171
1172
1173