root/trunk/dparse.d

Revision 14, 85.6 kB (checked in by Jaymz031602, 6 years ago)

--

Line 
1 // dparse - D module parser
2 // (C) Copyright 2004-2005 James Dunne
3
4 // Please feel free to distribute this module in any form you like.  I only ask that you
5 // give credit where credit is due.  You may make modifications to this module.  If you do
6 // so, you may provide your modifications publicly, but you are not required to.
7
8 // A minimal parser that skips over actual code.  Only concerned with parsing for declarations.
9
10 module  dparse;
11
12 import  std.stream;
13 import  std.string;
14 import  std.ctype;
15
16 import  dlexer;
17 import  dtypes;
18
19 const int TRUE = 1;
20 const int FALSE = 0;
21
22 class DParse : DLexer {
23     private:
24         // Check for a certain token:
25         void check(uint value) {
26             if (token.value != value)
27                 error(format("found '%s' when expecting '%s'", token.toString(), toktostr[value]));
28             nextToken();
29         }
30
31         void check(uint value, char[] string) {
32             if (token.value != value)
33                 error(format("found '%s' when expecting '%s' following '%s'", token.toString(), toktostr[value], string));
34             nextToken();
35         }
36
37         uint        linkage;
38
39     public:
40         ArrayT!(Identifier)     moduleident;
41
42         // Load up the module source code:
43         this(char[] filename, char[] src) {
44             // Load up the source for the lexer:
45             super(filename, src);
46             linkage = LINKd;
47             nextToken();            // start the scanner
48         }
49
50         Array parseModule() {
51             Array   decldefs;
52
53             // ModuleDeclation leads off
54             if (token.value == TOKmodule) {
55                 nextToken();
56                 if (token.value != TOKidentifier) {
57                     error("Identifier expected following module");
58                     goto Lerr;
59                 } else {
60                     ArrayT!(Identifier) a = null;
61                     Identifier id;
62
63                     id = token.ident;
64                     while (nextToken() == TOKdot) {
65                         if (!a)
66                             a = new ArrayT!(Identifier);
67                         a.push(id);
68                         nextToken();
69                         if (token.value != TOKidentifier) {
70                             error("Identifier expected following package");
71                             goto Lerr;
72                         }
73                         id = token.ident;
74                     }
75
76                     moduleident = a;
77
78                     if (token.value != TOKsemicolon)
79                         error(format("';' expected following module declaration instead of %s", token.toString()));
80                     nextToken();
81                 }
82             }
83
84             decldefs = parseDeclDefs(0);
85             if (token.value != TOKeof) {
86                 error("unrecognized declaration");
87                 goto Lerr;
88             }
89             return decldefs;
90
91           Lerr:
92             while (token.value != TOKsemicolon && token.value != TOKeof)
93                 nextToken();
94             nextToken();
95             return new Array;
96         }
97
98         Array parseDeclDefs(int once) {
99             Dsymbol s;
100             Array decldefs;
101             Array a;
102             uint prot;
103             uint stc;
104
105             //printf("parseDeclDefs()\n");
106             decldefs = new Array;
107             do {
108                 switch (token.value) {
109                     case TOKenum:
110                         s = parseEnum();
111                         break;
112
113                     case TOKstruct:
114                         s = parseAggregate();
115                         break;
116
117                     case TOKunion:
118                         s = parseAggregate();
119                         break;
120
121                     case TOKclass:
122                         s = parseAggregate();
123                         break;
124
125                     case TOKinterface:
126                         s = parseAggregate();
127                         break;
128
129                     case TOKimport:
130                         s = parseImport(decldefs);
131                         break;
132
133                     case TOKtemplate:
134                         s = cast(Dsymbol) parseTemplateDeclaration();
135                         break;
136
137                     case TOKmixin:
138                         s = parseMixin();
139                         break;
140
141                     case TOKinstance:   // Deprecated
142                         if (isDeclaration(token, 2, TOKreserved, null)) {
143                             //printf("it's a declaration\n");
144                             goto Ldeclaration;
145                         } else {
146                             // instance foo(bar) ident;
147
148                             TemplateInstance ti;
149
150                             //printf("it's an alias\n");
151                             ti = parseTemplateInstance();
152                             s = cast(Dsymbol) ti;
153                             if (ti) {
154                                 if (token.value == TOKidentifier) {
155                                     s = new AliasDeclaration(loc, token.ident, ti);
156
157                                     nextToken();
158                                 }
159                             }
160                             if (token.value != TOKsemicolon)
161                                 error("';' expected after template instance");
162                         }
163                         break;
164
165                     case TOKwchar: case TOKdchar:
166                     case TOKbit: case TOKchar:
167                     case TOKint8: case TOKuns8:
168                     case TOKint16: case TOKuns16:
169                     case TOKint32: case TOKuns32:
170                     case TOKint64: case TOKuns64:
171                     case TOKfloat32: case TOKfloat64: case TOKfloat80:
172                     case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
173                     case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
174                     case TOKvoid:
175
176                     case TOKalias:
177                     case TOKtypedef:
178                     case TOKidentifier:
179                     case TOKtypeof:
180                     case TOKdot:
181                       Ldeclaration:
182                         a = parseDeclaration();
183                         decldefs.append(a);
184                         continue;
185
186                     case TOKthis:
187                         s = parseCtor();
188                         break;
189
190                     case TOKtilde:
191                         s = parseDtor();
192                         break;
193
194                     case TOKinvariant:
195                         parseInvariant();
196                         s = null;
197                         break;
198
199                     case TOKunittest:
200                         parseUnitTest();
201                         s = null;
202                         break;
203
204                     case TOKnew:
205                         s = parseNew();
206                         break;
207
208                     case TOKdelete:
209                         s = parseDelete();
210                         break;
211
212                     case TOKeof:
213                     case TOKrcurly:
214                         return decldefs;
215
216                     case TOKstatic:
217                         nextToken();
218                         if (token.value == TOKthis)
219                             s = parseStaticCtor();
220                         else if (token.value == TOKtilde)
221                             s = parseStaticDtor();
222                         else if (token.value == TOKassert)
223                             s = parseStaticAssert();
224                         else {
225                             stc = STCstatic;
226                             goto Lstc2;
227                         }
228                         break;
229
230                     case TOKconst:
231                         stc = STCconst;
232                         goto Lstc;
233                     case TOKfinal:
234                         stc = STCfinal;
235                         goto Lstc;
236                     case TOKauto:
237                         stc = STCauto;
238                         goto Lstc;
239                     case TOKoverride:
240                         stc = STCoverride;
241                         goto Lstc;
242                     case TOKabstract:
243                         stc = STCabstract;
244                         goto Lstc;
245                     case TOKsynchronized:
246                         stc = STCsynchronized;
247                         goto Lstc;
248                     case TOKdeprecated:
249                         stc = STCdeprecated;
250                         goto Lstc;
251
252                       Lstc:
253                         nextToken();
254                       Lstc2:
255                         switch (token.value) {
256                             case TOKconst:
257                                 stc |= STCconst;
258                                 goto Lstc;
259                             case TOKfinal:
260                                 stc |= STCfinal;
261                                 goto Lstc;
262                             case TOKauto:
263                                 stc |= STCauto;
264                                 goto Lstc;
265                             case TOKoverride:
266                                 stc |= STCoverride;
267                                 goto Lstc;
268                             case TOKabstract:
269                                 stc |= STCabstract;
270                                 goto Lstc;
271                             case TOKsynchronized:
272                                 stc |= STCsynchronized;
273                                 goto Lstc;
274                             case TOKdeprecated:
275                                 stc |= STCdeprecated;
276                                 goto Lstc;
277                         }
278                         a = parseBlock();
279                         s = new StorageClassDeclaration(stc, a);
280                         break;
281
282                     case TOKprivate:
283                         prot = PROTprivate;
284                         goto Lprot;
285                     case TOKpackage:
286                         prot = PROTpackage;
287                         goto Lprot;
288                     case TOKprotected:
289                         prot = PROTprotected;
290                         goto Lprot;
291                     case TOKpublic:
292                         prot = PROTpublic;
293                         goto Lprot;
294                     case TOKexport:
295                         prot = PROTexport;
296                         goto Lprot;
297
298                       Lprot:
299                         nextToken();
300                         a = parseBlock();
301                         s = new ProtDeclaration(prot, a);
302                         break;
303
304                     case TOKalign:
305                         {
306                             uint n;
307
308                             s = null;
309                             nextToken();
310                             if (token.value == TOKlparen) {
311                                 nextToken();
312                                 if (token.value == TOKint32v)
313                                     n = cast(uint)token.uns64value;
314                                 else {
315                                     error("integer expected, not %s", token.toString());
316                                     n = 1;
317                                 }
318                                 nextToken();
319                                 check(TOKrparen);
320                             } else
321                                 n = 4;  //global.structalign;   // default
322
323                             a = parseBlock();
324                             s = new AlignDeclaration(n, a);
325                             break;
326                         }
327
328                     case TOKpragma:
329                         {
330                             Identifier ident;
331                             Array args = null;
332
333                             nextToken();
334                             check(TOKlparen);
335                             if (token.value != TOKidentifier) {
336                                 error("pragma(identifier expected");
337                                 goto Lerror;
338                             }
339                             ident = token.ident;
340                             nextToken();
341                             if (token.value == TOKcomma)
342                                 args = parseArguments();    // pragma(identifier, args...)
343                             else
344                                 check(TOKrparen);   // pragma(identifier)
345
346                             if (token.value == TOKsemicolon)
347                                 a = null;
348                             else
349                                 a = parseBlock();
350                             /+s = new PragmaDeclaration(ident, args, a);+/
351                             s = null;
352                             break;
353                         }
354
355                     case TOKextern:
356                         {
357                             uint link = LINKdefault;
358                             uint linksave;
359
360                             s = null;
361                             nextToken();
362                             if (token.value == TOKlparen) {
363                                 nextToken();
364                                 if (token.value == TOKidentifier) {
365                                     Identifier id = token.ident;
366
367                                     nextToken();
368                                     if (id == Id.Windows)
369                                         link = LINKwindows;
370                                     else if (id == Id.Pascal)
371                                         link = LINKpascal;
372                                     else if (id == Id.D)
373                                         link = LINKd;
374                                     else if (id == Id.C) {
375                                         link = LINKc;
376                                         if (token.value == TOKplusplus) {
377                                             link = LINKcpp;
378                                             nextToken();
379                                         }
380                                     } else {
381                                         error("valid linkage identifiers are D, C, C++, Pascal, Windows");
382                                         link = LINKd;
383                                         break;
384                                     }
385                                 } else {
386                                     link = LINKd;   // default
387                                 }
388                                 check(TOKrparen);
389                             } else {
390                                 stc = STCextern;
391                                 goto Lstc2;
392                             }
393                             linksave = linkage;
394                             linkage = link;
395                             a = parseBlock();
396                             linkage = linksave;
397                             s = new LinkDeclaration(link, a);
398                             break;
399                         }
400
401                     case TOKdebug:
402                         {
403                             DebugCondition condition;
404                             Array aelse;
405
406                             nextToken();
407                             if (token.value == TOKassign) {
408                                 nextToken();
409                                 if (token.value == TOKidentifier)
410                                     s = new DebugSymbol(token.ident);
411                                 else if (token.value == TOKint32v)
412                                     s = new DebugSymbol(cast(uint)token.uns64value);
413                                 else {
414                                     error("identifier or integer expected, not %s", token.toString());
415                                     s = null;
416                                 }
417                                 nextToken();
418                                 if (token.value != TOKsemicolon)
419                                     error("semicolon expected");
420                                 nextToken();
421                                 break;
422                             }
423
424                             if (token.value == TOKlparen) {
425                                 nextToken();
426                                 condition = parseDebugCondition();
427                                 check(TOKrparen);
428                             } else
429                                 condition = new DebugCondition(1, null);
430                             a = parseBlock();
431                             aelse = null;
432                             if (token.value == TOKelse) {
433                                 nextToken();
434                                 aelse = parseBlock();
435                             }
436                             s = new DebugDeclaration(condition, a, aelse);
437                             break;
438                         }
439
440                     case TOKversion:
441                         {
442                             VersionCondition condition;
443                             Array aelse;
444
445                             nextToken();
446                             if (token.value == TOKassign) {
447                                 nextToken();
448                                 if (token.value == TOKidentifier)
449                                     s = new VersionSymbol(token.ident);
450                                 else if (token.value == TOKint32v)
451                                     s = new VersionSymbol(cast(uint)token.uns64value);
452                                 else {
453                                     error("identifier or integer expected, not %s", token.toString());
454                                     s = null;
455                                 }
456                                 nextToken();
457                                 if (token.value != TOKsemicolon)
458                                     error("semicolon expected");
459                                 nextToken();
460                                 break;
461                             }
462
463                             if (token.value == TOKlparen) {
464                                 nextToken();
465                                 condition = parseVersionCondition();
466                                 check(TOKrparen);
467                             } else {
468                                 error("(condition) expected following version");
469                                 condition = null;
470                             }
471                             a = parseBlock();
472                             aelse = null;
473                             if (token.value == TOKelse) {
474                                 nextToken();
475                                 aelse = parseBlock();
476                             }
477                             s = new VersionDeclaration(condition, a, aelse);
478                             break;
479                         }
480
481                     case TOKsemicolon:  // empty declaration
482                         nextToken();
483                         continue;
484
485                     default:
486                         error("Declaration expected, not '%s'\n", token.toString());
487                       Lerror:
488                         while (token.value != TOKsemicolon && token.value != TOKeof)
489                             nextToken();
490                         nextToken();
491                         s = null;
492                         continue;
493                 }
494                 if (s)
495                     decldefs.push(s);
496             } while (!once);
497             return decldefs;
498         }
499
500         /********************************************
501          * Parse declarations after an align, protection, or extern decl.
502          */
503
504         Array parseBlock() {
505             Array a = null;
506             Dsymbol s;
507
508             //printf("parseBlock()\n");
509             switch (token.value) {
510                 case TOKsemicolon:
511                     error("declaration expected following attribute, not ';'");
512                     nextToken();
513                     break;
514
515                 case TOKlcurly:
516                     nextToken();
517                     a = parseDeclDefs(0);
518                     if (token.value != TOKrcurly) { /* { */
519                         error("matching '}' expected, not %s", token.toString());
520                     } else
521                         nextToken();
522                     break;
523
524                 case TOKcolon:
525                     nextToken();
526                     a = null;
527 /+      #else
528                     a = parseDeclDefs(0);   // grab declarations up to closing curly bracket
529         #endif+/
530                     break;
531
532                 default:
533                     a = parseDeclDefs(1);
534                     break;
535             }
536             return a;
537         }
538
539         /**********************************
540          * Parse a static assertion.
541          */
542
543         StaticAssert parseStaticAssert() {
544             Loc loc = this.loc;
545             Expression exp;
546
547             //printf("parseStaticAssert()\n");
548             nextToken();
549             check(TOKlparen);
550             exp = parseExpression();
551             check(TOKrparen);
552             check(TOKsemicolon);
553             return new StaticAssert(loc, exp);
554         }
555
556         /**************************************
557          * Parse a debug conditional
558          */
559
560         DebugCondition parseDebugCondition() {
561             uint level = 1;
562             Identifier id = null;
563
564             if (token.value == TOKidentifier)
565                 id = token.ident;
566             else if (token.value == TOKint32v)
567                 level = cast(uint)token.uns64value;
568             else
569                 error("identifier or integer expected, not %s", token.toString());
570             nextToken();
571
572             return new DebugCondition(level, id);
573         }
574
575         /**************************************
576          * Parse a version conditional
577          */
578
579         VersionCondition parseVersionCondition() {
580             uint level = 1;
581             Identifier id = null;
582
583             if (token.value == TOKidentifier)
584                 id = token.ident;
585             else if (token.value == TOKint32v)
586                 level = cast(uint)token.uns64value;
587             else
588                 error("identifier or integer expected, not %s", token.toString());
589             nextToken();
590
591             return new VersionCondition(level, id);
592         }
593
594         /*****************************************
595          * Parse a constructor definition:
596          *  this(arguments) { body }
597          * Current token is 'this'.
598          */
599
600         CtorDeclaration parseCtor() {
601             CtorDeclaration f;
602             Array arguments;
603             int varargs;
604             Loc loc = this.loc;
605
606             nextToken();
607             arguments = parseParameters(varargs);
608             f = new CtorDeclaration(loc, 0, arguments, varargs);
609             parseContracts(f);
610             return f;
611         }
612
613         /*****************************************
614          * Parse a destructor definition:
615          *  ~this() { body }
616          * Current token is '~'.
617          */
618
619         DtorDeclaration parseDtor() {
620             DtorDeclaration f;
621             Loc loc = this.loc;
622
623             nextToken();
624             check(TOKthis);
625             check(TOKlparen);
626             check(TOKrparen);
627
628             f = new DtorDeclaration(loc, 0);
629             parseContracts(f);
630             return f;
631         }
632
633         /*****************************************
634          * Parse a static constructor definition:
635          *  static this() { body }
636          * Current token is 'this'.
637          */
638
639         StaticCtorDeclaration parseStaticCtor() {
640             StaticCtorDeclaration f;
641             Loc loc = this.loc;
642
643             nextToken();
644             check(TOKlparen);
645             check(TOKrparen);
646
647             f = new StaticCtorDeclaration(loc, 0);
648             parseContracts(f);
649             return f;
650         }
651
652         /*****************************************
653          * Parse a static destructor definition:
654          *  static ~this() { body }
655          * Current token is '~'.
656          */
657
658         StaticDtorDeclaration parseStaticDtor() {
659             StaticDtorDeclaration f;
660             Loc loc = this.loc;
661
662             nextToken();
663             check(TOKthis);
664             check(TOKlparen);
665             check(TOKrparen);
666
667             f = new StaticDtorDeclaration(loc, 0);
668             parseContracts(f);
669             return f;
670         }
671
672         /*****************************************
673          * Parse an invariant definition:
674          *  invariant { body }
675          * Current token is 'invariant'.
676          */
677
678         InvariantDeclaration parseInvariant() {
679             InvariantDeclaration f;
680             Loc loc = this.loc;
681
682             nextToken();
683             //check(TOKlparen);     // don't require ()
684             //check(TOKrparen);
685
686             f = new InvariantDeclaration(loc, 0);
687             f.fbody = parseStatement(PScurly);
688             return f;
689         }
690
691         /*****************************************
692          * Parse a unittest definition:
693          *  unittest { body }
694          * Current token is 'unittest'.
695          */
696
697         UnitTestDeclaration parseUnitTest() {
698             UnitTestDeclaration f;
699             Statement sbody;
700             Loc loc = this.loc;
701
702             nextToken();
703
704             sbody = parseStatement(PScurly);
705
706             f = new UnitTestDeclaration(loc, this.loc);
707             f.fbody = sbody;
708             return f;
709         }
710        
711         /*****************************************
712          * Parse a new definition:
713          *  new(arguments) { body }
714          * Current token is 'new'.
715          */
716        
717         NewDeclaration parseNew() {
718             NewDeclaration f;
719             Array arguments;
720             int varargs;
721             Loc loc = this.loc;
722        
723             nextToken();
724             arguments = parseParameters(varargs);
725             f = new NewDeclaration(loc, 0, arguments, varargs);
726             parseContracts(f);
727             return f;
728         }
729        
730         /*****************************************
731          * Parse a delete definition:
732          *  delete(arguments) { body }
733          * Current token is 'delete'.
734          */
735        
736         DeleteDeclaration parseDelete() {
737             DeleteDeclaration f;
738             Array arguments;
739             int varargs;
740             Loc loc = this.loc;
741        
742             nextToken();
743             arguments = parseParameters(varargs);
744             if (varargs)
745                 error("... not allowed in delete function parameter list");
746             f = new DeleteDeclaration(loc, 0, arguments);
747             parseContracts(f);
748             return f;
749         }
750
751         /**********************************************
752          * Parse parameter list.
753          */
754
755         Array parseParameters(out int pvarargs) {
756             Array arguments = new Array;
757             int varargs = 0;
758             int hasdefault = 0;
759
760             check(TOKlparen);
761             while (1) {
762                 Type tb;
763                 Identifier ai;
764                 Type at;
765                 Argument a;
766                 uint inoutt;
767                 Expression ae;
768
769                 ai = null;
770                 inoutt = In;                // parameter is "in" by default
771                 switch (token.value) {
772                     case TOKrparen:
773                         break;
774
775                     case TOKdotdotdot:
776                         varargs = 1;
777                         nextToken();
778                         break;
779
780                     case TOKin:
781                         inoutt = In;
782                         nextToken();
783                         goto L1;
784
785                     case TOKout:
786                         inoutt = Out;
787                         nextToken();
788                         goto L1;
789
790                     case TOKinout:
791                         inoutt = InOut;
792                         nextToken();
793                         goto L1;
794
795                     default:
796                       L1:
797                         tb = parseBasicType();
798                         at = parseDeclarator(tb, &ai);
799                         if (token.value == TOKassign)   // = defaultArg
800                         {
801                             nextToken();
802                             ae = parseAssignExp();
803                             hasdefault = 1;
804                         } else {
805                             if (hasdefault)
806                                 error("default argument expected for parameter '%s'", ai.toString());
807                             ae = null;
808                         }
809                         a = new Argument(inoutt, at, ai, ae);
810                         arguments.push(a);
811                         if (token.value == TOKcomma) {
812                             nextToken();
813                             continue;
814                         }
815                         break;
816                 }
817                 break;
818             }
819             check(TOKrparen);
820             pvarargs = varargs;
821             return arguments;
822         }
823
824         /*************************************
825          */
826
827         EnumDeclaration parseEnum() {
828             EnumDeclaration e;
829             Identifier id;
830             Type t;
831
832             //printf("parseEnum()\n");
833             nextToken();
834             if (token.value == TOKidentifier) {
835                 id = token.ident;
836                 nextToken();
837             } else
838                 id = null;
839
840             if (token.value == TOKcolon) {
841                 nextToken();
842                 t = parseBasicType();
843             } else
844                 t = null;
845
846             e = new EnumDeclaration(id, t);
847             if (token.value == TOKsemicolon && id)
848                 nextToken();
849             else if (token.value == TOKlcurly) {
850                 //printf("enum definition\n");
851                 e.members = new ArrayT!(EnumMember);
852                 nextToken();
853                 while (token.value != TOKrcurly) {
854                     if (token.value == TOKidentifier) {
855                         EnumMember em;
856                         Expression value;
857                         Identifier ident;
858
859                         ident = token.ident;
860                         value = null;
861                         nextToken();
862                         if (token.value == TOKassign) {
863                             nextToken();
864                             value = parseAssignExp();
865                         }
866                         em = new EnumMember(loc, ident, value);
867                         e.members.push(em);
868                         if (token.value == TOKrcurly) { }
869                         else
870                             check(TOKcomma);
871                     } else {
872                         error("enum member expected");
873                         nextToken();
874                     }
875                 }
876                 nextToken();
877             } else
878                 error("enum declaration is invalid");
879
880             return e;
881         }
882
883         Dsymbol parseAggregate() {
884             AggregateDeclaration a = null;
885             int anon = 0;
886             uint tok;
887             Identifier id;
888             Array tpl = null;
889
890             //printf("parseAggregate()\n");
891             tok = token.value;
892             nextToken();
893             if (token.value != TOKidentifier) {
894                 id = null;
895             } else {
896                 id = token.ident;
897                 nextToken();
898
899                 if (token.value == TOKlparen) { // Class template declaration.
900
901                     // Gather template parameter list
902                     tpl = parseTemplateParameterList();
903                 }
904             }
905
906             switch (tok) {
907                 case TOKclass:
908                 case TOKinterface:
909                     {
910                         Array baseclasses = null;
911                         BaseClass b;
912
913                         if (!id)
914                             error("anonymous classes not allowed");
915
916                         // Collect base class(es)
917                         b = null;
918                         if (token.value == TOKcolon) {
919                             uint protection = PROTpublic;
920
921                             baseclasses = new Array;
922                             while (1) {
923                                 nextToken();
924                                 switch (token.value) {
925                                     case TOKidentifier:
926                                     case TOKinstance:
927                                         break;
928                                     case TOKprivate:
929                                         protection = PROTprivate;
930                                         continue;
931                                     case TOKpackage:
932                                         protection = PROTpackage;
933                                         continue;
934                                     case TOKprotected:
935                                         protection = PROTprotected;
936                                         continue;
937                                     case TOKpublic:
938                                         protection = PROTpublic;
939                                         continue;
940                                     default:
941                                         error("base classes expected following ':'");
942                                         return null;
943                                 }
944                                 b = new BaseClass(parseBasicType(), protection);
945                                 baseclasses.push(b);
946                                 if (token.value != TOKcomma)
947                                     break;
948                                 protection = PROTpublic;
949                             }
950                             if (token.value != TOKlcurly)
951                                 error("members expected");
952                         }
953
954                         if (tok == TOKclass)
955                             a = new ClassDeclaration(loc, id, baseclasses);
956                         else
957                             a = new InterfaceDeclaration(loc, id, baseclasses);
958                         break;
959                     }
960
961                 case TOKstruct:
962                     if (id)
963                         a = new StructDeclaration(loc, id);
964                     else
965                         anon = 1;
966                     break;
967
968                 case TOKunion:
969                     if (id)
970                         a = new UnionDeclaration(loc, id);
971                     else
972                         anon = 2;
973                     break;
974
975                 default:
976                     assert(0);
977                     break;
978             }
979
980             if (a && token.value == TOKsemicolon) {
981                 nextToken();
982             } else if (token.value == TOKlcurly) {
983                 //printf("aggregate definition\n");
984                 nextToken();
985                 Array decl = parseDeclDefs(0);
986
987                 if (token.value != TOKrcurly)
988                     error("struct member expected");
989                 nextToken();
990                 if (anon) {
991                     /* Anonymous structs/unions are more like attributes.
992                      */
993                     return new AnonDeclaration(anon - 1, decl);
994                 } else
995                     a.members = decl;
996             } else {
997                 error("{ } expected following aggregate declaration");
998                 a = new StructDeclaration(loc, null);
999             }
1000
1001             if (tpl) {
1002                 Array decldefs;
1003                 TemplateDeclaration tempdecl;
1004
1005                 // Wrap a template around the aggregate declaration
1006                 decldefs = new Array;
1007                 decldefs.push(a);
1008                 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
1009                 return tempdecl;
1010             }
1011
1012             return a;
1013         }
1014
1015         /**************************************
1016          * Parse a TemplateDeclaration.
1017          */
1018
1019         TemplateDeclaration parseTemplateDeclaration() {
1020             TemplateDeclaration tempdecl;
1021             Identifier id;
1022             Array tpl;
1023             Array decldefs;
1024             Loc loc = this.loc;
1025
1026             nextToken();
1027             if (token.value != TOKidentifier) {
1028                 error("TemplateIdentifier expected following template");
1029                 goto Lerr;
1030             }
1031             id = token.ident;
1032             nextToken();
1033             tpl = parseTemplateParameterList();
1034             if (!tpl)
1035                 goto Lerr;
1036
1037             if (token.value != TOKlcurly) {
1038                 error("members of template declaration expected");
1039                 goto Lerr;
1040             } else {
1041                 nextToken();
1042                 decldefs = parseDeclDefs(0);
1043                 if (token.value != TOKrcurly) {
1044                     error("template member expected");
1045                     goto Lerr;
1046                 }
1047                 nextToken();
1048             }
1049
1050             tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
1051             return tempdecl;
1052
1053           Lerr:
1054             return null;
1055         }
1056
1057         /******************************************
1058          * Parse template parameter list.
1059          */
1060
1061         Array parseTemplateParameterList() {
1062             Array tpl;
1063
1064             if (token.value != TOKlparen) {
1065                 error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1066                 goto Lerr;
1067             }
1068             tpl = new Array;
1069             nextToken();
1070
1071             // Get TemplateParameterList
1072             if (token.value != TOKrparen) {
1073                 while (1) {
1074                     TemplateParameter tp;
1075                     Identifier tp_ident;
1076                     Type tp_spectype;
1077                     Type tp_valtype;
1078                     Type tp_defaulttype;
1079                     Expression tp_specvalue;
1080                     Expression tp_defaultvalue;
1081                     Token t;
1082
1083                     // Get TemplateParameter
1084
1085                     // First, look ahead to see if it is a TypeParameter or a ValueParameter
1086                     t = peek(token);
1087                     if (token.value == TOKalias) {  // AliasParameter
1088                         nextToken();
1089                         if (token.value != TOKidentifier) {
1090                             error("Identifier expected for template parameter");
1091                             goto Lerr;
1092                         }
1093                         tp_ident = token.ident;
1094                         nextToken();
1095                         if (token.value == TOKassign)   // : Type
1096                         {
1097                             nextToken();
1098                             tp_defaulttype = parseBasicType();
1099                             tp_defaulttype = parseDeclarator(tp_defaulttype, null);
1100                         }
1101                         tp = new TemplateAliasParameter(loc, tp_ident, tp_defaulttype);
1102                     } else if (t.value == TOKcolon || t.value == TOKassign || t.value == TOKcomma || t.value == TOKrparen) {    // TypeParameter
1103                         if (token.value != TOKidentifier) {
1104                             error("Identifier expected for template parameter");
1105                             goto Lerr;
1106                         }
1107                         tp_ident = token.ident;
1108                         nextToken();
1109                         if (token.value == TOKcolon)    // : Type
1110                         {
1111                             nextToken();
1112                             tp_spectype = parseBasicType();
1113                             tp_spectype = parseDeclarator(tp_spectype, null);
1114                         }
1115                         if (token.value == TOKassign)   // : Type
1116                         {
1117                             nextToken();
1118                             tp_defaulttype = parseBasicType();
1119                             tp_defaulttype = parseDeclarator(tp_defaulttype, null);
1120                         }
1121                         tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1122                     } else {            // ValueParameter
1123                         tp_valtype = parseBasicType();
1124                         tp_valtype = parseDeclarator(tp_valtype, &tp_ident);
1125                         if (!tp_ident) {
1126                             error("no identifier for template value parameter");
1127                             goto Lerr;
1128                         }
1129                         if (token.value == TOKcolon)    // : CondExpression
1130                         {
1131                             nextToken();
1132                             tp_specvalue = parseCondExp();
1133                         }
1134                         if (token.value == TOKassign)   // = CondExpression
1135                         {
1136                             nextToken();
1137                             tp_defaultvalue = parseCondExp();
1138                         }
1139                         tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1140                     }
1141                     tpl.push(tp);
1142                     if (token.value != TOKcomma)
1143                         break;
1144                     nextToken();
1145                 }
1146             }
1147             check(TOKrparen);
1148             return tpl;
1149
1150           Lerr:
1151             return null;
1152         }
1153
1154         /**************************************
1155          * Parse a TemplateInstance.
1156          */
1157
1158         TemplateInstance parseTemplateInstance() {
1159             TemplateInstance tempinst;
1160             Identifier id;
1161
1162             //printf("parseTemplateInstance()\n");
1163             nextToken();
1164             if (token.value == TOKdot) {
1165                 id = Id.empty;
1166             } else if (token.value == TOKidentifier) {
1167                 id = token.ident;
1168                 nextToken();
1169             } else {
1170                 error("TemplateIdentifier expected following instance");
1171                 goto Lerr;
1172             }
1173             tempinst = new TemplateInstance(loc, id);
1174             while (token.value == TOKdot) {
1175                 nextToken();
1176                 if (token.value == TOKidentifier)
1177                     tempinst.addIdent(token.ident);
1178                 else {
1179                     error("identifier expected following '.' instead of '%s'", token.toString());
1180                     goto Lerr;
1181                 }
1182                 nextToken();
1183             }
1184             /+tempinst.tiargs = +/parseTemplateArgumentList();
1185
1186             //if (!global.params.useDeprecated)
1187             //  error("instance is deprecated, use %s", tempinst.toString());
1188             return tempinst;
1189
1190           Lerr:
1191             return null;
1192         }
1193
1194         /******************************************
1195          * Parse template mixin.
1196          *  mixin Foo;
1197          *  mixin Foo!(args);
1198          *  mixin a.b.c!(args).Foo!(args);
1199          *  mixin Foo!(args) identifier;
1200          */
1201
1202         TemplateMixin parseMixin() {
1203             TemplateMixin tm;
1204             Identifier id;
1205             TypeTypeof tqual;
1206             Array tiargs;
1207             ArrayT!(Identifier) idents;
1208
1209             //printf("parseMixin()\n");
1210             nextToken();
1211
1212             tqual = null;
1213             if (token.value == TOKdot) {
1214                 id = Id.empty;
1215             } else {
1216                 if (token.value == TOKtypeof) {
1217                     Expression exp;
1218
1219                     nextToken();
1220                     check(TOKlparen);
1221                     exp = parseExpression();
1222                     check(TOKrparen);
1223                     tqual = new TypeTypeof(loc, exp);
1224                     check(TOKdot);
1225                 }
1226                 if (token.value != TOKidentifier) {
1227                     error("identifier expected, not %s", token.toString());
1228                     goto Lerr;
1229                 }
1230                 id = token.ident;
1231             }
1232
1233             idents = new ArrayT!(Identifier);
1234             while (1) {
1235                 nextToken();
1236                 tiargs = null;
1237                 if (token.value == TOKnot) {
1238                     nextToken();
1239                     /+tiargs = +/parseTemplateArgumentList();
1240                 }
1241
1242                 if (token.value != TOKdot)
1243                     break;
1244
1245                 if (tiargs) {
1246                     TemplateInstance tempinst = new TemplateInstance(loc, id);
1247        
1248                     tempinst.tiargs = tiargs;
1249                     id = cast(Identifier) tempinst;
1250                     tiargs = null;
1251                 }
1252                 idents.push(id);
1253
1254                 nextToken();
1255                 if (token.value != TOKidentifier) {
1256                     error("identifier expected following '.' instead of '%s'", token.toString());
1257                     break;
1258                 }
1259                 id = token.ident;
1260             }
1261             idents.push(id);
1262
1263             if (token.value == TOKidentifier) {
1264                 id = token.ident;
1265                 nextToken();
1266             } else
1267                 id = null;
1268
1269             tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1270             if (token.value != TOKsemicolon)
1271                 error("';' expected after mixin");
1272             nextToken();
1273
1274             return tm;
1275
1276           Lerr:
1277             return null;
1278         }
1279
1280         /******************************************
1281          * Parse template argument list.
1282          * Input:
1283          *  current token is opening '('
1284          * Output:
1285          *  current token is one after closing ')'
1286          */
1287
1288         void parseTemplateArgumentList() {
1289             /+ArrayT!(Object) tiargs = new Array;+/
1290
1291             if (token.value != TOKlparen) {
1292                 error("!(TemplateArgumentList) expected following TemplateIdentifier");
1293                 return/+ tiargs+/;
1294             }
1295             nextToken();
1296
1297             // Get TemplateArgumentList
1298             if (token.value != TOKrparen) {
1299                 while (1) {
1300                     // See if it is an Expression or a Type
1301                     /+if (isDeclaration(&token, 0, TOKreserved, null)) {    // Type
1302                         Type ta;
1303
1304                         // Get TemplateArgument
1305                         ta = parseBasicType();
1306                         ta = parseDeclarator(ta, null);
1307                         tiargs.push(ta);
1308                     } else {            // Expression
1309                         Expression ea;
1310
1311                         ea = parseAssignExp();
1312                         tiargs.push(ea);
1313                     }+/
1314                     if (token.value != TOKcomma)
1315                         break;
1316                     nextToken();
1317                 }
1318             }
1319             check(TOKrparen, "template argument list");
1320             return/+ tiargs+/;
1321         }
1322
1323         Import parseImport(Array decldefs) {
1324             Import s;
1325             Identifier id;
1326             ArrayT!(Identifier) a;
1327             Loc loc;
1328
1329             //printf("parseImport()\n");
1330             do {
1331                 nextToken();
1332                 if (token.value != TOKidentifier) {
1333                     error("Identifier expected following import");
1334                     break;
1335                 }
1336
1337                 loc = this.loc;
1338                 a = null;
1339                 id = token.ident;
1340                 while (nextToken() == TOKdot) {
1341                     if (!a)
1342                         a = new ArrayT!(Identifier);
1343                     a.push(id);
1344                     nextToken();
1345                     if (token.value != TOKidentifier) {
1346                         error("Identifier expected following package");
1347                         break;
1348                     }
1349                     id = token.ident;
1350                 }
1351
1352                 s = new Import(loc, a, token.ident);
1353                 decldefs.push(s);
1354             } while (token.value == TOKcomma);
1355
1356             if (token.value == TOKsemicolon)
1357                 nextToken();
1358             else {
1359                 error("';' expected");
1360                 nextToken();
1361             }
1362
1363             return null;
1364         }
1365
1366         Type parseBasicType() {
1367             Type t;
1368             Identifier id;
1369             TypeQualified tid;
1370             TemplateInstance tempinst;
1371
1372             //printf("parseBasicType()\n");
1373             switch (token.value) {
1374                 case TOKvoid:    t = Type.tvoid;  goto LabelX;
1375                 case TOKint8:    t = Type.tint8;  goto LabelX;
1376                 case TOKuns8:    t = Type.tuns8;  goto LabelX;
1377                 case TOKint16:   t = Type.tint16; goto LabelX;
1378                 case TOKuns16:   t = Type.tuns16; goto LabelX;
1379                 case TOKint32:   t = Type.tint32; goto LabelX;
1380                 case TOKuns32:   t = Type.tuns32; goto LabelX;
1381                 case TOKint64:   t = Type.tint64; goto LabelX;
1382                 case TOKuns64:   t = Type.tuns64; goto LabelX;
1383                 case TOKfloat32: t = Type.tfloat32; goto LabelX;
1384                 case TOKfloat64: t = Type.tfloat64; goto LabelX;
1385                 case TOKfloat80: t = Type.tfloat80; goto LabelX;
1386                 case TOKimaginary32: t = Type.timaginary32; goto LabelX;
1387                 case TOKimaginary64: t = Type.timaginary64; goto LabelX;
1388                 case TOKimaginary80: t = Type.timaginary80; goto LabelX;
1389                 case TOKcomplex32: t = Type.tcomplex32; goto LabelX;
1390                 case TOKcomplex64: t = Type.tcomplex64; goto LabelX;
1391                 case TOKcomplex80: t = Type.tcomplex80; goto LabelX;
1392                 case TOKbit:     t = Type.tbit;     goto LabelX;
1393                 case TOKchar:    t = Type.tchar;    goto LabelX;
1394                 case TOKwchar:   t = Type.twchar; goto LabelX;
1395                 case TOKdchar:   t = Type.tdchar; goto LabelX;
1396                 LabelX:
1397                     nextToken();
1398                     break;
1399
1400                 case TOKidentifier:
1401                     id = token.ident;
1402                     nextToken();
1403                     if (token.value == TOKnot) {
1404                         nextToken();
1405                         tempinst = new TemplateInstance(loc, id);
1406                         /+tempinst.tiargs = +/parseTemplateArgumentList();
1407                         tid = new TypeInstance(loc, tempinst);
1408                         goto Lident2;
1409                     }
1410                   Lident:
1411                     tid = new TypeIdentifier(loc, id);
1412                   Lident2:
1413                     while (token.value == TOKdot) {
1414                         nextToken();
1415                         if (token.value != TOKidentifier) {
1416                             error("identifier expected following '.' instead of '%s'", token.toString());
1417                             break;
1418                         }
1419                         id = token.ident;
1420                         nextToken();
1421                         if (token.value == TOKnot) {
1422                             nextToken();
1423                             tempinst = new TemplateInstance(loc, id);
1424                             /+tempinst.tiargs = +/parseTemplateArgumentList();
1425                             /+tid.addIdent(cast(Identifier) tempinst);+/
1426                         } else
1427                             /+tid.addIdent(id);+/ { }
1428                     }
1429                     t = tid;
1430                     break;
1431
1432                 case TOKdot:
1433                     id = Id.empty;
1434                     goto Lident;
1435
1436                 case TOKinstance:
1437                     {                   // Deprecated
1438                         tempinst = parseTemplateInstance();
1439                         if (!tempinst)  // if error
1440                         {
1441                             t = Type.tvoid;
1442                             break;
1443                         }
1444
1445                         tid = new TypeInstance(loc, tempinst);
1446                         goto Lident2;
1447                     }
1448
1449                 case TOKtypeof:
1450                     {
1451                         Expression exp;
1452
1453                         nextToken();
1454                         check(TOKlparen);
1455                         exp = parseExpression();
1456                         check(TOKrparen);
1457                         tid = new TypeTypeof(loc, exp);
1458                         goto Lident2;
1459                     }
1460
1461                 default:
1462                     error("basic type expected, not %s", token.toString());
1463                     t = Type.tint32;
1464                     break;
1465             }
1466             return t;
1467         }
1468
1469         Type parseBasicType2(Type t) {
1470             Expression e;
1471             Type ts;
1472             Type ta;
1473
1474             //printf("parseBasicType2()\n");
1475             while (1) {
1476                 switch (token.value) {
1477                     case TOKmul:
1478                         t = new TypePointer(t);
1479                         nextToken();
1480                         continue;
1481
1482                     case TOKlbracket:
1483                         // Handle []. Make sure things like
1484                         //     int[3][1] a;
1485                         // is (array[1] of array[3] of int)
1486                         nextToken();
1487                         if (token.value == TOKrbracket) {
1488                             t = new TypeDArray(t);  // []
1489                             nextToken();
1490                         } else if (isDeclaration(token, 0, TOKrbracket, null)) {    // It's an associative array declaration
1491                             Type index;
1492
1493                             //printf("it's an associative array\n");
1494                             index = parseBasicType();
1495                             index = parseDeclarator(index, null);   // [ type ]
1496                             t = new TypeAArray(t, index);
1497                             check(TOKrbracket);
1498                         } else {
1499                             //printf("it's [expression]\n");
1500                             e = parseExpression();  // [ expression ]
1501                             t = new TypeSArray(t, e);
1502                             check(TOKrbracket);
1503                         }
1504                         continue;
1505
1506                     case TOKdelegate:
1507                     case TOKfunction:
1508                         {               // Handle delegate declaration:
1509                             //  t delegate(parameter list)
1510                             //  t function(parameter list)
1511                             Array arguments;
1512                             int varargs;
1513                             uint  save = token.value;
1514
1515                             nextToken();
1516                             arguments = parseParameters(varargs);
1517                             t = new TypeFunction(arguments, t, varargs, linkage);
1518                             if (save == TOKdelegate)
1519                                 t = new TypeDelegate(t);
1520                             else
1521                                 t = new TypePointer(t); // pointer to function
1522                             continue;
1523                         }
1524
1525                     default:
1526                         ts = t;
1527                         break;
1528                 }
1529                 break;
1530             }
1531             return ts;
1532         }
1533
1534         Type parseDeclarator(Type t, Identifier *pident) {
1535             Expression e;
1536             Type ts;
1537             Type ta;
1538             Type *pt;
1539
1540             //printf("parseDeclarator(t = %p)\n", t);
1541             while (1) {
1542                 switch (token.value) {
1543                     case TOKmul:
1544                         t = new TypePointer(t);
1545                         nextToken();
1546                         continue;
1547
1548                     case TOKlbracket:
1549                         // Handle []. Make sure things like
1550                         //     int[3][1] a;
1551                         // is (array[1] of array[3] of int)
1552                         nextToken();
1553                         if (token.value == TOKrbracket) {
1554                             t = new TypeDArray(t);  // []
1555                             nextToken();
1556                         } else if (isDeclaration(token, 0, TOKrbracket, null)) {    // It's an associative array declaration
1557                             Type index;
1558
1559                             //printf("it's an associative array\n");
1560                             index = parseBasicType();
1561                             index = parseDeclarator(index, null);   // [ type ]
1562                             t = new TypeAArray(t, index);
1563                             check(TOKrbracket);
1564                         } else {
1565                             //printf("it's [expression]\n");
1566                             e = parseExpression();  // [ expression ]
1567                             t = new TypeSArray(t, e);
1568                             check(TOKrbracket);
1569                         }
1570                         continue;
1571
1572                     case TOKidentifier:
1573                         if (pident)
1574                             *pident = token.ident;
1575                         else
1576                             error("unexpected identifer '%s' in declarator", token.ident.toString());
1577                         ts = t;
1578                         nextToken();
1579                         break;
1580
1581                     case TOKlparen:
1582                         nextToken();
1583                         ts = parseDeclarator(t, pident);
1584                         check(TOKrparen);
1585                         break;
1586
1587                     case TOKdelegate:
1588                     case TOKfunction:
1589                         {               // Handle delegate declaration:
1590                             //  t delegate(parameter list)
1591                             //  t function(parameter list)
1592                             Array arguments;
1593                             int varargs;
1594                             uint save = token.value;
1595
1596                             nextToken();
1597                             arguments = parseParameters(varargs);
1598                             t = new TypeFunction(arguments, t, varargs, linkage);
1599                             if (save == TOKdelegate)
1600                                 t = new TypeDelegate(t);
1601                             else
1602                                 t = new TypePointer(t); // pointer to function
1603                             continue;
1604                         }
1605                     default:
1606                         ts = t;
1607                         break;
1608                 }
1609                 break;
1610             }
1611
1612             while (1) {
1613                 switch (token.value) {
1614                     case TOKlbracket:
1615                         // This is the old C-style post [] syntax.
1616                         // Should we disallow it?
1617                         nextToken();
1618                         if (token.value == TOKrbracket) {
1619                             ta = new TypeDArray(t); // []
1620                             nextToken();
1621                         } else if (isDeclaration(token, 0, TOKrbracket, null)) {    // It's an associative array declaration
1622                             Type index;
1623
1624                             //printf("it's an associative array\n");
1625                             index = parseBasicType();
1626                             index = parseDeclarator(index, null);   // [ type ]
1627                             check(TOKrbracket);
1628                             ta = new TypeAArray(t, index);
1629                         } else {
1630                             //printf("it's [expression]\n");
1631                             e = parseExpression();  // [ expression ]
1632                             ta = new TypeSArray(t, e);
1633                             check(TOKrbracket);
1634                         }
1635                         for (pt = &ts; *pt != t; pt = &((*pt).next)) {}
1636                         *pt = ta;
1637                         continue;
1638                     case TOKlparen:
1639                         {
1640                             Array arguments;
1641                             int varargs;
1642
1643                             arguments = parseParameters(varargs);
1644                             ta = new TypeFunction(arguments, t, varargs, linkage);
1645                             for (pt = &ts; *pt != t; pt = &((*pt).next)) {}
1646                             *pt = ta;
1647                             continue;
1648                         }
1649                 }
1650                 break;
1651             }
1652
1653             return ts;
1654         }
1655        
1656         /**********************************
1657          * Return array of Declaration *'s.
1658          */
1659        
1660         Array parseDeclaration() {
1661             uint storage_class;
1662             uint sc;
1663             Type ts;
1664             Type t;
1665             Type tfirst;
1666             Identifier ident;
1667             Array a;
1668             uint tok;
1669
1670             //printf("parseDeclaration()\n");
1671             switch (token.value) {
1672                 case TOKtypedef:
1673                 case TOKalias:
1674                     tok = token.value;
1675                     nextToken();
1676                     break;
1677
1678                 default:
1679                     tok = TOKreserved;
1680                     break;
1681             }
1682
1683             storage_class = STCundefined;
1684             while (1) {
1685                 switch (token.value) {
1686                     case TOKconst:
1687                         sc = STCconst;
1688                         goto L1;
1689                     case TOKstatic:
1690                         sc = STCstatic;
1691                         goto L1;
1692                     case TOKfinal:
1693                         sc = STCfinal;
1694                         goto L1;
1695                     case TOKauto:
1696                         sc = STCauto;
1697                         goto L1;
1698                     case TOKoverride:
1699                         sc = STCoverride;
1700                         goto L1;
1701                     case TOKabstract:
1702                         sc = STCabstract;
1703                         goto L1;
1704                     case TOKsynchronized:
1705                         sc = STCsynchronized;
1706                         goto L1;
1707                     case TOKdeprecated:
1708                         sc = STCdeprecated;
1709                         goto L1;
1710                       L1:
1711                         if (storage_class & sc)
1712                             error("redundant storage class '%s'", token.toString());
1713                         storage_class = (storage_class | sc);
1714                         nextToken();
1715                         continue;
1716                 }
1717                 break;
1718             }
1719
1720             a = new Array;
1721             ts = parseBasicType();
1722             ts = parseBasicType2(ts);
1723             tfirst = null;
1724
1725             while (1) {
1726                 Loc loc = this.loc;
1727
1728                 ident = null;
1729                 t = parseDeclarator(ts, &ident);
1730                 assert(t);
1731                 if (!tfirst)
1732                     tfirst = t;
1733                 else if (t != tfirst)
1734                     error("multiple declarations must have the same type, not %s and %s", tfirst.toString(), t.toString());
1735                 if (!ident)
1736                     error("no identifier for declarator");
1737
1738                 if (tok == TOKtypedef || tok == TOKalias) {
1739                     Declaration v;
1740                     Initializer init;
1741
1742                     init = null;
1743                     if (token.value == TOKassign) {
1744                         nextToken();
1745                         init = parseInitializer();
1746                     }
1747                     if (tok == TOKtypedef)
1748                         v = new TypedefDeclaration(ident, t, init);
1749                     else {
1750                         if (init)
1751                             error("alias cannot have initializer");
1752                         v = new AliasDeclaration(loc, ident, t);
1753                     }
1754                     v.storage_class = storage_class;
1755                     a.push(v);
1756                     switch (token.value) {
1757                         case TOKsemicolon:
1758                             nextToken();
1759                             break;
1760
1761                         case TOKcomma:
1762                             nextToken();
1763                             continue;
1764
1765                         default:
1766                             error("semicolon expected to close %s declaration", Token.toChars(tok));
1767                             break;
1768                     }
1769                 } else if (t.ty == Tfunction) {
1770                     FuncDeclaration f;
1771
1772                     f = new FuncDeclaration(loc, 0, ident, storage_class, t);
1773                     a.push(f);
1774                     parseContracts(f);
1775                 } else {
1776                     VarDeclaration v;
1777                     Initializer init;
1778
1779                     init = null;
1780                     if (token.value == TOKassign) {
1781                         nextToken();
1782                         init = parseInitializer();
1783                     }
1784                     v = new VarDeclaration(loc, t, ident, init);
1785                     v.storage_class = storage_class;
1786                     a.push(v);
1787                     switch (token.value) {
1788                         case TOKsemicolon:
1789                             nextToken();
1790                             break;
1791
1792                         case TOKcomma:
1793                             nextToken();
1794                             continue;
1795
1796                         default:
1797                             error("semicolon expected, not '%s'", token.toString());
1798                             break;
1799                     }
1800                 }
1801                 break;
1802             }
1803             return a;
1804         }
1805
1806         /*****************************************
1807          * Parse contracts following function declaration.
1808          */
1809
1810         void parseContracts(FuncDeclaration f) {
1811             Type tb;
1812             uint linksave = linkage;
1813
1814             // The following is irrelevant, as it is overridden by sc.linkage in
1815             // TypeFunction.semantic
1816             linkage = LINKd;            // nested functions have D linkage
1817           L1:
1818             switch (token.value) {
1819                 case TOKlcurly:
1820                     if (f.frequire || f.fensure)
1821                         error("missing body { ... } after in or out");
1822                     f.fbody = parseStatement(PSsemi);
1823                     /+f.endloc = endloc;+/
1824                     break;
1825        
1826                 case TOKbody:
1827                     nextToken();
1828                     f.fbody = parseStatement(PScurly);
1829                     /+f.endloc = endloc;+/
1830                     break;
1831        
1832                 case TOKsemicolon:
1833                     if (f.frequire || f.fensure)
1834                         error("missing body { ... } after in or out");
1835                     nextToken();
1836                     break;
1837        
1838                 case TOKin:
1839                     nextToken();
1840                     if (f.frequire)
1841                         error("redundant 'in' statement");
1842                     f.frequire = parseStatement(PScurly | PSscope);
1843                     goto L1;
1844        
1845                 case TOKout:
1846                     // parse: out (identifier) { statement }
1847                     nextToken();
1848                     if (token.value != TOKlcurly) {
1849                         check(TOKlparen);
1850                         if (token.value != TOKidentifier)
1851                             error("(identifier) following 'out' expected, not %s", token.toString());
1852                         f.outId = token.ident;
1853                         nextToken();
1854                         check(TOKrparen);
1855                     }
1856                     if (f.fensure)
1857                         error("redundant 'out' statement");
1858                     f.fensure = parseStatement(PScurly | PSscope);
1859                     goto L1;
1860        
1861                 default:
1862                     error("semicolon expected following function declaration");
1863                     break;
1864             }
1865             linkage = linksave;
1866         }
1867        
1868         /*****************************************
1869          */
1870        
1871         Initializer parseInitializer() {
1872             StructInitializer ist;
1873             ArrayInitializer ia;
1874             ExpInitializer ie;
1875             Expression e;
1876             Identifier id;
1877             Initializer value;
1878             int comma;
1879             Loc loc = this.loc;
1880             Token t;
1881        
1882             switch (token.value) {
1883                 case TOKlcurly:
1884                     ist = new StructInitializer(loc);
1885                     nextToken();
1886                     comma = 0;
1887                     while (1) {
1888                         switch (token.value) {
1889                             case TOKidentifier:
1890                                 if (comma == 1)
1891                                     error("comma expected separating field initializers");
1892                                 t = peek(token);
1893                                 if (t.value == TOKcolon) {
1894                                     id = token.ident;
1895                                     nextToken();
1896                                     nextToken();    // skip over ':'
1897                                 } else {
1898                                     id = null;
1899                                 }
1900                                 value = parseInitializer();
1901                                 ist.addInit(id, value);
1902                                 comma = 1;
1903                                 continue;
1904        
1905                             case TOKcomma:
1906                                 nextToken();
1907                                 comma = 2;
1908                                 continue;
1909        
1910                             case TOKrcurly: // allow trailing comma's
1911                                 nextToken();
1912                                 break;
1913        
1914                             default:
1915                                 value = parseInitializer();
1916                                 ist.addInit(null, value);
1917                                 comma = 1;
1918                                 continue;
1919                                 //error("found '%s' instead of field initializer", token.toString());
1920                                 //break;
1921                         }
1922                         break;
1923                     }
1924                     return ist;
1925        
1926                 case TOKlbracket:
1927                     ia = new ArrayInitializer(loc);
1928                     nextToken();
1929                     comma = 0;
1930                     while (1) {
1931                         switch (token.value) {
1932                             default:
1933                                 if (comma == 1) {
1934                                     error("comma expected separating array initializers, not %s", token.toString());
1935                                     nextToken();
1936                                     break;
1937                                 }
1938                                 e = parseAssignExp();
1939                                 if (!e)
1940                                     break;
1941                                 if (token.value == TOKcolon) {
1942                                     nextToken();
1943                                     value = parseInitializer();
1944                                 } else {
1945                                     value = new ExpInitializer(e.loc, e);
1946                                     e = null;
1947                                 }
1948                                 ia.addInit(e, value);
1949                                 comma = 1;
1950                                 continue;
1951        
1952                             case TOKlcurly:
1953                             case TOKlbracket:
1954                                 if (comma == 1)
1955                                     error("comma expected separating array initializers, not %s", token.toString());
1956                                 value = parseInitializer();
1957                                 ia.addInit(null, value);
1958                                 comma = 1;
1959                                 continue;
1960        
1961                             case TOKcomma:
1962                                 nextToken();
1963                                 comma = 2;
1964                                 continue;
1965        
1966                             case TOKrbracket:   // allow trailing comma's
1967                                 nextToken();
1968                                 break;
1969        
1970                             case TOKeof:
1971                                 error("found '%s' instead of array initializer", token.toString());
1972                                 break;
1973                         }
1974                         break;
1975                     }
1976                     return ia;
1977
1978                 default:
1979                     e = parseAssignExp();
1980                     ie = new ExpInitializer(loc, e);
1981                     return ie;
1982             }
1983         }
1984
1985
1986         /*****************************************
1987          * Input:
1988          *  flags   PSxxxx
1989          */
1990
1991         Statement parseStatement(int flags)
1992         {
1993             Statement s;
1994             Token t;
1995             Loc loc = this.loc;
1996
1997             //printf("parseStatement()\n");
1998        
1999             if (flags & PScurly && token.value != TOKlcurly)
2000                 error("statement expected to be { }, not %s", token.toString());
2001        
2002             switch (token.value) {
2003                 case TOKidentifier:
2004                     // Need to look ahead to see if it is a declaration, label, or expression
2005                     t = peek(token);
2006                     if (t.value == TOKcolon) {  // It's a label
2007                         Identifier ident;
2008        
2009                         ident = token.ident;
2010                         nextToken();
2011                         nextToken();
2012                         /+s = +/parseStatement(PSsemi);
2013                         /+s = new LabelStatement(loc, ident, s);+/
2014                         s = null;
2015                         break;
2016                     }
2017                     // fallthrough to TOKdot
2018                 case TOKdot:
2019                 case TOKtypeof:
2020                     if (isDeclaration(token, 2, TOKreserved, null))
2021                         goto Ldeclaration;
2022                     else
2023                         goto Lexp;
2024                     break;
2025        
2026                 case TOKassert:
2027                 case TOKthis:
2028                 case TOKsuper:
2029                 case TOKint32v:
2030                 case TOKuns32v:
2031                 case TOKint64v:
2032                 case TOKuns64v:
2033                 case TOKfloat32v:
2034                 case TOKfloat64v:
2035                 case TOKfloat80v:
2036                 case TOKimaginary32v:
2037                 case TOKimaginary64v:
2038                 case TOKimaginary80v:
2039                 case TOKcharv:
2040                 case TOKwcharv:
2041                 case TOKdcharv:
2042                 case TOKnull:
2043                 case TOKtrue:
2044                 case TOKfalse:
2045                 case TOKstring:
2046                 case TOKlparen:
2047                 case TOKcast:
2048                 case TOKmul:
2049                 case TOKmin:
2050                 case TOKadd:
2051                 case TOKplusplus:
2052                 case TOKminusminus:
2053                 case TOKnew:
2054                 case TOKdelete:
2055                 case TOKdelegate:
2056                 case TOKfunction:
2057                 case TOKtypeid:
2058                   Lexp:
2059                     {
2060                         Expression exp;
2061        
2062                         exp = parseExpression();
2063                         check(TOKsemicolon, "statement");
2064                         /+s = new ExpStatement(loc, exp);+/
2065                         break;
2066                     }
2067        
2068                 case TOKinstance:       // Deprecated
2069                     /* Three cases:
2070                      *  1) Declaration
2071                      *  2) Template Instance Alias
2072                      *  3) Expression
2073                      */
2074                     if (isDeclaration(token, 2, TOKreserved, null)) {
2075                         //printf("it's a declaration\n");
2076                         goto Ldeclaration;
2077                     } else {
2078                         if (isTemplateInstance(token, &t) && t.value == TOKidentifier) {    // case 2
2079                             TemplateInstance ti;
2080                             AliasDeclaration a;
2081        
2082                             ti = parseTemplateInstance();
2083                             assert(ti);
2084                             assert(token.value == TOKidentifier);
2085        
2086                             a = new AliasDeclaration(loc, token.ident, ti);
2087                             s = new DeclarationStatement(loc, a);
2088                             nextToken();
2089                             if (token.value != TOKsemicolon)
2090                                 error("';' expected after template instance, not %s", token.toString());
2091                         } else
2092                             goto Lexp;  // case 3
2093                     }
2094                     break;
2095        
2096                 case TOKstatic:
2097                     {                   // Look ahead to see if it's static assert()
2098                         Token t;
2099        
2100                         t = peek(token);
2101                         if (t.value == TOKassert) {
2102                             nextToken();
2103                             /+s = new StaticAssertStatement(parseStaticAssert());+/
2104                             s = null;
2105                             break;
2106                         }
2107                         goto Ldeclaration;
2108                     }
2109        
2110                 case TOKwchar: case TOKdchar:
2111                 case TOKbit: case TOKchar:
2112                 case TOKint8: case TOKuns8:
2113                 case TOKint16: case TOKuns16:
2114                 case TOKint32: case TOKuns32:
2115                 case TOKint64: case TOKuns64:
2116                 case TOKfloat32: case TOKfloat64: case TOKfloat80:
2117                 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
2118                 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
2119                 case TOKvoid:
2120
2121                 case TOKtypedef:
2122                 case TOKalias:
2123                 case TOKconst:
2124                 case TOKauto:
2125         //  case TOKtypeof:
2126                   Ldeclaration:
2127                     {
2128                         Array a;
2129
2130                         a = parseDeclaration();
2131                         if (a.dim > 1) {
2132                             ArrayT!(Statement) as = new ArrayT!(Statement)();
2133
2134                             as.reserve(a.dim);
2135                             for (int i = 0; i < a.dim; i++) {
2136                                 Dsymbol d = cast(Dsymbol) a.data[i];
2137
2138                                 s = new DeclarationStatement(loc, d);
2139                                 as.push(s);
2140                             }
2141                             s = new CompoundStatement(loc, as);
2142                         } else if (a.dim == 1) {
2143                             Dsymbol d = cast(Dsymbol) a.data[0];
2144
2145                             s = new DeclarationStatement(loc, d);
2146                         } else
2147                             assert(0);
2148                         break;
2149                     }
2150
2151                 case TOKstruct:
2152                 case TOKunion:
2153                 case TOKclass:
2154                 case TOKinterface:
2155                     {
2156                         Dsymbol d;
2157
2158                         d = parseAggregate();
2159                         s = new DeclarationStatement(loc, d);
2160                         break;
2161                     }
2162
2163                 case TOKenum:
2164                     {
2165                         Dsymbol d;
2166        
2167                         d = parseEnum();
2168                         s = new DeclarationStatement(loc, d);
2169                         break;
2170                     }
2171
2172                 case TOKmixin:
2173                     {
2174                         Dsymbol d;
2175        
2176                         d = parseMixin();
2177                         s = new DeclarationStatement(loc, d);
2178                         break;
2179                     }
2180
2181                 case TOKlcurly:
2182                     {
2183                         nextToken();
2184                         while (token.value != TOKrcurly) {
2185                             parseStatement(PSsemi | PScurlyscope);
2186                         }
2187                         nextToken();
2188                         break;
2189                     }
2190
2191                 case TOKwhile:
2192                     {
2193                         nextToken();
2194                         check(TOKlparen);
2195                         parseExpression();
2196                         check(TOKrparen);
2197                         parseStatement(PSscope);
2198                         s = null;
2199                         break;
2200                     }
2201
2202                 case TOKsemicolon:
2203                     if (!(flags & PSsemi))
2204                         error("use '{ }' for an empty statement, not a ';'");
2205                     nextToken();
2206                     s = new ExpStatement(loc, null);
2207                     break;
2208
2209                 case TOKdo:
2210                     {
2211                         nextToken();
2212                         parseStatement(PSscope);
2213                         check(TOKwhile);
2214                         check(TOKlparen);
2215                         parseExpression();
2216                         check(TOKrparen);
2217                         s = null;
2218                         break;
2219                     }
2220
2221                 case TOKfor:
2222                     {
2223                         nextToken();
2224                         check(TOKlparen);
2225                         if (token.value == TOKsemicolon) {
2226                             nextToken();
2227                         } else {
2228                             parseStatement(0);
2229                         }
2230                         if (token.value == TOKsemicolon) {
2231                             nextToken();
2232                         } else {
2233                             parseExpression();
2234                             check(TOKsemicolon, "for condition");
2235                         }
2236                         if (token.value == TOKrparen) {
2237                             nextToken();
2238                         } else {
2239                             parseExpression();
2240                             check(TOKrparen);
2241                         }
2242                         parseStatement(0);
2243                         s = null;
2244                         break;
2245                     }
2246
2247                 case TOKforeach:
2248                     {
2249                         nextToken();
2250                         check(TOKlparen);
2251        
2252                         while (1) {
2253                             Type tb;
2254                             Identifier ai = null;
2255                             Type at;
2256                             uint inoutt;
2257                             Argument a;
2258        
2259                             inoutt = In;
2260                             if (token.value == TOKinout) {
2261                                 inoutt = InOut;
2262                                 nextToken();
2263                             }
2264                             tb = parseBasicType();
2265                             at = parseDeclarator(tb, &ai);
2266                             if (!ai)
2267                                 error("no identifier for declarator");
2268                             if (token.value == TOKcomma) {
2269                                 nextToken();
2270                                 continue;
2271                             }
2272                             break;
2273                         }
2274                         check(TOKsemicolon);
2275        
2276                         parseExpression();
2277                         check(TOKrparen);
2278                         parseStatement(0);
2279                         s = null;
2280                         break;
2281                     }
2282        
2283                 case TOKif:
2284                     {
2285                         nextToken();
2286                         check(TOKlparen);
2287                         parseExpression();
2288                         check(TOKrparen);
2289                         parseStatement(PSscope);
2290                         if (token.value == TOKelse) {
2291                             nextToken();
2292                             parseStatement(PSscope);
2293                         }
2294                         s = null;
2295                         break;
2296                     }
2297        
2298                 case TOKdebug:
2299                     {
2300                         nextToken();
2301                         if (token.value == TOKlparen) {
2302                             nextToken();
2303                             parseDebugCondition();
2304                             check(TOKrparen);
2305                         }
2306                         parseStatement(PSsemi);
2307                         if (token.value == TOKelse) {
2308                             nextToken();
2309                             parseStatement<