Fix parsing problem with array initialisers
[delight/core.git] / dmd / parse.c
blobd56438ab3a208459d7ad2fe28328c80047279294
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, September 2004
17 #include <stdio.h>
18 #include <assert.h>
20 #include "mem.h"
21 #include "lexer.h"
22 #include "parse.h"
23 #include "init.h"
24 #include "attrib.h"
25 #include "cond.h"
26 #include "mtype.h"
27 #include "template.h"
28 #include "staticassert.h"
29 #include "expression.h"
30 #include "statement.h"
31 #include "module.h"
32 #include "dsymbol.h"
33 #include "import.h"
34 #include "declaration.h"
35 #include "aggregate.h"
36 #include "enum.h"
37 #include "id.h"
38 #include "version.h"
39 #ifdef IN_GCC
40 #include "d-dmd-gcc.h"
41 #endif
43 // How multiple declarations are parsed.
44 // If 1, treat as C.
45 // If 0, treat:
46 // int *p, i;
47 // as:
48 // int* p;
49 // int* i;
50 #define CDECLSYNTAX 0
52 // Support C cast syntax:
53 // (type)(expression)
54 #define CCASTSYNTAX 1
56 // Support C array declarations, such as
57 // int a[3][4];
58 #define CARRAYDECL 1
60 // Support left-to-right array declarations
61 #define LTORARRAYDECL 1
64 Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
65 : Lexer(module, base, 0, length, doDocComment, 0, module->isDltFile)
67 //printf("Parser::Parser()\n");
68 md = NULL;
69 linkage = LINKd;
70 endloc = 0;
71 inBrackets = 0;
72 startBlockTok = TOKlcurly;
73 //nextToken(); // start up the scanner
76 DltParser::DltParser(Module *module, unsigned char *base, unsigned length, int doDocComment)
77 : Parser(module, base, length, doDocComment)
79 //printf("DltParser::DltParser(%s)\n", module->ident->string);
80 startBlockTok = TOKcolon;
83 Array *Parser::parseModule()
85 Array *decldefs;
87 // ModuleDeclation leads off
88 optionalEndline();
89 if (token.value == TOKmodule)
91 unsigned char *comment = token.blockComment;
93 nextToken();
94 if (token.value != TOKidentifier)
95 { error("Identifier expected following module");
96 goto Lerr;
98 else
100 Array *a = NULL;
101 Identifier *id;
103 id = token.ident;
104 while (nextToken() == TOKdot)
106 if (!a)
107 a = new Array();
108 a->push(id);
109 nextToken();
110 if (token.value != TOKidentifier)
111 { error("Identifier expected following package");
112 goto Lerr;
114 id = token.ident;
117 md = new ModuleDeclaration(a, id);
119 TOK end = dltSyntax ? TOKendline : TOKsemicolon;
120 if (token.value != end)
121 error("%s expected following module declaration instead of %s", Token::toChars(end), token.toChars());
123 nextToken();
124 addComment(mod, comment);
128 decldefs = parseDeclDefs(0);
129 if (token.value != TOKeof)
130 { error("unrecognized declaration '%s'", token.toChars());
131 goto Lerr;
133 return decldefs;
135 Lerr:
136 while (token.value != TOKsemicolon && token.value != TOKeof)
137 nextToken();
138 nextToken();
139 return new Array();
142 Array *Parser::parseDeclDefs(int once)
143 { Dsymbol *s;
144 Array *decldefs;
145 Array *a;
146 Array *aelse;
147 enum PROT prot;
148 unsigned stc;
149 Condition *condition;
150 unsigned char *comment;
152 //printf("Parser::parseDeclDefs()\n");
153 decldefs = new Array();
156 comment = token.blockComment;
157 switch (token.value)
159 case TOKendline:
160 nextToken();
161 continue;
162 case TOKenum:
163 s = parseEnum();
164 break;
166 case TOKstruct:
167 case TOKunion:
168 case TOKclass:
169 case TOKinterface:
170 s = parseAggregate();
171 break;
173 case TOKimport:
174 s = parseImport(decldefs, 0);
175 break;
177 case TOKtemplate:
178 s = (Dsymbol *)parseTemplateDeclaration();
179 break;
181 case TOKmixin:
182 { Loc loc = this->loc;
183 if (peek(&token)->value == TOKlparen)
184 { // mixin(string)
185 nextToken();
186 check(TOKlparen, "mixin");
187 Expression *e = parseAssignExp();
188 check(TOKrparen);
189 check(TOKsemicolon);
190 s = new CompileDeclaration(loc, e);
191 break;
193 s = parseMixin();
194 break;
197 CASE_BASIC_TYPES:
198 case TOKalias:
199 case TOKtypedef:
200 case TOKidentifier:
201 case TOKtypeof:
202 case TOKdot:
203 Ldeclaration:
204 a = parseDeclarations();
205 decldefs->append(a);
206 continue;
208 case TOKthis:
209 s = parseCtor();
210 break;
212 case TOKtilde:
213 s = parseDtor();
214 break;
216 case TOKinvariant:
217 #if 1
218 s = parseInvariant();
219 #else
220 if (peek(&token)->value == TOKlcurly)
221 s = parseInvariant();
222 else
224 stc = STCinvariant;
225 goto Lstc;
227 #endif
228 break;
230 case TOKunittest:
231 s = parseUnitTest();
232 break;
234 case TOKnew:
235 s = parseNew();
236 break;
238 case TOKdelete:
239 s = parseDelete();
240 break;
242 case TOKeof:
243 case TOKrcurly:
244 return decldefs;
246 case TOKstatic:
247 nextToken();
248 if (token.value == TOKthis)
249 s = parseStaticCtor();
250 else if (token.value == TOKtilde)
251 s = parseStaticDtor();
252 else if (token.value == TOKassert)
253 s = parseStaticAssert();
254 else if (token.value == TOKif)
255 { condition = parseStaticIfCondition();
256 a = parseBlock();
257 aelse = NULL;
258 if (token.value == TOKelse)
259 { nextToken();
260 aelse = parseBlock();
262 s = new StaticIfDeclaration(condition, a, aelse);
263 break;
265 else if (token.value == TOKimport)
267 s = parseImport(decldefs, 1);
269 else
270 { stc = STCstatic;
271 goto Lstc2;
273 break;
275 case TOKin:
276 nextToken();
277 stc = STCin;
278 goto Lstc2;
280 case TOKconst: stc = STCconst; goto Lstc;
281 case TOKfinal: stc = STCfinal; goto Lstc;
282 case TOKauto: stc = STCauto; goto Lstc;
283 case TOKscope: stc = STCscope; goto Lstc;
284 case TOKoverride: stc = STCoverride; goto Lstc;
285 case TOKabstract: stc = STCabstract; goto Lstc;
286 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
287 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
289 Lstc:
290 nextToken();
291 Lstc2:
292 switch (token.value)
294 case TOKconst: stc |= STCconst; goto Lstc;
295 case TOKfinal: stc |= STCfinal; goto Lstc;
296 case TOKauto: stc |= STCauto; goto Lstc;
297 case TOKscope: stc |= STCscope; goto Lstc;
298 case TOKoverride: stc |= STCoverride; goto Lstc;
299 case TOKabstract: stc |= STCabstract; goto Lstc;
300 case TOKsynchronized: stc |= STCsynchronized; goto Lstc;
301 case TOKdeprecated: stc |= STCdeprecated; goto Lstc;
302 //case TOKinvariant: stc |= STCinvariant; goto Lstc;
303 default:
304 break;
307 /* Look for auto initializers:
308 * storage_class identifier = initializer;
310 if (token.value == TOKidentifier &&
311 peek(&token)->value == TOKassign)
313 while (1)
315 Identifier *ident = token.ident;
316 nextToken();
317 nextToken();
318 Initializer *init = parseInitializer();
319 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
320 v->storage_class = stc;
321 s = v;
322 if (token.value == TOKsemicolon || token.value == TOKendline)
324 nextToken();
326 else if (token.value == TOKcomma)
328 nextToken();
329 if (token.value == TOKidentifier &&
330 peek(&token)->value == TOKassign)
332 decldefs->push(s);
333 addComment(s, comment);
334 continue;
336 else
337 error("Identifier expected following comma");
339 else
340 error("%s expected following declaration, not '%s'", endToken(), token.toChars());
341 break;
344 else
345 { a = parseBlock();
346 s = new StorageClassDeclaration(stc, a);
348 break;
350 case TOKextern:
351 if (peek(&token)->value != TOKlparen)
352 { stc = STCextern;
353 goto Lstc;
356 enum LINK linksave = linkage;
357 linkage = parseLinkage();
358 a = parseBlock();
359 s = new LinkDeclaration(linkage, a);
360 linkage = linksave;
361 break;
363 case TOKprivate: prot = PROTprivate; goto Lprot;
364 case TOKpackage: prot = PROTpackage; goto Lprot;
365 case TOKprotected: prot = PROTprotected; goto Lprot;
366 case TOKpublic: prot = PROTpublic; goto Lprot;
367 case TOKexport: prot = PROTexport; goto Lprot;
369 Lprot:
370 nextToken();
371 a = parseBlock();
372 s = new ProtDeclaration(prot, a);
373 break;
375 case TOKalign:
376 { unsigned n;
378 s = NULL;
379 nextToken();
380 if (token.value == TOKlparen)
382 nextToken();
383 if (token.value == TOKint32v)
384 n = (unsigned)token.uns64value;
385 else
386 { error("integer expected, not %s", token.toChars());
387 n = 1;
389 nextToken();
390 check(TOKrparen);
392 else
393 n = global.structalign; // default
395 a = parseBlock();
396 s = new AlignDeclaration(n, a);
397 break;
400 case TOKpragma:
401 { Identifier *ident;
402 Expressions *args = NULL;
404 nextToken();
405 check(TOKlparen);
406 if (token.value != TOKidentifier)
407 { error("pragma(identifier expected");
408 goto Lerror;
410 ident = token.ident;
411 nextToken();
412 if (token.value == TOKcomma)
413 args = parseArguments(); // pragma(identifier, args...)
414 else
415 check(TOKrparen); // pragma(identifier)
417 if (token.value == TOKsemicolon || token.value == TOKendline)
418 a = NULL;
419 else if (dltSyntax)
421 check(TOKcolon);
422 a = parseDeclDefs(0);
423 check(TOKrcurly);
425 else
426 a = parseBlock();
427 s = new PragmaDeclaration(loc, ident, args, a);
428 break;
431 case TOKdebug:
432 nextToken();
433 if (token.value == TOKassign)
435 nextToken();
436 if (token.value == TOKidentifier)
437 s = new DebugSymbol(loc, token.ident);
438 else if (token.value == TOKint32v)
439 s = new DebugSymbol(loc, (unsigned)token.uns64value);
440 else
441 { error("identifier or integer expected, not %s", token.toChars());
442 s = NULL;
444 nextToken();
445 if (token.value != TOKsemicolon)
446 error("semicolon expected");
447 nextToken();
448 break;
451 condition = parseDebugCondition();
452 goto Lcondition;
454 case TOKversion:
455 nextToken();
456 if (token.value == TOKassign)
458 nextToken();
459 if (token.value == TOKidentifier)
460 s = new VersionSymbol(loc, token.ident);
461 else if (token.value == TOKint32v)
462 s = new VersionSymbol(loc, (unsigned)token.uns64value);
463 else
464 { error("identifier or integer expected, not %s", token.toChars());
465 s = NULL;
467 nextToken();
468 if (token.value != TOKsemicolon && token.value != TOKendline)
469 error("%s expected after version assignment", endToken());
470 nextToken();
471 break;
473 condition = parseVersionCondition();
474 goto Lcondition;
476 Lcondition:
477 a = parseBlock();
478 aelse = NULL;
479 if (token.value == TOKelse)
480 { nextToken();
481 aelse = parseBlock();
483 s = new ConditionalDeclaration(condition, a, aelse);
484 break;
486 case TOKsemicolon: // empty declaration
487 nextToken();
488 continue;
490 default:
491 error("Declaration expected, not '%s'",token.toChars());
492 Lerror:
493 while (token.value != TOKsemicolon && token.value != TOKendline && token.value != TOKeof)
494 nextToken();
495 nextToken();
496 s = NULL;
497 continue;
499 if (s)
500 { decldefs->push(s);
501 addComment(s, comment);
503 } while (!once);
504 return decldefs;
508 /********************************************
509 * Parse declarations after an align, protection, or extern decl.
512 Array *Parser::parseBlock()
514 Array *a = NULL;
515 Dsymbol *s;
517 //printf("Parser::parseBlock()\n");
518 switch (token.value)
520 case TOKsemicolon:
521 error("declaration expected following attribute, not ';'");
522 nextToken();
523 break;
525 case TOKlcurly:
526 nextToken();
527 a = parseDeclDefs(0);
528 if (token.value != TOKrcurly)
529 { /* { */
530 error("matching '}' expected, not %s", token.toChars());
532 else
533 nextToken();
534 break;
536 case TOKcolon:
537 nextToken();
538 #if 0
539 a = NULL;
540 #else
541 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
542 #endif
543 break;
545 default:
546 a = parseDeclDefs(1);
547 break;
549 return a;
552 Array *DltParser::parseBlock()
554 Array *a = NULL;
555 Dsymbol *s;
557 optionalEndline();
558 switch (token.value)
560 case TOKendline:
561 case TOKsemicolon:
562 error("declaration expected following attribute, not %s", token.toChars());
563 nextToken();
564 break;
566 case TOKcolon:
567 nextToken();
568 a = parseDeclDefs(0);
569 if (token.value != TOKrcurly)
571 error("matching end-of-block expected, not %s", token.toChars());
573 else
574 nextToken();
575 break;
577 default:
578 a = parseDeclDefs(1);
579 break;
581 return a;
584 /**********************************
585 * Parse a static assertion.
588 StaticAssert *Parser::parseStaticAssert()
590 Loc loc = this->loc;
591 Expression *exp;
592 Expression *msg = NULL;
594 //printf("parseStaticAssert()\n");
595 nextToken();
596 checkLParen();
597 exp = parseAssignExp();
598 if (token.value == TOKcomma)
599 { nextToken();
600 msg = parseAssignExp();
602 checkRParen();
603 if (token.value == TOKsemicolon || token.value == TOKendline) {
604 nextToken();
605 return new StaticAssert(loc, exp, msg);
607 error("expected %s after static assert", endToken());
611 /***********************************
612 * Parse extern (linkage)
613 * The parser is on the 'extern' token.
616 enum LINK Parser::parseLinkage()
618 enum LINK link = LINKdefault;
619 nextToken();
620 assert(token.value == TOKlparen);
621 nextToken();
622 if (token.value == TOKidentifier)
623 { Identifier *id = token.ident;
625 nextToken();
626 if (id == Id::Windows)
627 link = LINKwindows;
628 else if (id == Id::Pascal)
629 link = LINKpascal;
630 else if (id == Id::D)
631 link = LINKd;
632 else if (id == Id::C)
634 link = LINKc;
635 if (token.value == TOKplusplus)
636 { link = LINKcpp;
637 nextToken();
640 else if (id == Id::System)
642 #ifdef IN_GCC
643 link = d_gcc_is_target_win32() ? LINKwindows : LINKc;
644 #else
645 #if _WIN32
646 link = LINKwindows;
647 #else
648 link = LINKc;
649 #endif
650 #endif
652 else
654 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
655 link = LINKd;
658 else
660 link = LINKd; // default
662 check(TOKrparen);
663 return link;
666 /**************************************
667 * Parse a debug conditional
670 Condition *Parser::parseDebugCondition()
672 Condition *c;
674 if (token.value == TOKlparen)
676 nextToken();
677 unsigned level = 1;
678 Identifier *id = NULL;
680 if (token.value == TOKidentifier)
681 id = token.ident;
682 else if (token.value == TOKint32v)
683 level = (unsigned)token.uns64value;
684 else
685 error("identifier or integer expected, not %s", token.toChars());
686 nextToken();
687 check(TOKrparen);
688 c = new DebugCondition(mod, level, id);
689 if (dltSyntax && token.value != TOKcolon)
690 error("expected colon after debug(), not '%s'", token.toChars());
691 } else {
692 if (dltSyntax && token.value != TOKcolon)
693 error("expected ':' or '(' after 'debug', not '%s'", token.toChars());
694 c = new DebugCondition(mod, 1, NULL);
696 return c;
700 /**************************************
701 * Parse a version conditional
704 Condition *Parser::parseVersionCondition()
706 Condition *c;
707 unsigned level = 1;
708 Identifier *id = NULL;
710 if (token.value == TOKlparen)
712 nextToken();
713 if (token.value == TOKidentifier)
714 id = token.ident;
715 else if (token.value == TOKint32v)
716 level = (unsigned)token.uns64value;
717 #if V2
718 /* Allow:
719 * version (unittest)
720 * even though unittest is a keyword
722 else if (token.value == TOKunittest)
723 id = Lexer::idPool(Token::toChars(TOKunittest));
724 #endif
725 else
726 error("identifier or integer expected, not %s", token.toChars());
727 nextToken();
728 check(TOKrparen);
731 else
732 error("(condition) expected following version");
733 c = new VersionCondition(mod, level, id);
734 return c;
738 /***********************************************
739 * static if (expression)
740 * body
741 * else
742 * body
745 Condition *Parser::parseStaticIfCondition()
746 { Expression *exp;
747 Condition *condition;
748 Array *aif;
749 Array *aelse;
750 Loc loc = this->loc;
752 nextToken();
753 checkLParen();
754 exp = parseAssignExp();
755 checkRParen();
757 condition = new StaticIfCondition(loc, exp);
758 return condition;
762 /*****************************************
763 * Parse a constructor definition:
764 * this(arguments) { body }
765 * Current token is 'this'.
768 CtorDeclaration *Parser::parseCtor()
770 CtorDeclaration *f;
771 Arguments *arguments;
772 int varargs;
773 Loc loc = this->loc;
775 nextToken();
776 arguments = parseParameters(&varargs);
777 f = new CtorDeclaration(loc, 0, arguments, varargs);
778 parseContracts(f);
779 return f;
782 /*****************************************
783 * Parse a destructor definition:
784 * ~this() { body }
785 * Current token is '~'.
788 DtorDeclaration *Parser::parseDtor()
790 DtorDeclaration *f;
791 Loc loc = this->loc;
793 nextToken();
794 check(TOKthis);
795 check(TOKlparen);
796 check(TOKrparen);
798 f = new DtorDeclaration(loc, 0);
799 parseContracts(f);
800 return f;
803 /*****************************************
804 * Parse a static constructor definition:
805 * static this() { body }
806 * Current token is 'this'.
809 StaticCtorDeclaration *Parser::parseStaticCtor()
811 StaticCtorDeclaration *f;
812 Loc loc = this->loc;
814 nextToken();
815 check(TOKlparen);
816 check(TOKrparen);
818 f = new StaticCtorDeclaration(loc, 0);
819 parseContracts(f);
820 return f;
823 /*****************************************
824 * Parse a static destructor definition:
825 * static ~this() { body }
826 * Current token is '~'.
829 StaticDtorDeclaration *Parser::parseStaticDtor()
831 StaticDtorDeclaration *f;
832 Loc loc = this->loc;
834 nextToken();
835 check(TOKthis);
836 check(TOKlparen);
837 check(TOKrparen);
839 f = new StaticDtorDeclaration(loc, 0);
840 parseContracts(f);
841 return f;
844 /*****************************************
845 * Parse an invariant definition:
846 * invariant { body }
847 * Current token is 'invariant'.
850 InvariantDeclaration *Parser::parseInvariant()
852 InvariantDeclaration *f;
853 Loc loc = this->loc;
855 nextToken();
856 if (token.value == TOKlparen) // optional ()
858 nextToken();
859 check(TOKrparen);
862 f = new InvariantDeclaration(loc, 0);
863 f->fbody = parseStatement(PScurly);
864 return f;
867 /*****************************************
868 * Parse a unittest definition:
869 * unittest { body }
870 * Current token is 'unittest'.
873 UnitTestDeclaration *Parser::parseUnitTest()
875 UnitTestDeclaration *f;
876 Statement *body;
877 Loc loc = this->loc;
879 nextToken();
881 body = parseStatement(PScurly);
883 f = new UnitTestDeclaration(loc, this->loc);
884 f->fbody = body;
885 return f;
888 /*****************************************
889 * Parse a new definition:
890 * new(arguments) { body }
891 * Current token is 'new'.
894 NewDeclaration *Parser::parseNew()
896 NewDeclaration *f;
897 Arguments *arguments;
898 int varargs;
899 Loc loc = this->loc;
901 nextToken();
902 arguments = parseParameters(&varargs);
903 f = new NewDeclaration(loc, 0, arguments, varargs);
904 parseContracts(f);
905 return f;
908 /*****************************************
909 * Parse a delete definition:
910 * delete(arguments) { body }
911 * Current token is 'delete'.
914 DeleteDeclaration *Parser::parseDelete()
916 DeleteDeclaration *f;
917 Arguments *arguments;
918 int varargs;
919 Loc loc = this->loc;
921 nextToken();
922 arguments = parseParameters(&varargs);
923 if (varargs)
924 error("... not allowed in delete function parameter list");
925 f = new DeleteDeclaration(loc, 0, arguments);
926 parseContracts(f);
927 return f;
930 /**********************************************
931 * Parse parameter list.
934 Arguments *Parser::parseParameters(int *pvarargs)
936 Arguments *arguments = new Arguments();
937 int varargs = 0;
938 int hasdefault = 0;
940 check(TOKlparen);
941 while (1)
942 { Type *tb;
943 Identifier *ai;
944 Type *at;
945 Argument *a;
946 unsigned storageClass;
947 Expression *ae;
949 ai = NULL;
950 storageClass = STCin; // parameter is "in" by default
951 switch (token.value)
953 case TOKrparen:
954 break;
956 case TOKdotdotdot:
957 varargs = 1;
958 nextToken();
959 break;
961 case TOKin:
962 storageClass = STCin;
963 nextToken();
964 goto L1;
966 case TOKout:
967 storageClass = STCout;
968 nextToken();
969 goto L1;
971 case TOKinout:
972 case TOKref:
973 storageClass = STCref;
974 nextToken();
975 goto L1;
977 case TOKlazy:
978 storageClass = STClazy;
979 nextToken();
980 goto L1;
982 default:
984 tb = parseBasicType();
985 at = parseDeclarator(tb, &ai);
986 ae = NULL;
987 if (token.value == TOKassign) // = defaultArg
988 { nextToken();
989 ae = parseAssignExp();
990 hasdefault = 1;
992 else
993 { if (hasdefault)
994 error("default argument expected for %s",
995 ai ? ai->toChars() : at->toChars());
997 if (token.value == TOKdotdotdot)
998 { /* This is:
999 * at ai ...
1002 if (storageClass & (STCout | STCref))
1003 error("variadic argument cannot be out or ref");
1004 varargs = 2;
1005 a = new Argument(storageClass, at, ai, ae);
1006 arguments->push(a);
1007 nextToken();
1008 break;
1010 a = new Argument(storageClass, at, ai, ae);
1011 arguments->push(a);
1012 if (token.value == TOKcomma)
1013 { nextToken();
1014 continue;
1016 break;
1018 break;
1020 check(TOKrparen);
1021 *pvarargs = varargs;
1022 return arguments;
1026 /*************************************
1029 EnumDeclaration *Parser::parseEnum()
1030 { EnumDeclaration *e;
1031 Identifier *id;
1032 Type *t;
1033 Loc loc = this->loc;
1035 //printf("Parser::parseEnum()\n");
1036 nextToken();
1037 if (token.value == TOKidentifier)
1038 { id = token.ident;
1039 nextToken();
1041 else
1042 id = NULL;
1044 if (token.value == (dltSyntax ? TOKextends : TOKcolon))
1046 nextToken();
1047 t = parseBasicType();
1049 else
1050 t = NULL;
1052 e = new EnumDeclaration(loc, id, t);
1053 if (token.value == TOKsemicolon && id)
1054 nextToken();
1055 else if (token.value == startBlockTok)
1057 //printf("enum definition\n");
1058 e->members = new Array();
1059 nextToken();
1060 unsigned char *comment = token.blockComment;
1061 optionalEndline();
1062 while (token.value != TOKrcurly)
1064 if (token.value == TOKidentifier)
1065 { EnumMember *em;
1066 Expression *value;
1067 Identifier *ident;
1069 loc = this->loc;
1070 ident = token.ident;
1071 value = NULL;
1072 nextToken();
1073 if (token.value == TOKassign)
1075 nextToken();
1076 value = parseAssignExp();
1078 em = new EnumMember(loc, ident, value);
1079 e->members->push(em);
1080 optionalEndline();
1081 if (token.value == TOKrcurly)
1083 else
1084 { addComment(em, comment);
1085 comment = NULL;
1086 check(TOKcomma);
1087 optionalEndline();
1089 addComment(em, comment);
1090 comment = token.blockComment;
1092 else
1093 { error("enum member expected");
1094 nextToken();
1097 nextToken();
1099 else
1100 error("enum declaration is invalid");
1102 return e;
1105 Dsymbol *Parser::parseAggregate()
1106 { AggregateDeclaration *a = NULL;
1107 int anon = 0;
1108 enum TOK tok;
1109 Identifier *id;
1110 TemplateParameters *tpl = NULL;
1112 //printf("Parser::parseAggregate()\n");
1113 tok = token.value;
1114 nextToken();
1115 if (token.value != TOKidentifier)
1116 { id = NULL;
1118 else
1119 { id = token.ident;
1120 nextToken();
1122 if (token.value == TOKlparen)
1123 { // Class template declaration.
1125 // Gather template parameter list
1126 tpl = parseTemplateParameterList();
1130 Loc loc = this->loc;
1131 switch (tok)
1132 { case TOKclass:
1133 case TOKinterface:
1135 if (!id)
1136 error("anonymous classes not allowed");
1138 // Collect base class(es)
1139 BaseClasses *baseclasses = NULL;
1140 if (token.value == (dltSyntax ? TOKextends : TOKcolon))
1142 nextToken();
1143 baseclasses = parseBaseClasses();
1144 if (token.value != startBlockTok)
1145 error("members expected");
1148 if (tok == TOKclass)
1149 a = new ClassDeclaration(loc, id, baseclasses);
1150 else
1151 a = new InterfaceDeclaration(loc, id, baseclasses);
1152 break;
1155 case TOKstruct:
1156 if (id)
1157 a = new StructDeclaration(loc, id);
1158 else
1159 anon = 1;
1160 break;
1162 case TOKunion:
1163 if (id)
1164 a = new UnionDeclaration(loc, id);
1165 else
1166 anon = 2;
1167 break;
1169 default:
1170 assert(0);
1171 break;
1173 if (a && token.value == (dltSyntax ? TOKendline : TOKsemicolon))
1174 { nextToken();
1176 else if (token.value == startBlockTok)
1178 //printf("aggregate definition\n");
1179 nextToken();
1180 optionalEndline();
1181 Array *decl = parseDeclDefs(0);
1182 if (token.value != TOKrcurly)
1183 error("end-of-block expected following member declarations in aggregate");
1184 nextToken();
1185 if (anon)
1187 /* Anonymous structs/unions are more like attributes.
1189 return new AnonDeclaration(loc, anon - 1, decl);
1191 else
1192 a->members = decl;
1194 else
1196 error("%s expected following aggregate declaration", Token::toChars(startBlockTok));
1197 a = new StructDeclaration(loc, NULL);
1200 if (tpl)
1201 { Array *decldefs;
1202 TemplateDeclaration *tempdecl;
1204 // Wrap a template around the aggregate declaration
1205 decldefs = new Array();
1206 decldefs->push(a);
1207 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1208 return tempdecl;
1211 return a;
1214 /*******************************************
1217 BaseClasses *Parser::parseBaseClasses()
1219 enum PROT protection = PROTpublic;
1220 BaseClasses *baseclasses = new BaseClasses();
1222 for (; 1; nextToken())
1224 switch (token.value)
1226 case TOKidentifier:
1227 break;
1228 case TOKprivate:
1229 protection = PROTprivate;
1230 continue;
1231 case TOKpackage:
1232 protection = PROTpackage;
1233 continue;
1234 case TOKprotected:
1235 protection = PROTprotected;
1236 continue;
1237 case TOKpublic:
1238 protection = PROTpublic;
1239 continue;
1240 default:
1241 error("base classes expected instead of %s", token.toChars());
1242 return NULL;
1244 BaseClass *b = new BaseClass(parseBasicType(), protection);
1245 baseclasses->push(b);
1246 if (token.value != TOKcomma)
1247 break;
1248 protection = PROTpublic;
1250 return baseclasses;
1253 /**************************************
1254 * Parse a TemplateDeclaration.
1257 TemplateDeclaration *Parser::parseTemplateDeclaration()
1259 TemplateDeclaration *tempdecl;
1260 Identifier *id;
1261 TemplateParameters *tpl;
1262 Array *decldefs;
1263 Loc loc = this->loc;
1265 nextToken();
1266 if (token.value != TOKidentifier)
1267 { error("TemplateIdentifier expected following template");
1268 goto Lerr;
1270 id = token.ident;
1271 nextToken();
1272 tpl = parseTemplateParameterList();
1273 if (!tpl)
1274 goto Lerr;
1276 if (token.value != startBlockTok)
1277 { error("members of template declaration expected");
1278 goto Lerr;
1280 else
1282 nextToken();
1283 decldefs = parseDeclDefs(0);
1284 if (token.value != TOKrcurly)
1285 { error("template member expected");
1286 goto Lerr;
1288 nextToken();
1291 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1292 return tempdecl;
1294 Lerr:
1295 return NULL;
1298 /******************************************
1299 * Parse template parameter list.
1302 TemplateParameters *Parser::parseTemplateParameterList()
1304 TemplateParameters *tpl = new TemplateParameters();
1306 if (token.value != TOKlparen)
1307 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1308 goto Lerr;
1310 nextToken();
1312 // Get array of TemplateParameters
1313 if (token.value != TOKrparen)
1314 { int isvariadic = 0;
1316 while (1)
1317 { TemplateParameter *tp;
1318 Identifier *tp_ident = NULL;
1319 Type *tp_spectype = NULL;
1320 Type *tp_valtype = NULL;
1321 Type *tp_defaulttype = NULL;
1322 Expression *tp_specvalue = NULL;
1323 Expression *tp_defaultvalue = NULL;
1324 Token *t;
1326 // Get TemplateParameter
1328 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1329 t = peek(&token);
1330 if (token.value == TOKalias)
1331 { // AliasParameter
1332 nextToken();
1333 if (token.value != TOKidentifier)
1334 { error("Identifier expected for template parameter");
1335 goto Lerr;
1337 tp_ident = token.ident;
1338 nextToken();
1339 if (token.value == TOKcolon) // : Type
1341 nextToken();
1342 tp_spectype = parseBasicType();
1343 tp_spectype = parseDeclarator(tp_spectype, NULL);
1345 if (token.value == TOKassign) // = Type
1347 nextToken();
1348 tp_defaulttype = parseBasicType();
1349 tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
1351 tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1353 else if (t->value == TOKcolon || t->value == TOKassign ||
1354 t->value == TOKcomma || t->value == TOKrparen)
1355 { // TypeParameter
1356 if (token.value != TOKidentifier)
1357 { error("Identifier expected for template parameter");
1358 goto Lerr;
1360 tp_ident = token.ident;
1361 nextToken();
1362 if (token.value == TOKcolon) // : Type
1364 nextToken();
1365 tp_spectype = parseBasicType();
1366 tp_spectype = parseDeclarator(tp_spectype, NULL);
1368 if (token.value == TOKassign) // = Type
1370 nextToken();
1371 tp_defaulttype = parseBasicType();
1372 tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
1374 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1376 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1377 { // ident...
1378 if (isvariadic)
1379 error("variadic template parameter must be last");
1380 isvariadic = 1;
1381 tp_ident = token.ident;
1382 nextToken();
1383 nextToken();
1384 tp = new TemplateTupleParameter(loc, tp_ident);
1386 else
1387 { // ValueParameter
1388 tp_valtype = parseBasicType();
1389 tp_valtype = parseDeclarator(tp_valtype, &tp_ident);
1390 if (!tp_ident)
1392 error("no identifier for template value parameter");
1393 tp_ident = new Identifier("error", TOKidentifier);
1395 if (token.value == TOKcolon) // : CondExpression
1397 nextToken();
1398 tp_specvalue = parseCondExp();
1400 if (token.value == TOKassign) // = CondExpression
1402 nextToken();
1403 tp_defaultvalue = parseCondExp();
1405 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1407 tpl->push(tp);
1408 if (token.value != TOKcomma)
1409 break;
1410 nextToken();
1413 check(TOKrparen);
1414 Lerr:
1415 return tpl;
1418 /******************************************
1419 * Parse template mixin.
1420 * mixin Foo;
1421 * mixin Foo!(args);
1422 * mixin a.b.c!(args).Foo!(args);
1423 * mixin Foo!(args) identifier;
1424 * mixin typeof(expr).identifier!(args);
1427 Dsymbol *Parser::parseMixin()
1429 TemplateMixin *tm;
1430 Identifier *id;
1431 Type *tqual;
1432 Objects *tiargs;
1433 Array *idents;
1435 //printf("parseMixin()\n");
1436 nextToken();
1437 tqual = NULL;
1438 if (token.value == TOKdot)
1440 id = Id::empty;
1442 else
1444 if (token.value == TOKtypeof)
1445 { Expression *exp;
1447 nextToken();
1448 check(TOKlparen);
1449 exp = parseExpression();
1450 check(TOKrparen);
1451 tqual = new TypeTypeof(loc, exp);
1452 check(TOKdot);
1454 if (token.value != TOKidentifier)
1456 error("identifier expected, not %s", token.toChars());
1457 goto Lerr;
1459 id = token.ident;
1460 nextToken();
1463 idents = new Array();
1464 while (1)
1466 tiargs = NULL;
1467 if (token.value == TOKnot)
1469 nextToken();
1470 tiargs = parseTemplateArgumentList();
1473 if (token.value != TOKdot)
1474 break;
1476 if (tiargs)
1477 { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1478 tempinst->tiargs = tiargs;
1479 id = (Identifier *)tempinst;
1480 tiargs = NULL;
1482 idents->push(id);
1484 nextToken();
1485 if (token.value != TOKidentifier)
1486 { error("identifier expected following '.' instead of '%s'", token.toChars());
1487 break;
1489 id = token.ident;
1490 nextToken();
1492 idents->push(id);
1494 if (token.value == TOKidentifier)
1496 id = token.ident;
1497 nextToken();
1499 else
1500 id = NULL;
1502 tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1503 if (token.value != TOKsemicolon)
1504 error("';' expected after mixin");
1505 nextToken();
1507 return tm;
1509 Lerr:
1510 return NULL;
1513 /******************************************
1514 * Parse template argument list.
1515 * Input:
1516 * current token is opening '('
1517 * Output:
1518 * current token is one after closing ')'
1521 Objects *Parser::parseTemplateArgumentList()
1523 //printf("Parser::parseTemplateArgumentList()\n");
1524 Objects *tiargs = new Objects();
1525 if (token.value != TOKlparen)
1526 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1527 return tiargs;
1529 nextToken();
1531 // Get TemplateArgumentList
1532 if (token.value != TOKrparen)
1534 while (1)
1536 // See if it is an Expression or a Type
1537 if (isDeclaration(&token, 0, TOKreserved, NULL))
1538 { // Type
1539 Type *ta;
1541 // Get TemplateArgument
1542 ta = parseBasicType();
1543 ta = parseDeclarator(ta, NULL);
1544 tiargs->push(ta);
1546 else
1547 { // Expression
1548 Expression *ea;
1550 ea = parseAssignExp();
1551 tiargs->push(ea);
1553 if (token.value != TOKcomma)
1554 break;
1555 nextToken();
1558 check(TOKrparen, "template argument list");
1559 return tiargs;
1562 Import *Parser::parseImport(Array *decldefs, int isstatic)
1563 { Import *s;
1564 Identifier *id;
1565 Identifier *aliasid = NULL;
1566 Array *a;
1567 Loc loc;
1569 //printf("Parser::parseImport()\n");
1573 nextToken();
1574 if (token.value != TOKidentifier)
1575 { error("Identifier expected following import");
1576 break;
1579 loc = this->loc;
1580 a = NULL;
1581 id = token.ident;
1582 nextToken();
1583 if (!aliasid && token.value == TOKassign)
1585 aliasid = id;
1586 goto L1;
1588 while (token.value == TOKdot)
1590 if (!a)
1591 a = new Array();
1592 a->push(id);
1593 nextToken();
1594 if (token.value != TOKidentifier)
1595 { error("Identifier expected following package");
1596 break;
1598 id = token.ident;
1599 nextToken();
1602 s = new Import(loc, a, token.ident, aliasid, isstatic);
1603 decldefs->push(s);
1605 /* Look for
1606 * : alias=name, alias=name;
1607 * syntax.
1609 if (token.value == TOKcolon)
1611 nextToken();
1612 while (1)
1613 { Identifier *name;
1614 Identifier *alias;
1616 optionalEndline();
1618 if (dltSyntax && token.value == TOKrcurly)
1619 break;
1620 if (token.value != TOKidentifier)
1621 { error("Identifier expected following :");
1622 break;
1624 alias = token.ident;
1625 nextToken();
1626 if (token.value == TOKassign)
1628 nextToken();
1629 if (token.value != TOKidentifier)
1630 { error("Identifier expected following %s=", alias->toChars());
1631 break;
1633 name = token.ident;
1634 nextToken();
1636 else
1637 { name = alias;
1638 alias = NULL;
1640 s->addAlias(name, alias);
1641 if (token.value != TOKcomma && token.value != TOKendline)
1642 break;
1643 nextToken();
1645 if (dltSyntax)
1647 check(TOKrcurly);
1648 return NULL;
1650 else
1651 break;
1654 aliasid = NULL;
1655 } while (token.value == TOKcomma);
1657 if (token.value == TOKsemicolon || token.value == TOKendline)
1658 nextToken();
1659 else
1661 error("%s expected", endToken());
1662 nextToken();
1665 return NULL;
1668 Type *Parser::parseBasicType()
1669 { Type *t;
1670 Identifier *id;
1671 TypeQualified *tid;
1672 TemplateInstance *tempinst;
1674 //printf("parseBasicType()\n");
1675 switch (token.value)
1677 CASE_BASIC_TYPES_X(t):
1678 nextToken();
1679 break;
1681 case TOKidentifier:
1682 id = token.ident;
1683 nextToken();
1684 if (token.value == TOKnot)
1686 nextToken();
1687 tempinst = new TemplateInstance(loc, id);
1688 tempinst->tiargs = parseTemplateArgumentList();
1689 tid = new TypeInstance(loc, tempinst);
1690 goto Lident2;
1692 Lident:
1693 tid = new TypeIdentifier(loc, id);
1694 Lident2:
1695 while (token.value == TOKdot)
1696 { nextToken();
1697 if (token.value != TOKidentifier)
1698 { error("identifier expected following '.' instead of '%s'", token.toChars());
1699 break;
1701 id = token.ident;
1702 nextToken();
1703 if (token.value == TOKnot)
1705 nextToken();
1706 tempinst = new TemplateInstance(loc, id);
1707 tempinst->tiargs = parseTemplateArgumentList();
1708 tid->addIdent((Identifier *)tempinst);
1710 else
1711 tid->addIdent(id);
1713 t = tid;
1714 break;
1716 case TOKdot:
1717 id = Id::empty;
1718 goto Lident;
1720 case TOKtypeof:
1721 { Expression *exp;
1723 nextToken();
1724 check(TOKlparen);
1725 exp = parseExpression();
1726 check(TOKrparen);
1727 tid = new TypeTypeof(loc, exp);
1728 goto Lident2;
1731 default:
1732 error("basic type expected, not %s", token.toChars());
1733 t = Type::tint32;
1734 break;
1736 return t;
1739 Type *Parser::parseBasicType2(Type *t)
1741 Type *ts;
1742 Type *ta;
1744 //printf("parseBasicType2()\n");
1745 while (1)
1747 switch (token.value)
1749 case TOKmul:
1750 t = new TypePointer(t);
1751 nextToken();
1752 continue;
1754 case TOKlbracket:
1755 #if LTORARRAYDECL
1756 // Handle []. Make sure things like
1757 // int[3][1] a;
1758 // is (array[1] of array[3] of int)
1759 nextToken();
1760 if (token.value == TOKrbracket)
1762 t = new TypeDArray(t); // []
1763 nextToken();
1765 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
1766 { // It's an associative array declaration
1767 Type *index;
1769 //printf("it's an associative array\n");
1770 index = parseBasicType();
1771 index = parseDeclarator(index, NULL); // [ type ]
1772 if (index->ty == Tmaybe && !dltSyntax)
1774 // This might be an expression. Remove the
1775 // maybe, so that D can try to resolve it as
1776 // a variable instead.
1777 index = index->next;
1779 t = new TypeAArray(t, index);
1780 check(TOKrbracket);
1782 else
1784 //printf("it's [expression]\n");
1785 inBrackets++;
1786 Expression *e = parseExpression(); // [ expression ]
1787 if (token.value == TOKslice)
1788 { Expression *e2;
1790 nextToken();
1791 e2 = parseExpression(); // [ exp .. exp ]
1792 t = new TypeSlice(t, e, e2);
1794 else
1795 t = new TypeSArray(t,e);
1796 inBrackets--;
1797 check(TOKrbracket);
1799 continue;
1800 #else
1801 // Handle []. Make sure things like
1802 // int[3][1] a;
1803 // is (array[3] of array[1] of int)
1804 ts = t;
1805 while (token.value == TOKlbracket)
1807 nextToken();
1808 if (token.value == TOKrbracket)
1810 ta = new TypeDArray(t); // []
1811 nextToken();
1813 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
1814 { // It's an associative array declaration
1815 Type *index;
1817 //printf("it's an associative array\n");
1818 index = parseBasicType();
1819 index = parseDeclarator(index, NULL); // [ type ]
1820 check(TOKrbracket);
1821 ta = new TypeAArray(t, index);
1823 else
1825 //printf("it's [expression]\n");
1826 Expression *e = parseExpression(); // [ expression ]
1827 ta = new TypeSArray(t,e);
1828 check(TOKrbracket);
1830 Type **pt;
1831 for (pt = &ts; *pt != t; pt = &(*pt)->next)
1833 *pt = ta;
1835 t = ts;
1836 continue;
1837 #endif
1839 case TOKdelegate:
1840 case TOKfunction:
1841 { // Handle delegate declaration:
1842 // t delegate(parameter list)
1843 // t function(parameter list)
1844 Arguments *arguments;
1845 int varargs;
1846 enum TOK save = token.value;
1848 nextToken();
1849 arguments = parseParameters(&varargs);
1850 t = new TypeFunction(arguments, t, varargs, linkage);
1851 if (save == TOKdelegate)
1852 t = new TypeDelegate(t);
1853 else
1854 t = new TypePointer(t); // pointer to function
1855 continue;
1858 case TOKquestion:
1859 if (dltSyntax)
1861 t = t->maybe();
1862 nextToken();
1863 continue;
1865 // fall-through to default
1867 default:
1868 ts = t;
1869 break;
1871 break;
1874 if (!dltSyntax)
1876 switch (ts->ty) {
1877 case Tpointer:
1878 case Tident:
1879 // TypeMaybe will unwrap itself later if this isn't a nullable type
1880 ts = ts->maybe();
1881 break;
1885 return ts;
1888 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
1889 { Type *ts;
1890 Type *ta;
1892 //printf("parseDeclarator(tpl = %p)\n", tpl);
1893 t = parseBasicType2(t);
1895 switch (token.value)
1898 case TOKidentifier:
1899 if (pident)
1900 *pident = token.ident;
1901 else
1902 error("unexpected identifer '%s' in declarator", token.ident->toChars());
1903 ts = t;
1904 nextToken();
1905 break;
1907 case TOKlparen:
1908 nextToken();
1909 ts = parseDeclarator(t, pident);
1910 check(TOKrparen);
1911 break;
1913 default:
1914 ts = t;
1915 break;
1918 while (1)
1920 switch (token.value)
1922 #if CARRAYDECL
1923 case TOKlbracket:
1924 { // This is the old C-style post [] syntax.
1925 nextToken();
1926 if (token.value == TOKrbracket)
1928 ta = new TypeDArray(t); // []
1929 nextToken();
1931 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
1932 { // It's an associative array declaration
1933 Type *index;
1935 //printf("it's an associative array\n");
1936 index = parseBasicType();
1937 index = parseDeclarator(index, NULL); // [ type ]
1938 check(TOKrbracket);
1939 ta = new TypeAArray(t, index);
1941 else
1943 //printf("it's [expression]\n");
1944 Expression *e = parseExpression(); // [ expression ]
1945 ta = new TypeSArray(t, e);
1946 check(TOKrbracket);
1948 Type **pt;
1949 for (pt = &ts; *pt != t; pt = &(*pt)->next)
1951 *pt = ta;
1952 continue;
1954 #endif
1955 case TOKlparen:
1956 { Arguments *arguments;
1957 int varargs;
1959 if (tpl)
1961 /* Look ahead to see if this is (...)(...),
1962 * i.e. a function template declaration
1964 if (peekPastParen(&token)->value == TOKlparen)
1965 { // It's a function template declaration
1966 //printf("function template declaration\n");
1968 // Gather template parameter list
1969 *tpl = parseTemplateParameterList();
1973 arguments = parseParameters(&varargs);
1974 Type *ta = new TypeFunction(arguments, t, varargs, linkage);
1975 Type **pt;
1976 for (pt = &ts; *pt != t; pt = &(*pt)->next)
1978 *pt = ta;
1979 break;
1982 break;
1985 return ts;
1988 /**********************************
1989 * Return array of Declaration *'s.
1992 Array *Parser::parseDeclarations()
1994 enum STC storage_class;
1995 enum STC stc;
1996 Type *ts;
1997 Type *t;
1998 Type *tfirst;
1999 Identifier *ident;
2000 Array *a;
2001 enum TOK tok;
2002 unsigned char *comment = token.blockComment;
2003 enum LINK link = linkage;
2005 //printf("parseDeclarations()\n");
2006 switch (token.value)
2008 case TOKtypedef:
2009 case TOKalias:
2010 tok = token.value;
2011 nextToken();
2012 break;
2014 default:
2015 tok = TOKreserved;
2016 break;
2019 storage_class = STCundefined;
2020 while (1)
2022 switch (token.value)
2024 case TOKconst: stc = STCconst; goto L1;
2025 case TOKstatic: stc = STCstatic; goto L1;
2026 case TOKfinal: stc = STCfinal; goto L1;
2027 case TOKauto: stc = STCauto; goto L1;
2028 case TOKscope: stc = STCscope; goto L1;
2029 case TOKoverride: stc = STCoverride; goto L1;
2030 case TOKabstract: stc = STCabstract; goto L1;
2031 case TOKsynchronized: stc = STCsynchronized; goto L1;
2032 case TOKdeprecated: stc = STCdeprecated; goto L1;
2034 if (storage_class & stc)
2035 error("redundant storage class '%s'", token.toChars());
2036 storage_class = (STC) (storage_class | stc);
2037 nextToken();
2038 continue;
2040 case TOKextern:
2041 if (peek(&token)->value != TOKlparen)
2042 { stc = STCextern;
2043 goto L1;
2046 link = parseLinkage();
2047 continue;
2049 default:
2050 break;
2052 break;
2055 a = new Array();
2057 /* Look for auto initializers:
2058 * storage_class identifier = initializer;
2060 while (storage_class &&
2061 token.value == TOKidentifier &&
2062 peek(&token)->value == TOKassign)
2064 ident = token.ident;
2065 nextToken();
2066 nextToken();
2067 Initializer *init = parseInitializer();
2068 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2069 v->storage_class = storage_class;
2070 a->push(v);
2071 if (token.value == TOKsemicolon || token.value == TOKendline)
2073 nextToken();
2074 addComment(v, comment);
2076 else if (token.value == TOKcomma)
2078 nextToken();
2079 if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
2081 error("Identifier expected following comma");
2083 else
2084 continue;
2086 else
2087 error("%s expected following auto declaration, not '%s'", endToken(), token.toChars());
2088 return a;
2091 if (token.value == TOKclass)
2092 { AggregateDeclaration *s;
2094 s = (AggregateDeclaration *)parseAggregate();
2095 s->storage_class |= storage_class;
2096 a->push(s);
2097 addComment(s, comment);
2098 return a;
2101 ts = parseBasicType();
2102 ts = parseBasicType2(ts);
2103 tfirst = NULL;
2105 while (1)
2107 Loc loc = this->loc;
2108 TemplateParameters *tpl = NULL;
2110 ident = NULL;
2111 t = parseDeclarator(ts, &ident, &tpl);
2112 assert(t);
2113 if (!tfirst)
2114 tfirst = t;
2115 else if (t != tfirst)
2116 error("multiple declarations must have the same type, not %s and %s",
2117 tfirst->toChars(), t->toChars());
2118 if (!ident)
2119 error("no identifier for declarator %s", t->toChars());
2121 if (tok == TOKtypedef || tok == TOKalias)
2122 { Declaration *v;
2123 Initializer *init;
2125 if (!dltSyntax)
2127 /* Unwrap maybe qualifiers from aliases.
2128 * Otherwise, it thinks we're aliasing types when we're not.
2130 if (t->ty == Tmaybe) {
2131 t = t->next;
2135 init = NULL;
2136 if (token.value == TOKassign)
2138 nextToken();
2139 init = parseInitializer();
2141 if (tok == TOKtypedef)
2142 v = new TypedefDeclaration(loc, ident, t, init);
2143 else
2144 { if (init)
2145 error("alias cannot have initializer");
2146 v = new AliasDeclaration(loc, ident, t);
2148 v->storage_class = storage_class;
2149 if (link == linkage)
2150 a->push(v);
2151 else
2153 Array *ax = new Array();
2154 ax->push(v);
2155 Dsymbol *s = new LinkDeclaration(link, ax);
2156 a->push(s);
2158 switch (token.value)
2159 { case TOKsemicolon:
2160 case TOKendline:
2161 nextToken();
2162 addComment(v, comment);
2163 break;
2165 case TOKcomma:
2166 nextToken();
2167 addComment(v, comment);
2168 continue;
2170 default:
2171 error("%s expected to close %s declaration", endToken(), Token::toChars(tok));
2172 break;
2175 else if (t->ty == Tfunction)
2176 { FuncDeclaration *f;
2177 Dsymbol *s;
2179 f = new FuncDeclaration(loc, 0, ident, storage_class, t);
2180 addComment(f, comment);
2181 parseContracts(f);
2182 addComment(f, NULL);
2183 if (link == linkage)
2185 s = f;
2187 else
2189 Array *ax = new Array();
2190 ax->push(f);
2191 s = new LinkDeclaration(link, ax);
2193 if (tpl) // it's a function template
2194 { Array *decldefs;
2195 TemplateDeclaration *tempdecl;
2197 // Wrap a template around the aggregate declaration
2198 decldefs = new Array();
2199 decldefs->push(s);
2200 tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs, dltSyntax);
2201 s = tempdecl;
2203 addComment(s, comment);
2204 a->push(s);
2206 else
2207 { VarDeclaration *v;
2208 Initializer *init;
2210 init = NULL;
2211 if (token.value == TOKassign)
2213 nextToken();
2214 init = parseInitializer();
2216 v = new VarDeclaration(loc, t, ident, init);
2217 v->storage_class = storage_class;
2218 if (link == linkage)
2219 a->push(v);
2220 else
2222 Array *ax = new Array();
2223 ax->push(v);
2224 Dsymbol *s = new LinkDeclaration(link, ax);
2225 a->push(s);
2227 switch (token.value)
2228 { case TOKsemicolon:
2229 case TOKendline:
2230 nextToken();
2231 addComment(v, comment);
2232 break;
2234 case TOKcomma:
2235 nextToken();
2236 addComment(v, comment);
2237 continue;
2239 default:
2240 error("%s expected, not '%s'", endToken(), token.toChars());
2241 break;
2244 break;
2246 return a;
2249 /*****************************************
2250 * Parse contracts following function declaration.
2253 void Parser::parseContracts(FuncDeclaration *f)
2255 Type *tb;
2256 enum LINK linksave = linkage;
2258 // The following is irrelevant, as it is overridden by sc->linkage in
2259 // TypeFunction::semantic
2260 linkage = LINKd; // nested functions have D linkage
2262 switch (token.value)
2264 case TOKlcurly:
2265 case TOKcolon:
2266 if (token.value != startBlockTok)
2267 error("use %s to start a new block", Token::toChars(startBlockTok));
2268 if (f->frequire || f->fensure)
2269 error("missing body { ... } after in or out");
2270 f->fbody = parseStatement(PSsemi | PScolon);
2271 f->endloc = endloc;
2272 break;
2274 case TOKbody:
2275 nextToken();
2276 f->fbody = parseStatement(PScurly);
2277 f->endloc = endloc;
2278 break;
2280 case TOKsemicolon:
2281 if (dltSyntax)
2282 error("unexpected semi-colon after function declaration");
2283 // fall-through
2284 case TOKendline:
2285 if (f->frequire || f->fensure)
2286 error("missing body { ... } after in or out");
2287 nextToken();
2288 break;
2290 #if 0 // Do we want this for function declarations, so we can do:
2291 // int x, y, foo(), z;
2292 case TOKcomma:
2293 nextToken();
2294 continue;
2295 #endif
2297 #if 0 // Dumped feature
2298 case TOKthrow:
2299 if (!f->fthrows)
2300 f->fthrows = new Array();
2301 nextToken();
2302 check(TOKlparen);
2303 while (1)
2305 tb = parseBasicType();
2306 f->fthrows->push(tb);
2307 if (token.value == TOKcomma)
2308 { nextToken();
2309 continue;
2311 break;
2313 check(TOKrparen);
2314 goto L1;
2315 #endif
2317 case TOKin:
2318 nextToken();
2319 if (f->frequire)
2320 error("redundant 'in' statement");
2321 f->frequire = parseStatement(PScurly | PSscope);
2322 goto L1;
2324 case TOKout:
2325 // parse: out (identifier) { statement }
2326 nextToken();
2327 if (token.value != startBlockTok)
2329 check(TOKlparen);
2330 if (token.value != TOKidentifier)
2331 error("(identifier) following 'out' expected, not %s", token.toChars());
2332 f->outId = token.ident;
2333 nextToken();
2334 check(TOKrparen);
2336 if (f->fensure)
2337 error("redundant 'out' statement");
2338 f->fensure = parseStatement(PScurly | PSscope);
2339 goto L1;
2341 default:
2342 error("%s expected following function declaration", endToken());
2343 break;
2345 linkage = linksave;
2348 /*****************************************
2351 Initializer *Parser::parseInitializer()
2353 StructInitializer *is;
2354 ArrayInitializer *ia;
2355 ExpInitializer *ie;
2356 Expression *e;
2357 Identifier *id;
2358 Initializer *value;
2359 int comma;
2360 Loc loc = this->loc;
2361 Token *t;
2362 int braces;
2364 switch (token.value)
2366 case TOKlcurly:
2367 /* Scan ahead to see if it is a struct initializer or
2368 * a function literal.
2369 * If it contains a ';', it is a function literal.
2370 * Treat { } as a struct initializer.
2372 braces = 1;
2373 for (t = peek(&token); 1; t = peek(t))
2375 switch (t->value)
2377 case TOKsemicolon:
2378 case TOKreturn:
2379 goto Lexpression;
2381 case TOKlcurly:
2382 braces++;
2383 continue;
2385 case TOKrcurly:
2386 if (--braces == 0)
2387 break;
2388 continue;
2390 case TOKeof:
2391 break;
2393 default:
2394 continue;
2396 break;
2399 is = new StructInitializer(loc);
2400 nextToken();
2401 comma = 0;
2402 while (1)
2404 switch (token.value)
2406 case TOKidentifier:
2407 if (comma == 1)
2408 error("comma expected separating field initializers");
2409 t = peek(&token);
2410 if (t->value == TOKcolon)
2412 id = token.ident;
2413 nextToken();
2414 nextToken(); // skip over ':'
2416 else
2417 { id = NULL;
2419 value = parseInitializer();
2420 is->addInit(id, value);
2421 comma = 1;
2422 continue;
2424 case TOKcomma:
2425 nextToken();
2426 comma = 2;
2427 continue;
2429 case TOKrcurly: // allow trailing comma's
2430 nextToken();
2431 break;
2433 case TOKeof:
2434 error("found EOF instead of initializer");
2435 break;
2437 default:
2438 value = parseInitializer();
2439 is->addInit(NULL, value);
2440 comma = 1;
2441 continue;
2442 //error("found '%s' instead of field initializer", token.toChars());
2443 //break;
2445 break;
2447 return is;
2449 case TOKlbracket:
2450 ia = new ArrayInitializer(loc);
2451 nextToken();
2452 comma = 0;
2453 while (1)
2455 switch (token.value)
2457 default:
2458 if (comma == 1)
2459 { error("comma expected separating array initializers, not %s", token.toChars());
2460 nextToken();
2461 break;
2463 e = parseAssignExp();
2464 if (!e)
2465 break;
2466 if (token.value == TOKcolon)
2468 nextToken();
2469 value = parseInitializer();
2471 else
2472 { value = new ExpInitializer(e->loc, e);
2473 e = NULL;
2475 ia->addInit(e, value);
2476 comma = 1;
2477 continue;
2479 case TOKlcurly:
2480 case TOKlbracket:
2481 if (comma == 1)
2482 error("comma expected separating array initializers, not %s", token.toChars());
2483 value = parseInitializer();
2484 ia->addInit(NULL, value);
2485 comma = 1;
2486 continue;
2488 case TOKcomma:
2489 nextToken();
2490 comma = 2;
2491 continue;
2493 case TOKrbracket: // allow trailing comma's
2494 nextToken();
2495 break;
2497 case TOKeof:
2498 error("found '%s' instead of array initializer", token.toChars());
2499 break;
2501 break;
2503 return ia;
2505 case TOKvoid:
2506 t = peek(&token);
2507 if (t->value == TOKsemicolon || t->value == TOKcomma || t->value == TOKendline)
2509 nextToken();
2510 return new VoidInitializer(loc);
2512 goto Lexpression;
2514 default:
2515 Lexpression:
2516 e = parseAssignExp();
2517 ie = new ExpInitializer(loc, e);
2518 return ie;
2522 Statement *Parser::logStatement(int level) {
2523 nextToken();
2524 if (token.value != TOKlparen)
2525 error(loc, "found '%s' when expecting '('", token.toChars());
2526 return new LogStatement(loc, level, parseArguments());
2529 /*****************************************
2530 * Input:
2531 * flags PSxxxx
2534 Statement *DltParser::parseStatement(int flags)
2536 optionalEndline();
2537 if (flags & (PScolon | PSscope))
2538 flags |= PScurly;
2539 return Parser::parseStatement(flags);
2542 Statement *Parser::parseStatement(int flags)
2543 { Statement *s;
2544 Token *t;
2545 Condition *condition;
2546 Statement *ifbody;
2547 Statement *elsebody;
2548 Loc loc = this->loc;
2550 //printf("parseStatement()\n");
2552 if ((flags & PScurly) && token.value != startBlockTok)
2553 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
2555 int tok = token.value;
2557 switch (token.value)
2559 case TOKidentifier:
2560 if (!dltSyntax)
2562 // Need to look ahead to see if it is a declaration, label, or expression
2563 t = peek(&token);
2564 if (t->value == TOKcolon)
2565 { // It's a label
2566 Identifier *ident;
2568 ident = token.ident;
2569 nextToken();
2570 nextToken();
2571 s = parseStatement(PSsemi);
2572 s = new LabelStatement(loc, ident, s);
2573 break;
2576 // fallthrough to TOKdot
2577 case TOKdot:
2578 case TOKtypeof:
2579 if (isDeclaration(&token, 2, TOKreserved, NULL))
2580 goto Ldeclaration;
2581 else
2582 goto Lexp;
2583 break;
2585 case TOKassert:
2586 case TOKthis:
2587 case TOKsuper:
2588 case TOKint32v:
2589 case TOKuns32v:
2590 case TOKint64v:
2591 case TOKuns64v:
2592 case TOKfloat32v:
2593 case TOKfloat64v:
2594 case TOKfloat80v:
2595 case TOKimaginary32v:
2596 case TOKimaginary64v:
2597 case TOKimaginary80v:
2598 case TOKcharv:
2599 case TOKwcharv:
2600 case TOKdcharv:
2601 case TOKnull:
2602 case TOKtrue:
2603 case TOKfalse:
2604 case TOKstring:
2605 case TOKlparen:
2606 case TOKcast:
2607 case TOKmul:
2608 case TOKmin:
2609 case TOKadd:
2610 case TOKplusplus:
2611 case TOKminusminus:
2612 case TOKnew:
2613 case TOKdelete:
2614 case TOKdelegate:
2615 case TOKfunction:
2616 case TOKtypeid:
2617 case TOKis:
2618 case TOKlbracket:
2619 Lexp:
2620 { Expression *exp;
2622 exp = parseExpression();
2623 if (!dltSyntax)
2624 check(TOKsemicolon, "statement");
2625 s = new ExpStatement(loc, exp);
2626 break;
2629 case TOKstatic:
2630 { // Look ahead to see if it's static assert() or static if()
2631 Token *t;
2633 t = peek(&token);
2634 if (t->value == TOKassert)
2636 nextToken();
2637 s = new StaticAssertStatement(parseStaticAssert());
2638 break;
2640 if (t->value == TOKif)
2642 nextToken();
2643 condition = parseStaticIfCondition();
2644 goto Lcondition;
2646 goto Ldeclaration;
2649 CASE_BASIC_TYPES:
2650 case TOKtypedef:
2651 case TOKalias:
2652 case TOKconst:
2653 case TOKauto:
2654 case TOKextern:
2655 case TOKfinal:
2656 case TOKinvariant:
2657 // case TOKtypeof:
2658 Ldeclaration:
2659 { Array *a;
2661 a = parseDeclarations();
2662 if (a->dim > 1)
2664 Statements *as = new Statements();
2665 as->reserve(a->dim);
2666 for (int i = 0; i < a->dim; i++)
2668 Dsymbol *d = (Dsymbol *)a->data[i];
2669 s = new DeclarationStatement(loc, d);
2670 as->push(s);
2672 s = new CompoundStatement(loc, as);
2674 else if (a->dim == 1)
2676 Dsymbol *d = (Dsymbol *)a->data[0];
2677 s = new DeclarationStatement(loc, d);
2679 else
2680 assert(0);
2681 if (flags & PSscope)
2682 s = new ScopeStatement(loc, s);
2683 break;
2686 case TOKstruct:
2687 case TOKunion:
2688 case TOKclass:
2689 case TOKinterface:
2690 { Dsymbol *d;
2692 d = parseAggregate();
2693 s = new DeclarationStatement(loc, d);
2694 break;
2697 case TOKenum:
2698 { Dsymbol *d;
2700 d = parseEnum();
2701 s = new DeclarationStatement(loc, d);
2702 break;
2705 case TOKmixin:
2706 { t = peek(&token);
2707 if (t->value == TOKlparen)
2708 { // mixin(string)
2709 nextToken();
2710 check(TOKlparen, "mixin");
2711 Expression *e = parseAssignExp();
2712 check(TOKrparen);
2713 check(TOKsemicolon);
2714 s = new CompileStatement(loc, e);
2715 break;
2717 Dsymbol *d = parseMixin();
2718 s = new DeclarationStatement(loc, d);
2719 break;
2722 case TOKcolon:
2723 case TOKlcurly:
2724 { Statements *statements;
2726 if (token.value != startBlockTok)
2727 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
2729 nextToken();
2730 optionalEndline();
2731 statements = new Statements();
2732 while (token.value != TOKrcurly)
2734 statements->push(parseStatement(PSsemi | PScurlyscope));
2735 optionalEndline();
2737 endloc = this->loc;
2738 s = new CompoundStatement(loc, statements);
2739 if (flags & (PSscope | PScurlyscope))
2740 s = new ScopeStatement(loc, s);
2741 nextToken();
2742 break;
2745 case TOKlog_error: s = logStatement(LogStatement::Error); break;
2746 case TOKlog_warning: s = logStatement(LogStatement::Warn); break;
2747 case TOKlog_info: s = logStatement(LogStatement::Info); break;
2748 case TOKlog_trace: s = logStatement(LogStatement::Trace); break;
2750 case TOKwhile:
2751 { Expression *condition;
2752 Statement *body;
2754 nextToken();
2755 checkLParen();
2756 condition = parseExpression();
2757 checkRParen();
2758 body = parseStatement(PSscope);
2759 s = new WhileStatement(loc, condition, body);
2760 break;
2763 case TOKsemicolon:
2764 if (!(flags & PSsemi))
2765 error("use '{ }' for an empty statement, not a ';'");
2766 nextToken();
2767 s = new ExpStatement(loc, NULL);
2768 break;
2770 case TOKdo:
2771 { Statement *body;
2772 Expression *condition;
2774 nextToken();
2775 body = parseStatement(PSscope);
2776 check(TOKwhile);
2777 checkLParen();
2778 condition = parseExpression();
2779 checkRParen();
2780 s = new DoStatement(loc, body, condition);
2781 break;
2784 case TOKfor:
2786 Statement *init;
2787 Expression *condition;
2788 Expression *increment;
2789 Statement *body;
2791 nextToken();
2793 if (token.value == TOKlparen) {
2794 /* for (init; cond; incr): ... */
2795 nextToken();
2796 if (token.value == TOKsemicolon)
2797 { init = NULL;
2798 nextToken();
2800 else
2801 { init = parseStatement(0);
2803 if (token.value == TOKsemicolon)
2805 condition = NULL;
2806 nextToken();
2808 else
2810 condition = parseExpression();
2811 check(TOKsemicolon, "for condition");
2813 if (token.value == TOKrparen)
2814 { increment = NULL;
2815 nextToken();
2817 else
2818 { increment = parseExpression();
2819 check(TOKrparen);
2821 body = parseStatement(PSscope);
2822 s = new ForStatement(loc, init, condition, increment, body);
2823 if (init)
2824 s = new ScopeStatement(loc, s);
2825 } else if (dltSyntax)
2826 goto caseForeach;
2827 break;
2830 caseForeach:
2831 case TOKforeach:
2832 case TOKforeach_reverse:
2834 /* for var in seq: ... */
2835 /* for index, var in seq: ... */
2836 Arguments *arguments;
2838 Statement *d;
2839 Statement *body;
2840 Expression *aggr;
2841 enum TOK op = (TOK) tok;
2843 if (tok != TOKfor)
2844 nextToken();
2846 checkLParen();
2848 TOK inTok = dltSyntax ? TOKin : TOKsemicolon;
2850 arguments = new Arguments();
2852 while (1)
2854 Type *tb;
2855 Identifier *ai = NULL;
2856 Type *at;
2857 unsigned storageClass;
2858 Argument *a;
2860 storageClass = STCin;
2861 if (token.value == TOKinout || token.value == TOKref)
2862 { storageClass = STCref;
2863 nextToken();
2865 if (token.value == TOKidentifier)
2867 Token *t = peek(&token);
2868 if (t->value == TOKcomma || t->value == inTok)
2869 { ai = token.ident;
2870 at = NULL; // infer argument type
2871 nextToken();
2872 goto Larg;
2875 tb = parseBasicType();
2876 at = parseDeclarator(tb, &ai);
2877 if (!ai)
2878 error("no identifier for declarator %s", at->toChars());
2879 Larg:
2880 a = new Argument(storageClass, at, ai, NULL);
2881 arguments->push(a);
2882 if (token.value == TOKcomma)
2883 { nextToken();
2884 continue;
2886 break;
2889 check(inTok);
2891 aggr = parseExpression();
2892 checkRParen();
2894 if (dltSyntax) {
2895 if (token.value == TOKreversed) {
2896 op = TOKforeach_reverse;
2897 nextToken();
2898 } else {
2899 op = TOKforeach;
2903 body = parseStatement(PScolon);
2904 s = new ForeachStatement(loc, op, arguments, aggr, body);
2905 break;
2908 case TOKif:
2909 { Argument *arg = NULL;
2910 Expression *condition;
2911 Statement *ifbody;
2912 Statement *elsebody;
2914 nextToken();
2915 checkLParen();
2917 if (token.value == TOKauto)
2919 nextToken();
2920 if (token.value == TOKidentifier)
2922 Token *t = peek(&token);
2923 if (t->value == TOKassign)
2925 arg = new Argument(STCin, NULL, token.ident, NULL);
2926 nextToken();
2927 nextToken();
2929 else
2930 { error("= expected following auto identifier");
2931 goto Lerror;
2934 else
2935 { error("identifier expected following auto");
2936 goto Lerror;
2939 else if (isDeclaration(&token, 2, TOKassign, NULL))
2941 Type *tb;
2942 Type *at;
2943 Identifier *ai;
2945 tb = parseBasicType();
2946 at = parseDeclarator(tb, &ai);
2947 check(TOKassign);
2948 arg = new Argument(STCin, at, ai, NULL);
2951 // Check for " ident;"
2952 else if (token.value == TOKidentifier && !dltSyntax)
2954 Token *t = peek(&token);
2955 if (t->value == TOKcomma || t->value == TOKsemicolon)
2957 arg = new Argument(STCin, NULL, token.ident, NULL);
2958 nextToken();
2959 nextToken();
2960 if (1 || !global.params.useDeprecated)
2961 error("if (v; e) is deprecated, use if (auto v = e)");
2965 condition = parseExpression();
2966 checkRParen();
2967 ifbody = parseStatement(PSscope);
2968 if (token.value == TOKelse)
2970 nextToken();
2971 if (dltSyntax)
2973 if (token.value == TOKcolon) {
2974 elsebody = parseStatement(PSscope);
2975 } else if (token.value == TOKif) {
2976 elsebody = parseStatement(0);
2977 } else {
2978 error("Expected 'else:' or 'else if', not 'else %s'", token.toChars());
2979 elsebody = NULL;
2982 else
2983 elsebody = parseStatement(PSscope);
2985 else
2986 elsebody = NULL;
2987 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
2988 break;
2991 case TOKscope:
2992 if (peek(&token)->value != TOKlparen)
2993 goto Ldeclaration; // scope used as storage class
2994 nextToken();
2995 check(TOKlparen);
2996 if (token.value != TOKidentifier)
2997 { error("scope identifier expected");
2998 goto Lerror;
3000 else
3001 { TOK t = TOKon_scope_exit;
3002 Identifier *id = token.ident;
3004 if (id == Id::exit)
3005 t = TOKon_scope_exit;
3006 else if (id == Id::failure)
3007 t = TOKon_scope_failure;
3008 else if (id == Id::success)
3009 t = TOKon_scope_success;
3010 else
3011 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3012 nextToken();
3013 check(TOKrparen);
3014 Statement *st = parseStatement(PScolon | PScurlyscope);
3015 s = new OnScopeStatement(loc, t, st);
3016 break;
3019 case TOKdebug:
3020 nextToken();
3021 condition = parseDebugCondition();
3022 goto Lcondition;
3024 case TOKversion:
3025 nextToken();
3026 condition = parseVersionCondition();
3027 goto Lcondition;
3029 Lcondition:
3030 if (dltSyntax && token.value != TOKcolon)
3031 error("expected colon after condition, not '%s'", token.toChars());
3032 ifbody = parseStatement(PScolon /*PSsemi*/);
3033 elsebody = NULL;
3034 if (token.value == TOKelse)
3036 nextToken();
3037 elsebody = parseStatement(PScolon /*PSsemi*/);
3039 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3040 break;
3042 case TOKpragma:
3043 { Identifier *ident;
3044 Expressions *args = NULL;
3045 Statement *body;
3047 nextToken();
3048 check(TOKlparen);
3049 if (token.value != TOKidentifier)
3050 { error("pragma(identifier expected");
3051 goto Lerror;
3053 ident = token.ident;
3054 nextToken();
3055 if (token.value == TOKcomma)
3056 args = parseArguments(); // pragma(identifier, args...);
3057 else
3058 check(TOKrparen); // pragma(identifier);
3059 if (token.value == TOKsemicolon)
3060 { nextToken();
3061 body = NULL;
3063 else
3064 body = parseStatement(PSsemi | PScolon);
3065 s = new PragmaStatement(loc, ident, args, body);
3066 break;
3069 case TOKswitch:
3070 { Expression *condition;
3071 Statement *body;
3073 nextToken();
3074 checkLParen();
3075 condition = parseExpression();
3076 checkRParen();
3077 body = parseStatement(PSscope | PScolon);
3078 s = new SwitchStatement(loc, condition, body);
3079 break;
3082 case TOKcase:
3083 { Expression *exp;
3084 Statements *statements;
3085 Array cases; // array of Expression's
3087 while (1)
3089 nextToken();
3090 exp = parseAssignExp();
3091 cases.push(exp);
3092 if (token.value != TOKcomma)
3093 break;
3096 if (dltSyntax)
3098 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3100 else
3102 check(TOKcolon);
3104 statements = new Statements();
3105 while (token.value != TOKcase &&
3106 token.value != TOKdefault &&
3107 token.value != TOKrcurly)
3109 statements->push(parseStatement(PSsemi | PScurlyscope));
3111 s = new CompoundStatement(loc, statements);
3114 s = new ScopeStatement(loc, s);
3116 // Keep cases in order by building the case statements backwards
3117 for (int i = cases.dim; i; i--)
3119 exp = (Expression *)cases.data[i - 1];
3120 s = new CaseStatement(loc, exp, s);
3122 break;
3125 case TOKdefault:
3127 Statements *statements;
3129 nextToken();
3131 if (dltSyntax)
3133 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3135 else
3137 check(TOKcolon);
3139 statements = new Statements();
3140 while (token.value != TOKcase &&
3141 token.value != TOKdefault &&
3142 token.value != TOKrcurly)
3144 statements->push(parseStatement(PSsemi | PScurlyscope));
3146 s = new CompoundStatement(loc, statements);
3149 s = new ScopeStatement(loc, s);
3150 s = new DefaultStatement(loc, s);
3151 break;
3154 case TOKreturn:
3155 { Expression *exp;
3157 nextToken();
3158 if (token.value == TOKsemicolon || token.value == TOKendline)
3159 exp = NULL;
3160 else
3161 exp = parseExpression();
3163 if (!dltSyntax)
3164 check(TOKsemicolon, "return statement");
3165 else if (token.value != TOKendline) {
3166 error("Expected end-of-line after return statement, but found '%s'", token.toChars());
3169 s = new ReturnStatement(loc, exp);
3170 break;
3173 case TOKbreak:
3174 { Identifier *ident;
3176 nextToken();
3177 if (token.value == TOKidentifier)
3178 { ident = token.ident;
3179 nextToken();
3181 else
3182 ident = NULL;
3183 if (token.value != TOKsemicolon && token.value != TOKendline) {
3184 error("expected %s after break, not '%s'", endToken(), token.toChars());
3186 if (!dltSyntax)
3187 nextToken();
3188 s = new BreakStatement(loc, ident);
3189 break;
3192 case TOKcontinue:
3193 { Identifier *ident;
3195 nextToken();
3196 if (token.value == TOKidentifier)
3197 { ident = token.ident;
3198 nextToken();
3200 else
3201 ident = NULL;
3202 check(TOKsemicolon, "continue statement");
3203 s = new ContinueStatement(loc, ident);
3204 break;
3207 case TOKgoto:
3208 { Identifier *ident;
3210 nextToken();
3211 if (token.value == TOKdefault)
3213 nextToken();
3214 s = new GotoDefaultStatement(loc);
3216 else if (token.value == TOKcase)
3218 Expression *exp = NULL;
3220 nextToken();
3221 if (token.value != TOKsemicolon)
3222 exp = parseExpression();
3223 s = new GotoCaseStatement(loc, exp);
3225 else
3227 if (token.value != TOKidentifier)
3228 { error("Identifier expected following goto");
3229 ident = NULL;
3231 else
3232 { ident = token.ident;
3233 nextToken();
3235 s = new GotoStatement(loc, ident);
3237 if (token.value != TOKsemicolon && token.value != TOKendline) {
3238 error("expected %s after goto statement, not '%s'", endToken(), token.toChars());
3240 break;
3243 case TOKsynchronized:
3244 { Expression *exp;
3245 Statement *body;
3247 nextToken();
3248 if (token.value == TOKlparen)
3250 nextToken();
3251 exp = parseExpression();
3252 check(TOKrparen);
3254 else
3255 exp = NULL;
3256 body = parseStatement(PSscope);
3257 s = new SynchronizedStatement(loc, exp, body);
3258 break;
3261 case TOKwith:
3262 { Expression *exp;
3263 Statement *body;
3265 nextToken();
3266 check(TOKlparen);
3267 exp = parseExpression();
3268 check(TOKrparen);
3269 body = parseStatement(PSscope);
3270 s = new WithStatement(loc, exp, body);
3271 break;
3274 case TOKtry:
3275 { Statement *body;
3276 Array *catches = NULL;
3277 Statement *finalbody = NULL;
3279 nextToken();
3280 body = parseStatement(PSscope);
3281 while (token.value == TOKcatch)
3283 Statement *handler;
3284 Catch *c;
3285 Type *t;
3286 Identifier *id;
3287 Loc loc = this->loc;
3289 nextToken();
3290 if (token.value == startBlockTok)
3292 t = NULL;
3293 id = NULL;
3295 else
3297 check(TOKlparen);
3298 t = parseBasicType();
3299 id = NULL;
3300 t = parseDeclarator(t, &id);
3301 check(TOKrparen);
3303 handler = parseStatement(PScolon);
3304 c = new Catch(loc, t, id, handler);
3305 if (!catches)
3306 catches = new Array();
3307 catches->push(c);
3310 if (token.value == TOKfinally)
3311 { nextToken();
3312 finalbody = parseStatement(PScolon);
3315 s = body;
3316 if (!catches && !finalbody)
3317 error("catch or finally expected following try");
3318 else
3319 { if (catches)
3320 s = new TryCatchStatement(loc, body, catches);
3321 if (finalbody)
3322 s = new TryFinallyStatement(loc, s, finalbody);
3324 break;
3327 case TOKthrow:
3328 { Expression *exp;
3330 nextToken();
3331 exp = parseExpression();
3332 if (token.value != TOKsemicolon && token.value != TOKendline) {
3333 error("%s expected after throw statement, not '%s'", endToken(), token.toChars());
3335 if (!dltSyntax)
3336 nextToken();
3337 s = new ThrowStatement(loc, exp);
3338 break;
3341 case TOKvolatile:
3342 nextToken();
3343 s = parseStatement(PSsemi | PScurlyscope);
3344 s = new VolatileStatement(loc, s);
3345 break;
3347 case TOKasm:
3348 { Statements *statements;
3349 Identifier *label;
3350 Loc labelloc;
3351 Token *toklist;
3352 Token **ptoklist;
3354 // Parse the asm block into a sequence of AsmStatements,
3355 // each AsmStatement is one instruction.
3356 // Separate out labels.
3357 // Defer parsing of AsmStatements until semantic processing.
3359 nextToken();
3360 #if GDC_EXTENDED_ASM_SYNTAX
3361 if (token.value == TOKlparen)
3363 nextToken();
3364 s = parseExtAsm(1);
3365 break;
3367 #endif
3368 check(startBlockTok);
3369 toklist = NULL;
3370 ptoklist = &toklist;
3371 label = NULL;
3372 statements = new Statements();
3373 while (1)
3375 switch (token.value)
3377 case TOKidentifier:
3378 if (!toklist)
3380 // Look ahead to see if it is a label
3381 t = peek(&token);
3382 if (t->value == TOKcolon)
3383 { // It's a label
3384 label = token.ident;
3385 labelloc = this->loc;
3386 nextToken();
3387 nextToken();
3388 continue;
3391 goto Ldefault;
3393 case TOKrcurly:
3394 if (toklist || label)
3396 error("asm statements must end in ';'");
3398 break;
3400 case TOKendline:
3401 case TOKsemicolon:
3402 s = NULL;
3403 if (toklist || label)
3404 { // Create AsmStatement from list of tokens we've saved
3405 s = new AsmStatement(this->loc, toklist);
3406 toklist = NULL;
3407 ptoklist = &toklist;
3408 if (label)
3409 { s = new LabelStatement(labelloc, label, s);
3410 label = NULL;
3412 statements->push(s);
3414 nextToken();
3415 continue;
3417 case TOKeof:
3418 /* { */
3419 error("matching '}' expected, not end of file");
3420 break;
3422 case TOKlparen:
3423 case TOKstring:
3424 // If the first token is a string or '(', parse as extended asm.
3425 if (! toklist)
3427 s = parseExtAsm(0);
3428 statements->push(s);
3429 continue;
3431 // ...else, drop through.
3433 default:
3434 Ldefault:
3435 *ptoklist = new Token();
3436 memcpy(*ptoklist, &token, sizeof(Token));
3437 ptoklist = &(*ptoklist)->next;
3438 *ptoklist = NULL;
3440 nextToken();
3441 continue;
3443 break;
3445 s = new CompoundStatement(loc, statements);
3446 nextToken();
3447 break;
3450 default:
3451 error("found '%s' instead of statement", token.toChars());
3452 goto Lerror;
3454 Lerror:
3455 while (token.value != TOKrcurly &&
3456 token.value != TOKsemicolon &&
3457 token.value != TOKeof)
3458 nextToken();
3459 if (token.value == TOKsemicolon)
3460 nextToken();
3461 s = NULL;
3462 break;
3465 return s;
3468 Statement *Parser::parseExtAsm(int expect_rparen)
3470 Expression * insnTemplate;
3471 Expressions * args = NULL;
3472 Array * argNames = NULL;
3473 Expressions * argConstraints = NULL;
3474 int nOutputArgs = 0;
3475 Expressions * clobbers = NULL;
3476 bool isInputPhase = false; // Output operands first, then input.
3478 insnTemplate = parseExpression();
3479 if (token.value == TOKrparen || token.value == TOKsemicolon)
3480 goto Ldone;
3481 check(TOKcolon);
3482 while (1) {
3483 Expression * arg = NULL;
3484 Identifier * name = NULL;
3485 Expression * constraint = NULL;
3487 switch (token.value)
3489 case TOKsemicolon:
3490 case TOKrparen:
3491 goto Ldone;
3493 case TOKcolon:
3494 nextToken();
3495 goto LnextPhase;
3497 case TOKeof:
3498 error("unterminated statement");
3500 case TOKlbracket:
3501 nextToken();
3502 if (token.value == TOKidentifier)
3504 name = token.ident;
3505 nextToken();
3507 else
3508 error("expected identifier after '['");
3509 check(TOKrbracket);
3510 // drop through
3511 default:
3512 constraint = parsePrimaryExp();
3513 if (constraint->op != TOKstring)
3514 error("expected constant string constraint for operand");
3515 arg = parseAssignExp();
3516 if (! args)
3518 args = new Expressions;
3519 argConstraints = new Expressions;
3520 argNames = new Array;
3522 args->push(arg);
3523 argNames->push(name);
3524 argConstraints->push(constraint);
3525 if (! isInputPhase)
3526 nOutputArgs++;
3528 if (token.value == TOKcomma)
3529 nextToken();
3530 break;
3532 continue;
3533 LnextPhase:
3534 if (! isInputPhase)
3535 isInputPhase = true;
3536 else
3537 break;
3540 while (1)
3542 Expression * clobber;
3544 switch (token.value)
3546 case TOKsemicolon:
3547 case TOKrparen:
3548 goto Ldone;
3550 case TOKeof:
3551 error("unterminated statement");
3553 default:
3554 clobber = parseAssignExp();
3555 if (clobber->op != TOKstring)
3556 error("expected constant string constraint for clobber name");
3557 if (! clobbers)
3558 clobbers = new Expressions;
3559 clobbers->push(clobber);
3561 if (token.value == TOKcomma)
3562 nextToken();
3563 break;
3566 Ldone:
3567 if (expect_rparen)
3568 check(TOKrparen);
3569 else
3570 check(TOKsemicolon);
3572 return new ExtAsmStatement(loc, insnTemplate, args, argNames,
3573 argConstraints, nOutputArgs, clobbers);
3576 void Parser::optionalEndline() {
3577 while (token.value == TOKendline) {
3578 nextToken();
3582 void Parser::check(enum TOK value)
3584 check(loc, value);
3587 void Parser::check(Loc loc, enum TOK value)
3589 if (token.value != value)
3590 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
3591 nextToken();
3594 void Parser::check(enum TOK value, char *string)
3596 if (token.value != value)
3597 error("found '%s' when expecting '%s' following '%s'",
3598 token.toChars(), Token::toChars(value), string);
3599 nextToken();
3602 char *Parser::endToken()
3604 return "semicolon";
3607 char *DltParser::endToken()
3609 return "newline";
3612 void Parser::checkLParen() { check(TOKlparen); }
3613 void Parser::checkRParen() { check(TOKrparen); }
3615 void DltParser::checkLParen() { }
3616 void DltParser::checkRParen() { }
3618 /************************************
3619 * Determine if the scanner is sitting on the start of a declaration.
3620 * Input:
3621 * needId 0 no identifier
3622 * 1 identifier optional
3623 * 2 must have identifier
3626 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
3628 int haveId = 0;
3630 if (!isBasicType(&t))
3631 return FALSE;
3632 if (!isDeclarator(&t, &haveId, endtok))
3633 return FALSE;
3634 if ( needId == 1 ||
3635 (needId == 0 && !haveId) ||
3636 (needId == 2 && haveId))
3637 { if (pt)
3638 *pt = t;
3639 return TRUE;
3641 else
3642 return FALSE;
3645 int Parser::isBasicType(Token **pt)
3647 // This code parallels parseBasicType()
3648 Token *t = *pt;
3649 Token *t2;
3650 int parens;
3652 switch (t->value)
3654 CASE_BASIC_TYPES:
3655 t = peek(t);
3656 break;
3658 case TOKidentifier:
3659 t = peek(t);
3660 if (t->value == TOKnot)
3662 goto L4;
3664 goto L3;
3665 while (1)
3668 t = peek(t);
3670 if (t->value == TOKdot)
3672 Ldot:
3673 t = peek(t);
3674 if (t->value != TOKidentifier)
3675 goto Lfalse;
3676 t = peek(t);
3677 if (t->value != TOKnot)
3678 goto L3;
3680 t = peek(t);
3681 if (t->value != TOKlparen)
3682 goto Lfalse;
3683 if (!skipParens(t, &t))
3684 goto Lfalse;
3686 else
3687 break;
3689 break;
3691 case TOKdot:
3692 goto Ldot;
3694 case TOKtypeof:
3695 /* typeof(exp).identifier...
3697 t = peek(t);
3698 if (t->value != TOKlparen)
3699 goto Lfalse;
3700 if (!skipParens(t, &t))
3701 goto Lfalse;
3702 goto L2;
3704 default:
3705 goto Lfalse;
3707 *pt = t;
3708 return TRUE;
3710 Lfalse:
3711 return FALSE;
3714 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
3715 { // This code parallels parseDeclarator()
3716 Token *t = *pt;
3717 int parens;
3719 //printf("Parser::isDeclarator()\n");
3720 //t->print();
3721 if (t->value == TOKassign)
3722 return FALSE;
3724 while (1)
3726 parens = FALSE;
3727 switch (t->value)
3729 case TOKquestion:
3730 case TOKmul:
3731 case TOKand:
3732 t = peek(t);
3733 continue;
3735 case TOKlbracket:
3736 t = peek(t);
3737 if (t->value == TOKrbracket)
3739 t = peek(t);
3741 else if (isDeclaration(t, 0, TOKrbracket, &t))
3742 { // It's an associative array declaration
3743 t = peek(t);
3745 else
3747 // [ expression ]
3748 // [ expression .. expression ]
3749 if (!isExpression(&t))
3750 return FALSE;
3751 if (t->value == TOKslice)
3752 { t = peek(t);
3753 if (!isExpression(&t))
3754 return FALSE;
3756 if (t->value != TOKrbracket)
3757 return FALSE;
3758 t = peek(t);
3760 continue;
3762 case TOKidentifier:
3763 if (*haveId)
3764 return FALSE;
3765 *haveId = TRUE;
3766 t = peek(t);
3767 break;
3769 case TOKlparen:
3770 t = peek(t);
3772 if (t->value == TOKrparen)
3773 return FALSE; // () is not a declarator
3775 /* Regard ( identifier ) as not a declarator
3776 * BUG: what about ( *identifier ) in
3777 * f(*p)(x);
3778 * where f is a class instance with overloaded () ?
3779 * Should we just disallow C-style function pointer declarations?
3781 if (t->value == TOKidentifier)
3782 { Token *t2 = peek(t);
3783 if (t2->value == TOKrparen)
3784 return FALSE;
3788 if (!isDeclarator(&t, haveId, TOKrparen))
3789 return FALSE;
3790 t = peek(t);
3791 parens = TRUE;
3792 break;
3794 case TOKdelegate:
3795 case TOKfunction:
3796 t = peek(t);
3797 if (!isParameters(&t))
3798 return FALSE;
3799 continue;
3801 break;
3804 while (1)
3806 switch (t->value)
3808 #if CARRAYDECL
3809 case TOKlbracket:
3810 parens = FALSE;
3811 t = peek(t);
3812 if (t->value == TOKrbracket)
3814 t = peek(t);
3816 else if (isDeclaration(t, 0, TOKrbracket, &t))
3817 { // It's an associative array declaration
3818 t = peek(t);
3820 else
3822 // [ expression ]
3823 if (!isExpression(&t))
3824 return FALSE;
3825 if (t->value != TOKrbracket)
3826 return FALSE;
3827 t = peek(t);
3829 continue;
3830 #endif
3832 case TOKlparen:
3833 parens = FALSE;
3834 if (!isParameters(&t))
3835 return FALSE;
3836 continue;
3838 // Valid tokens that follow a declaration
3839 case TOKrparen:
3840 case TOKrbracket:
3841 case TOKassign:
3842 case TOKcomma:
3843 case TOKendline:
3844 case TOKsemicolon:
3845 case TOKlcurly:
3846 case TOKin:
3847 // The !parens is to disallow unnecessary parentheses
3848 if (!parens && (endtok == TOKreserved || endtok == t->value))
3849 { *pt = t;
3850 return TRUE;
3852 return FALSE;
3854 default:
3855 return FALSE;
3861 int Parser::isParameters(Token **pt)
3862 { // This code parallels parseParameters()
3863 Token *t = *pt;
3864 int tmp;
3866 //printf("isParameters()\n");
3867 if (t->value != TOKlparen)
3868 return FALSE;
3870 t = peek(t);
3871 while (1)
3873 switch (t->value)
3875 case TOKrparen:
3876 break;
3878 case TOKdotdotdot:
3879 t = peek(t);
3880 break;
3882 case TOKin:
3883 case TOKout:
3884 case TOKinout:
3885 case TOKref:
3886 case TOKlazy:
3887 t = peek(t);
3888 default:
3889 if (!isBasicType(&t))
3890 return FALSE;
3891 tmp = FALSE;
3892 if (t->value != TOKdotdotdot &&
3893 !isDeclarator(&t, &tmp, TOKreserved))
3894 return FALSE;
3895 if (t->value == TOKassign)
3896 { t = peek(t);
3897 if (!isExpression(&t))
3898 return FALSE;
3900 if (t->value == TOKdotdotdot)
3902 t = peek(t);
3903 break;
3905 if (t->value == TOKcomma)
3906 { t = peek(t);
3907 continue;
3909 break;
3911 break;
3913 if (t->value != TOKrparen)
3914 return FALSE;
3915 t = peek(t);
3916 *pt = t;
3917 return TRUE;
3920 int Parser::isExpression(Token **pt)
3922 // This is supposed to determine if something is an expression.
3923 // What it actually does is scan until a closing right bracket
3924 // is found.
3926 Token *t = *pt;
3927 int brnest = 0;
3928 int panest = 0;
3930 for (;; t = peek(t))
3932 switch (t->value)
3934 case TOKlbracket:
3935 brnest++;
3936 continue;
3938 case TOKrbracket:
3939 if (--brnest >= 0)
3940 continue;
3941 break;
3943 case TOKlparen:
3944 panest++;
3945 continue;
3947 case TOKcomma:
3948 if (brnest || panest)
3949 continue;
3950 break;
3952 case TOKrparen:
3953 if (--panest >= 0)
3954 continue;
3955 break;
3957 case TOKslice:
3958 if (brnest)
3959 continue;
3960 break;
3962 case TOKeof:
3963 return FALSE;
3965 default:
3966 continue;
3968 break;
3971 *pt = t;
3972 return TRUE;
3975 /**********************************************
3976 * Skip over
3977 * instance foo.bar(parameters...)
3978 * Output:
3979 * if (pt), *pt is set to the token following the closing )
3980 * Returns:
3981 * 1 it's valid instance syntax
3982 * 0 invalid instance syntax
3985 int Parser::isTemplateInstance(Token *t, Token **pt)
3987 t = peek(t);
3988 if (t->value != TOKdot)
3990 if (t->value != TOKidentifier)
3991 goto Lfalse;
3992 t = peek(t);
3994 while (t->value == TOKdot)
3996 t = peek(t);
3997 if (t->value != TOKidentifier)
3998 goto Lfalse;
3999 t = peek(t);
4001 if (t->value != TOKlparen)
4002 goto Lfalse;
4004 // Skip over the template arguments
4005 while (1)
4007 while (1)
4009 t = peek(t);
4010 switch (t->value)
4012 case TOKlparen:
4013 if (!skipParens(t, &t))
4014 goto Lfalse;
4015 continue;
4016 case TOKrparen:
4017 break;
4018 case TOKcomma:
4019 break;
4020 case TOKeof:
4021 case TOKsemicolon:
4022 goto Lfalse;
4023 default:
4024 continue;
4026 break;
4029 if (t->value != TOKcomma)
4030 break;
4032 if (t->value != TOKrparen)
4033 goto Lfalse;
4034 t = peek(t);
4035 if (pt)
4036 *pt = t;
4037 return 1;
4039 Lfalse:
4040 return 0;
4043 /*******************************************
4044 * Skip parens, brackets.
4045 * Input:
4046 * t is on opening (
4047 * Output:
4048 * *pt is set to closing token, which is ')' on success
4049 * Returns:
4050 * !=0 successful
4051 * 0 some parsing error
4054 int Parser::skipParens(Token *t, Token **pt)
4056 int parens = 0;
4058 while (1)
4060 switch (t->value)
4062 case TOKlparen:
4063 parens++;
4064 break;
4066 case TOKrparen:
4067 parens--;
4068 if (parens < 0)
4069 goto Lfalse;
4070 if (parens == 0)
4071 goto Ldone;
4072 break;
4074 case TOKeof:
4075 case TOKsemicolon:
4076 goto Lfalse;
4078 default:
4079 break;
4081 t = peek(t);
4084 Ldone:
4085 if (*pt)
4086 *pt = t;
4087 return 1;
4089 Lfalse:
4090 return 0;
4093 /********************************* Expression Parser ***************************/
4095 Expression *Parser::parsePrimaryExp()
4096 { Expression *e;
4097 Type *t;
4098 Identifier *id;
4099 enum TOK save;
4100 Loc loc = this->loc;
4102 switch (token.value)
4104 case TOKidentifier:
4105 id = token.ident;
4106 nextToken();
4107 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4108 { // identifier!(template-argument-list)
4109 TemplateInstance *tempinst;
4111 tempinst = new TemplateInstance(loc, id);
4112 nextToken();
4113 tempinst->tiargs = parseTemplateArgumentList();
4114 e = new ScopeExp(loc, tempinst);
4116 else
4117 e = new IdentifierExp(loc, id);
4118 break;
4120 case TOKdollar:
4121 if (!inBrackets)
4122 error("'$' is valid only inside [] of index or slice");
4123 e = new DollarExp(loc);
4124 nextToken();
4125 break;
4127 case TOKdot:
4128 // Signal global scope '.' operator with "" identifier
4129 e = new IdentifierExp(loc, Id::empty);
4130 break;
4132 case TOKthis:
4133 e = new ThisExp(loc);
4134 nextToken();
4135 break;
4137 case TOKsuper:
4138 e = new SuperExp(loc);
4139 nextToken();
4140 break;
4142 case TOKint32v:
4143 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
4144 nextToken();
4145 break;
4147 case TOKuns32v:
4148 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
4149 nextToken();
4150 break;
4152 case TOKint64v:
4153 e = new IntegerExp(loc, token.int64value, Type::tint64);
4154 nextToken();
4155 break;
4157 case TOKuns64v:
4158 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4159 nextToken();
4160 break;
4162 case TOKfloat32v:
4163 e = new RealExp(loc, token.float80value, Type::tfloat32);
4164 nextToken();
4165 break;
4167 case TOKfloat64v:
4168 e = new RealExp(loc, token.float80value, Type::tfloat64);
4169 nextToken();
4170 break;
4172 case TOKfloat80v:
4173 e = new RealExp(loc, token.float80value, Type::tfloat80);
4174 nextToken();
4175 break;
4177 case TOKimaginary32v:
4178 e = new RealExp(loc, token.float80value, Type::timaginary32);
4179 nextToken();
4180 break;
4182 case TOKimaginary64v:
4183 e = new RealExp(loc, token.float80value, Type::timaginary64);
4184 nextToken();
4185 break;
4187 case TOKimaginary80v:
4188 e = new RealExp(loc, token.float80value, Type::timaginary80);
4189 nextToken();
4190 break;
4192 case TOKnull:
4193 e = new NullExp(loc);
4194 nextToken();
4195 break;
4197 case TOKtrue:
4198 e = new IntegerExp(loc, 1, Type::tbool);
4199 nextToken();
4200 break;
4202 case TOKfalse:
4203 e = new IntegerExp(loc, 0, Type::tbool);
4204 nextToken();
4205 break;
4207 case TOKcharv:
4208 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tchar);
4209 nextToken();
4210 break;
4212 case TOKwcharv:
4213 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::twchar);
4214 nextToken();
4215 break;
4217 case TOKdcharv:
4218 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
4219 nextToken();
4220 break;
4222 case TOKstring:
4223 { unsigned char *s;
4224 unsigned len;
4225 unsigned char postfix;
4227 // cat adjacent strings
4228 s = token.ustring;
4229 len = token.len;
4230 postfix = token.postfix;
4231 while (1)
4233 nextToken();
4234 if (token.value == TOKstring)
4235 { unsigned len1;
4236 unsigned len2;
4237 unsigned char *s2;
4239 if (token.postfix)
4240 { if (token.postfix != postfix)
4241 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4242 postfix = token.postfix;
4245 len1 = len;
4246 len2 = token.len;
4247 len = len1 + len2;
4248 s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
4249 memcpy(s2, s, len1 * sizeof(unsigned char));
4250 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
4251 s = s2;
4253 else
4254 break;
4256 e = new StringExp(loc, s, len, postfix);
4257 break;
4260 CASE_BASIC_TYPES_X(t):
4261 nextToken();
4263 check(TOKdot, t->toChars());
4264 if (token.value != TOKidentifier)
4265 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
4266 goto Lerr;
4268 e = new TypeDotIdExp(loc, t, token.ident);
4269 nextToken();
4270 break;
4272 case TOKtypeof:
4273 { Expression *exp;
4275 nextToken();
4276 check(TOKlparen);
4277 exp = parseExpression();
4278 check(TOKrparen);
4279 t = new TypeTypeof(loc, exp);
4280 if (token.value == TOKdot)
4281 goto L1;
4282 e = new TypeExp(loc, t);
4283 break;
4286 case TOKtypeid:
4287 { Type *t;
4289 nextToken();
4290 check(TOKlparen, "typeid");
4291 t = parseBasicType();
4292 t = parseDeclarator(t,NULL); // ( type )
4293 check(TOKrparen);
4294 e = new TypeidExp(loc, t);
4295 break;
4298 case TOKis:
4299 { Type *targ;
4300 Identifier *ident = NULL;
4301 Type *tspec = NULL;
4302 enum TOK tok = TOKreserved;
4303 enum TOK tok2 = TOKreserved;
4304 Loc loc = this->loc;
4306 nextToken();
4307 if (token.value == TOKlparen)
4309 nextToken();
4310 targ = parseBasicType();
4311 targ = parseDeclarator(targ, &ident);
4312 if (token.value == TOKcolon || token.value == TOKequal)
4314 tok = token.value;
4315 nextToken();
4316 if (tok == TOKequal &&
4317 (token.value == TOKtypedef ||
4318 token.value == TOKstruct ||
4319 token.value == TOKunion ||
4320 token.value == TOKclass ||
4321 token.value == TOKsuper ||
4322 token.value == TOKenum ||
4323 token.value == TOKinterface ||
4324 token.value == TOKfunction ||
4325 token.value == TOKdelegate ||
4326 token.value == TOKreturn))
4328 tok2 = token.value;
4329 nextToken();
4331 else
4333 tspec = parseBasicType();
4334 tspec = parseDeclarator(tspec, NULL);
4337 check(TOKrparen);
4339 else
4340 { error("(type identifier : specialization) expected following is");
4341 goto Lerr;
4343 e = new IsExp(loc, targ, ident, tok, tspec, tok2);
4344 break;
4347 case TOKassert:
4348 { Expression *msg = NULL;
4350 nextToken();
4352 checkLParen();
4353 e = parseAssignExp();
4354 if (token.value == (dltSyntax ? TOKelse : TOKcomma))
4355 { nextToken();
4356 msg = parseAssignExp();
4358 checkRParen();
4360 e = new AssertExp(loc, e, msg);
4361 break;
4364 case TOKmixin:
4366 nextToken();
4367 check(TOKlparen, "mixin");
4368 e = parseAssignExp();
4369 check(TOKrparen);
4370 e = new CompileExp(loc, e);
4371 break;
4374 case TOKimport:
4376 nextToken();
4377 check(TOKlparen, "import");
4378 e = parseAssignExp();
4379 check(TOKrparen);
4380 e = new FileExp(loc, e);
4381 break;
4384 case TOKlparen:
4385 if (peekPastParen(&token)->value == TOKlcurly)
4386 { // (arguments) { statements... }
4387 save = TOKdelegate;
4388 goto case_delegate;
4390 // ( expression )
4391 nextToken();
4392 e = parseExpression();
4393 check(loc, TOKrparen);
4394 break;
4396 case TOKlbracket:
4397 { /* Parse array literals and associative array literals:
4398 * [ value, value, value ... ]
4399 * [ key:value, key:value, key:value ... ]
4401 Expressions *values = new Expressions();
4402 Expressions *keys = NULL;
4404 nextToken();
4405 if (token.value != TOKrbracket)
4407 while (1)
4409 Expression *e = parseAssignExp();
4410 if (token.value == TOKcolon && (keys || values->dim == 0))
4411 { nextToken();
4412 if (!keys)
4413 keys = new Expressions();
4414 keys->push(e);
4415 e = parseAssignExp();
4417 else if (keys)
4418 { error("'key:value' expected for associative array literal");
4419 delete keys;
4420 keys = NULL;
4422 values->push(e);
4423 if (token.value == TOKrbracket)
4424 break;
4425 check(TOKcomma);
4428 check(TOKrbracket);
4430 if (keys)
4431 e = new AssocArrayLiteralExp(loc, keys, values);
4432 else
4433 e = new ArrayLiteralExp(loc, values);
4434 break;
4437 case TOKlcurly:
4438 // { statements... }
4439 save = TOKdelegate;
4440 goto case_delegate;
4442 case TOKfunction:
4443 case TOKdelegate:
4444 save = token.value;
4445 nextToken();
4446 case_delegate:
4448 /* function type(parameters) { body }
4449 * delegate type(parameters) { body }
4451 Arguments *arguments;
4452 int varargs;
4453 FuncLiteralDeclaration *fd;
4454 Type *t;
4456 if (token.value == TOKlcurly)
4458 t = NULL;
4459 varargs = 0;
4460 arguments = new Arguments();
4462 else
4464 if (token.value == TOKlparen)
4465 t = NULL;
4466 else
4468 t = parseBasicType();
4469 t = parseBasicType2(t); // function return type
4471 arguments = parseParameters(&varargs);
4473 t = new TypeFunction(arguments, t, varargs, linkage);
4474 fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL);
4475 parseContracts(fd);
4476 e = new FuncExp(loc, fd);
4477 break;
4480 default:
4481 error("expression expected, not '%s'", token.toChars());
4482 Lerr:
4483 // Anything for e, as long as it's not NULL
4484 e = new IntegerExp(loc, 0, Type::tint32);
4485 nextToken();
4486 break;
4488 return parsePostExp(e);
4491 Expression *Parser::parsePostExp(Expression *e)
4493 Loc loc;
4495 while (1)
4497 loc = this->loc;
4498 switch (token.value)
4500 case TOKdot:
4501 nextToken();
4502 if (token.value == TOKidentifier)
4503 { Identifier *id = token.ident;
4505 nextToken();
4506 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4507 { // identifier!(template-argument-list)
4508 TemplateInstance *tempinst;
4510 tempinst = new TemplateInstance(loc, id);
4511 nextToken();
4512 tempinst->tiargs = parseTemplateArgumentList();
4513 e = new DotTemplateInstanceExp(loc, e, tempinst);
4515 else
4516 e = new DotIdExp(loc, e, id);
4517 continue;
4519 else if (token.value == TOKnew)
4521 e = parseNewExp(e);
4522 continue;
4524 else
4525 error("identifier expected following '.', not '%s'", token.toChars());
4526 break;
4528 case TOKplusplus:
4529 e = new PostExp(TOKplusplus, loc, e);
4530 break;
4532 case TOKminusminus:
4533 e = new PostExp(TOKminusminus, loc, e);
4534 break;
4536 case TOKlparen:
4537 e = new CallExp(loc, e, parseArguments());
4538 continue;
4540 case TOKlbracket:
4541 { // array dereferences:
4542 // array[index]
4543 // array[]
4544 // array[lwr .. upr]
4545 Expression *index;
4546 Expression *upr;
4548 inBrackets++;
4549 nextToken();
4550 if (token.value == TOKrbracket)
4551 { // array[]
4552 e = new SliceExp(loc, e, NULL, NULL);
4553 nextToken();
4555 else
4557 index = parseAssignExp();
4558 if (token.value == TOKslice)
4559 { // array[lwr .. upr]
4560 nextToken();
4561 upr = parseAssignExp();
4562 e = new SliceExp(loc, e, index, upr);
4564 else
4565 { // array[index, i2, i3, i4, ...]
4566 Expressions *arguments = new Expressions();
4567 arguments->push(index);
4568 if (token.value == TOKcomma)
4570 nextToken();
4571 while (1)
4572 { Expression *arg;
4574 arg = parseAssignExp();
4575 arguments->push(arg);
4576 if (token.value == TOKrbracket)
4577 break;
4578 check(TOKcomma);
4581 e = new ArrayExp(loc, e, arguments);
4583 check(TOKrbracket);
4584 inBrackets--;
4586 continue;
4589 default:
4590 return e;
4592 nextToken();
4596 Expression *Parser::parseUnaryExp()
4597 { Expression *e;
4598 Loc loc = this->loc;
4600 switch (token.value)
4602 case TOKand:
4603 nextToken();
4604 e = parseUnaryExp();
4605 e = new AddrExp(loc, e);
4606 break;
4608 case TOKplusplus:
4609 nextToken();
4610 e = parseUnaryExp();
4611 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
4612 break;
4614 case TOKminusminus:
4615 nextToken();
4616 e = parseUnaryExp();
4617 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
4618 break;
4620 case TOKmul:
4621 nextToken();
4622 e = parseUnaryExp();
4623 e = new PtrExp(loc, e);
4624 break;
4626 case TOKmin:
4627 nextToken();
4628 e = parseUnaryExp();
4629 e = new NegExp(loc, e);
4630 break;
4632 case TOKadd:
4633 nextToken();
4634 e = parseUnaryExp();
4635 e = new UAddExp(loc, e);
4636 break;
4638 case TOKnot:
4639 nextToken();
4640 e = parseUnaryExp();
4641 e = new NotExp(loc, e);
4642 break;
4644 case TOKtilde:
4645 nextToken();
4646 e = parseUnaryExp();
4647 e = new ComExp(loc, e);
4648 break;
4650 case TOKdelete:
4651 nextToken();
4652 e = parseUnaryExp();
4653 e = new DeleteExp(loc, e);
4654 break;
4656 case TOKnew:
4657 e = parseNewExp(NULL);
4658 break;
4660 case TOKcast: // cast(type) expression
4661 { Type *t;
4663 nextToken();
4664 check(TOKlparen);
4665 t = parseBasicType();
4666 t = parseDeclarator(t,NULL); // ( type )
4667 check(TOKrparen);
4669 e = parseUnaryExp();
4670 e = new CastExp(loc, e, t);
4671 break;
4674 case TOKlparen:
4675 { Token *tk;
4677 tk = peek(&token);
4678 #if CCASTSYNTAX
4679 // If cast
4680 if (isDeclaration(tk, 0, TOKrparen, &tk))
4682 tk = peek(tk); // skip over right parenthesis
4683 switch (tk->value)
4685 case TOKdot:
4686 case TOKplusplus:
4687 case TOKminusminus:
4688 case TOKnot:
4689 case TOKdelete:
4690 case TOKnew:
4691 case TOKlparen:
4692 case TOKidentifier:
4693 case TOKthis:
4694 case TOKsuper:
4695 case TOKint32v:
4696 case TOKuns32v:
4697 case TOKint64v:
4698 case TOKuns64v:
4699 case TOKfloat32v:
4700 case TOKfloat64v:
4701 case TOKfloat80v:
4702 case TOKimaginary32v:
4703 case TOKimaginary64v:
4704 case TOKimaginary80v:
4705 case TOKnull:
4706 case TOKtrue:
4707 case TOKfalse:
4708 case TOKcharv:
4709 case TOKwcharv:
4710 case TOKdcharv:
4711 case TOKstring:
4712 #if 0
4713 case TOKtilde:
4714 case TOKand:
4715 case TOKmul:
4716 case TOKmin:
4717 case TOKadd:
4718 #endif
4719 case TOKfunction:
4720 case TOKdelegate:
4721 case TOKtypeof:
4722 CASE_BASIC_TYPES: // (type)int.size
4723 { // (type) una_exp
4724 Type *t;
4726 nextToken();
4727 t = parseBasicType();
4728 t = parseDeclarator(t,NULL);
4729 check(TOKrparen);
4731 // if .identifier
4732 if (token.value == TOKdot)
4734 nextToken();
4735 if (token.value != TOKidentifier)
4736 { error("Identifier expected following (type).");
4737 return NULL;
4739 e = new TypeDotIdExp(loc, t, token.ident);
4740 nextToken();
4741 e = parsePostExp(e);
4743 else
4745 e = parseUnaryExp();
4746 e = new CastExp(loc, e, t);
4747 error("C style cast illegal, use %s", e->toChars());
4749 return e;
4753 #endif
4754 e = parsePrimaryExp();
4755 break;
4757 default:
4758 e = parsePrimaryExp();
4759 break;
4761 assert(e);
4762 return e;
4765 Expression *Parser::parseMulExp()
4766 { Expression *e;
4767 Expression *e2;
4768 Loc loc = this->loc;
4770 e = parseUnaryExp();
4771 while (1)
4773 switch (token.value)
4775 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
4776 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
4777 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
4779 default:
4780 break;
4782 break;
4784 return e;
4787 Expression *Parser::parseAddExp()
4788 { Expression *e;
4789 Expression *e2;
4790 Loc loc = this->loc;
4792 e = parseMulExp();
4793 while (1)
4795 switch (token.value)
4797 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
4798 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
4799 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
4801 default:
4802 break;
4804 break;
4806 return e;
4809 Expression *Parser::parseShiftExp()
4810 { Expression *e;
4811 Expression *e2;
4812 Loc loc = this->loc;
4814 e = parseAddExp();
4815 while (1)
4817 switch (token.value)
4819 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
4820 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
4821 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
4823 default:
4824 break;
4826 break;
4828 return e;
4831 Expression *Parser::parseRelExp()
4832 { Expression *e;
4833 Expression *e2;
4834 enum TOK op;
4835 Loc loc = this->loc;
4837 e = parseShiftExp();
4838 while (1)
4840 switch (token.value)
4842 case TOKlt:
4843 case TOKle:
4844 case TOKgt:
4845 case TOKge:
4846 case TOKunord:
4847 case TOKlg:
4848 case TOKleg:
4849 case TOKule:
4850 case TOKul:
4851 case TOKuge:
4852 case TOKug:
4853 case TOKue:
4854 op = token.value;
4855 nextToken();
4856 e2 = parseShiftExp();
4857 e = new CmpExp(op, loc, e, e2);
4858 continue;
4860 case TOKin:
4861 nextToken();
4862 e2 = parseShiftExp();
4863 e = new InExp(loc, e, e2);
4864 continue;
4866 default:
4867 break;
4869 break;
4871 return e;
4874 Expression *Parser::parseEqualExp()
4875 { Expression *e;
4876 Expression *e2;
4877 Token *t;
4878 Loc loc = this->loc;
4880 e = parseRelExp();
4881 while (1)
4882 { enum TOK value = token.value;
4884 switch (value)
4886 case TOKequal:
4887 case TOKnotequal:
4888 nextToken();
4889 e2 = parseRelExp();
4890 e = new EqualExp(value, loc, e, e2);
4891 continue;
4893 case TOKidentity:
4894 error("'===' is no longer legal, use 'is' instead");
4895 goto L1;
4897 case TOKnotidentity:
4898 error("'!==' is no longer legal, use '!is' instead");
4899 goto L1;
4901 case TOKis:
4902 value = TOKidentity;
4903 goto L1;
4905 case TOKnot:
4906 // Attempt to identify '!is'
4907 t = peek(&token);
4908 if (t->value != TOKis)
4909 break;
4910 nextToken();
4911 value = TOKnotidentity;
4912 goto L1;
4915 nextToken();
4916 e2 = parseRelExp();
4917 e = new IdentityExp(value, loc, e, e2);
4918 continue;
4920 default:
4921 break;
4923 break;
4925 return e;
4928 Expression *Parser::parseCmpExp()
4929 { Expression *e;
4930 Expression *e2;
4931 Token *t;
4932 Loc loc = this->loc;
4934 e = parseShiftExp();
4935 enum TOK op = token.value;
4937 switch (op)
4939 case TOKequal:
4940 case TOKnotequal:
4941 nextToken();
4942 e2 = parseShiftExp();
4943 e = new EqualExp(op, loc, e, e2);
4944 break;
4946 case TOKis:
4947 op = TOKidentity;
4948 goto L1;
4950 case TOKnot:
4951 // Attempt to identify '!is'
4952 t = peek(&token);
4953 if (t->value != TOKis)
4954 break;
4955 nextToken();
4956 op = TOKnotidentity;
4957 goto L1;
4960 nextToken();
4961 e2 = parseShiftExp();
4962 e = new IdentityExp(op, loc, e, e2);
4963 break;
4965 case TOKlt:
4966 case TOKle:
4967 case TOKgt:
4968 case TOKge:
4969 case TOKunord:
4970 case TOKlg:
4971 case TOKleg:
4972 case TOKule:
4973 case TOKul:
4974 case TOKuge:
4975 case TOKug:
4976 case TOKue:
4977 nextToken();
4978 e2 = parseShiftExp();
4979 e = new CmpExp(op, loc, e, e2);
4980 break;
4982 case TOKin:
4983 nextToken();
4984 e2 = parseShiftExp();
4985 e = new InExp(loc, e, e2);
4986 break;
4988 default:
4989 break;
4991 return e;
4994 Expression *Parser::parseAndExp()
4995 { Expression *e;
4996 Expression *e2;
4997 Loc loc = this->loc;
4999 if (global.params.Dversion == 1)
5001 e = parseEqualExp();
5002 while (token.value == TOKand)
5004 nextToken();
5005 e2 = parseEqualExp();
5006 e = new AndExp(loc,e,e2);
5007 loc = this->loc;
5010 else
5012 e = parseCmpExp();
5013 while (token.value == TOKand)
5015 nextToken();
5016 e2 = parseCmpExp();
5017 e = new AndExp(loc,e,e2);
5018 loc = this->loc;
5021 return e;
5024 Expression *Parser::parseXorExp()
5025 { Expression *e;
5026 Expression *e2;
5027 Loc loc = this->loc;
5029 e = parseAndExp();
5030 while (token.value == TOKxor)
5032 nextToken();
5033 e2 = parseAndExp();
5034 e = new XorExp(loc, e, e2);
5036 return e;
5039 Expression *Parser::parseOrExp()
5040 { Expression *e;
5041 Expression *e2;
5042 Loc loc = this->loc;
5044 e = parseXorExp();
5045 while (token.value == TOKor)
5047 nextToken();
5048 e2 = parseXorExp();
5049 e = new OrExp(loc, e, e2);
5051 return e;
5054 Expression *Parser::parseAndAndExp()
5055 { Expression *e;
5056 Expression *e2;
5057 Loc loc = this->loc;
5059 e = parseOrExp();
5060 while (token.value == TOKandand)
5062 nextToken();
5063 e2 = parseOrExp();
5064 e = new AndAndExp(loc, e, e2);
5066 return e;
5069 Expression *Parser::parseOrOrExp()
5070 { Expression *e;
5071 Expression *e2;
5072 Loc loc = this->loc;
5074 e = parseAndAndExp();
5075 while (token.value == TOKoror)
5077 nextToken();
5078 e2 = parseAndAndExp();
5079 e = new OrOrExp(loc, e, e2);
5081 return e;
5084 Expression *Parser::parseCondExp()
5085 { Expression *e;
5086 Expression *e1;
5087 Expression *e2;
5088 Loc loc = this->loc;
5090 e = parseOrOrExp();
5091 if (token.value == TOKquestion)
5093 nextToken();
5094 e1 = parseExpression();
5095 check(TOKcolon);
5096 e2 = parseCondExp();
5097 e = new CondExp(loc, e, e1, e2);
5099 return e;
5102 Expression *DltParser::parseCondExp()
5103 { Expression *e;
5104 Expression *e1;
5105 Expression *e2;
5106 Loc loc = this->loc;
5108 e = parseOrOrExp();
5109 if (token.value == TOKif)
5111 nextToken();
5112 e1 = parseExpression();
5113 check(TOKelse);
5114 e2 = parseCondExp();
5115 e = new CondExp(loc, e1, e, e2);
5117 return e;
5120 Expression *Parser::parseAssignExp()
5121 { Expression *e;
5122 Expression *e2;
5123 Loc loc;
5125 e = parseCondExp();
5126 while (1)
5128 loc = this->loc;
5129 switch (token.value)
5131 #define X(tok,ector) \
5132 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5134 X(TOKassign, AssignExp);
5135 X(TOKaddass, AddAssignExp);
5136 X(TOKminass, MinAssignExp);
5137 X(TOKmulass, MulAssignExp);
5138 X(TOKdivass, DivAssignExp);
5139 X(TOKmodass, ModAssignExp);
5140 X(TOKandass, AndAssignExp);
5141 X(TOKorass, OrAssignExp);
5142 X(TOKxorass, XorAssignExp);
5143 X(TOKshlass, ShlAssignExp);
5144 X(TOKshrass, ShrAssignExp);
5145 X(TOKushrass, UshrAssignExp);
5146 X(TOKcatass, CatAssignExp);
5148 #undef X
5149 default:
5150 break;
5152 break;
5154 return e;
5157 Expression *Parser::parseExpression()
5158 { Expression *e;
5159 Expression *e2;
5160 Loc loc = this->loc;
5162 //printf("Parser::parseExpression()\n");
5163 e = parseAssignExp();
5164 while (token.value == TOKcomma)
5166 nextToken();
5167 e2 = parseAssignExp();
5168 e = new CommaExp(loc, e, e2);
5169 loc = this->loc;
5171 return e;
5175 /*************************
5176 * Collect argument list.
5177 * Assume current token is '(' or '['.
5180 Expressions *Parser::parseArguments()
5181 { // function call
5182 Expressions *arguments;
5183 Expression *arg;
5184 enum TOK endtok;
5186 arguments = new Expressions();
5187 if (token.value == TOKlbracket)
5188 endtok = TOKrbracket;
5189 else
5190 endtok = TOKrparen;
5193 nextToken();
5194 if (token.value != endtok)
5196 while (1)
5198 arg = parseAssignExp();
5199 arguments->push(arg);
5200 if (token.value == endtok)
5201 break;
5202 check(TOKcomma);
5205 check(endtok);
5207 return arguments;
5210 /*******************************************
5213 Expression *Parser::parseNewExp(Expression *thisexp)
5214 { Type *t;
5215 Expressions *newargs;
5216 Expressions *arguments = NULL;
5217 Expression *e;
5218 Loc loc = this->loc;
5220 nextToken();
5221 newargs = NULL;
5222 if (token.value == TOKlparen)
5224 newargs = parseArguments();
5227 // An anonymous nested class starts with "class"
5228 if (token.value == TOKclass)
5230 nextToken();
5231 if (token.value == TOKlparen)
5232 arguments = parseArguments();
5234 BaseClasses *baseclasses = NULL;
5235 if (token.value != TOKlcurly)
5236 baseclasses = parseBaseClasses();
5238 Identifier *id = NULL;
5239 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
5241 if (token.value != TOKlcurly)
5242 { error("{ members } expected for anonymous class");
5243 cd->members = NULL;
5245 else
5247 nextToken();
5248 Array *decl = parseDeclDefs(0);
5249 if (token.value != TOKrcurly)
5250 error("class member expected");
5251 nextToken();
5252 cd->members = decl;
5255 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5257 return e;
5260 #if LTORARRAYDECL
5261 t = parseBasicType();
5262 t = parseBasicType2(t);
5263 if (t->ty == Taarray)
5265 Type *index = ((TypeAArray *)t)->index;
5267 Expression *e = index->toExpression();
5268 if (e)
5269 { arguments = new Expressions();
5270 arguments->push(e);
5271 t = new TypeDArray(t->next);
5273 else
5275 error("need size of rightmost array, not type %s", index->toChars());
5276 return new NullExp(loc);
5279 else if (t->ty == Tsarray)
5281 TypeSArray *tsa = (TypeSArray *)t;
5282 Expression *e = tsa->dim;
5284 arguments = new Expressions();
5285 arguments->push(e);
5286 t = new TypeDArray(t->next);
5288 else if (token.value == TOKlparen)
5290 arguments = parseArguments();
5292 #else
5293 t = parseBasicType();
5294 while (token.value == TOKmul)
5295 { t = new TypePointer(t);
5296 nextToken();
5298 if (token.value == TOKlbracket)
5300 Expression *e;
5302 nextToken();
5303 e = parseAssignExp();
5304 arguments = new Array();
5305 arguments->push(e);
5306 check(TOKrbracket);
5307 t = parseDeclarator(t, NULL);
5308 t = new TypeDArray(t);
5310 else if (token.value == TOKlparen)
5311 arguments = parseArguments();
5312 #endif
5313 e = new NewExp(loc, thisexp, newargs, t, arguments);
5314 return e;
5317 /**********************************************
5320 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
5322 s->addComment(combineComments(blockComment, token.lineComment));
5326 /********************************* ***************************/