1:
2: // Compiler implementation of the D programming language
3: // Copyright (c) 1999-2011 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.
10:
11: // This is the D parser
12:
13: #include <stdio.h>
14: static char __file__[] = __FILE__; /* for tassert.h */
15: #include "tassert.h"
16:
17: #include "rmem.h"
18: #include "lexer.h"
19: #include "parse.h"
20: #include "init.h"
21: #include "attrib.h"
22: #include "cond.h"
23: #include "mtype.h"
24: #include "template.h"
25: #include "staticassert.h"
26: #include "expression.h"
27: #include "statement.h"
28: #include "module.h"
29: #include "dsymbol.h"
30: #include "import.h"
31: #include "declaration.h"
32: #include "aggregate.h"
33: #include "enum.h"
34: #include "id.h"
35: #include "version.h"
36: #include "aliasthis.h"
37:
38: // How multiple declarations are parsed.
39: // If 1, treat as C.
40: // If 0, treat:
41: // int *p, i;
42: // as:
43: // int* p;
44: // int* i;
45: #define CDECLSYNTAX 0
46:
47: // Support C cast syntax:
48: // (type)(expression)
49: #define CCASTSYNTAX 1
50:
51: // Support postfix C array declarations, such as
52: // int a[3][4];
53: #define CARRAYDECL 1
54:
55: // Support D1 inout
56: #define D1INOUT 0
57:
58: Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
59: : Lexer(module, base, 0, length, doDocComment, 0)
60: {
61: //printf("Parser::Parser()\n");
62: md = NULL;
63: linkage = LINKd;
64: endloc = 0;
65: inBrackets = 0;
66: //nextToken(); // start up the scanner
67: }
68:
69: Dsymbols *Parser::parseModule()
70: {
71: Dsymbols *decldefs;
72:
73: // ModuleDeclation leads off
74: if (token.value == TOKmodule)
75: {
76: unsigned char *comment = token.blockComment;
77: bool safe = FALSE;
78:
79: nextToken();
80: #if 0 && DMDV2
81: if (token.value == TOKlparen)
82: {
83: nextToken();
84: if (token.value != TOKidentifier)
85: { error("module (system) identifier expected");
86: goto Lerr;
87: }
88: Identifier *id = token.ident;
89:
90: if (id == Id::system)
91: safe = TRUE;
92: else
93: error("(safe) expected, not %s", id->toChars());
94: nextToken();
95: check(TOKrparen);
96: }
97: #endif
98:
99: if (token.value != TOKidentifier)
100: { error("Identifier expected following module");
101: goto Lerr;
102: }
103: else
104: {
105: Identifiers *a = NULL;
106: Identifier *id;
107:
108: id = token.ident;
109: while (nextToken() == TOKdot)
110: {
111: if (!a)
112: a = new Identifiers();
113: a->push(id);
114: nextToken();
115: if (token.value != TOKidentifier)
116: { error("Identifier expected following package");
117: goto Lerr;
118: }
119: id = token.ident;
120: }
121:
122: md = new ModuleDeclaration(a, id, safe);
123:
124: if (token.value != TOKsemicolon)
125: error("';' expected following module declaration instead of %s", token.toChars());
126: nextToken();
127: addComment(mod, comment);
128: }
129: }
130:
131: decldefs = parseDeclDefs(0);
132: if (token.value != TOKeof)
133: { error("unrecognized declaration");
134: goto Lerr;
135: }
136: return decldefs;
137:
138: Lerr:
139: while (token.value != TOKsemicolon && token.value != TOKeof)
140: nextToken();
141: nextToken();
142: return new Dsymbols();
143: }
144:
145: Dsymbols *Parser::parseDeclDefs(int once)
146: { Dsymbol *s;
147: Dsymbols *decldefs;
148: Dsymbols *a;
149: Dsymbols *aelse;
150: enum PROT prot;
151: StorageClass stc;
152: StorageClass storageClass;
153: Condition *condition;
154: unsigned char *comment;
155:
156: //printf("Parser::parseDeclDefs()\n");
157: decldefs = new Dsymbols();
158: do
159: {
160: comment = token.blockComment;
161: storageClass = STCundefined;
162: switch (token.value)
163: {
164: case TOKenum:
165: { /* Determine if this is a manifest constant declaration,
166: * or a conventional enum.
167: */
168: Token *t = peek(&token);
169: if (t->value == TOKlcurly || t->value == TOKcolon)
170: s = parseEnum();
171: else if (t->value != TOKidentifier)
172: goto Ldeclaration;
173: else
174: {
175: t = peek(t);
176: if (t->value == TOKlcurly || t->value == TOKcolon ||
177: t->value == TOKsemicolon)
178: s = parseEnum();
179: else
180: goto Ldeclaration;
181: }
182: break;
183: }
184:
185: case TOKstruct:
186: case TOKunion:
187: case TOKclass:
188: case TOKinterface:
189: s = parseAggregate();
190: break;
191:
192: case TOKimport:
193: s = parseImport(decldefs, 0);
194: break;
195:
196: case TOKtemplate:
197: s = (Dsymbol *)parseTemplateDeclaration(0);
198: break;
199:
200: case TOKmixin:
201: { Loc loc = this->loc;
202: switch (peekNext())
203: {
204: case TOKlparen:
205: { // mixin(string)
206: nextToken();
207: check(TOKlparen, "mixin");
208: Expression *e = parseAssignExp();
209: check(TOKrparen);
210: check(TOKsemicolon);
211: s = new CompileDeclaration(loc, e);
212: break;
213: }
214: case TOKtemplate:
215: // mixin template
216: nextToken();
217: s = (Dsymbol *)parseTemplateDeclaration(1);
218: break;
219:
220: default:
221: s = parseMixin();
222: break;
223: }
224: break;
225: }
226:
227: case BASIC_TYPES:
228: case TOKalias:
229: case TOKtypedef:
230: case TOKidentifier:
231: case TOKtypeof:
232: case TOKdot:
233: Ldeclaration:
234: a = parseDeclarations(STCundefined, NULL);
235: decldefs->append(a);
236: continue;
237:
238: case TOKthis:
239: s = parseCtor();
240: break;
241:
242: #if 0 // dead end, use this(this){} instead
243: case TOKassign:
244: s = parsePostBlit();
245: break;
246: #endif
247: case TOKtilde:
248: s = parseDtor();
249: break;
250:
251: case TOKinvariant:
252: { Token *t;
253: t = peek(&token);
254: if (t->value == TOKlparen)
255: {
256: if (peek(t)->value == TOKrparen)
257: // invariant() forms start of class invariant
258: s = parseInvariant();
259: else
260: // invariant(type)
261: goto Ldeclaration;
262: }
263: else
264: {
265: stc = STCimmutable;
266: goto Lstc;
267: }
268: break;
269: }
270:
271: case TOKunittest:
272: s = parseUnitTest();
273: break;
274:
275: case TOKnew:
276: s = parseNew();
277: break;
278:
279: case TOKdelete:
280: s = parseDelete();
281: break;
282:
283: case TOKeof:
284: case TOKrcurly:
285: return decldefs;
286:
287: case TOKstatic:
288: nextToken();
289: if (token.value == TOKthis)
290: s = parseStaticCtor();
291: else if (token.value == TOKtilde)
292: s = parseStaticDtor();
293: else if (token.value == TOKassert)
294: s = parseStaticAssert();
295: else if (token.value == TOKif)
296: { condition = parseStaticIfCondition();
297: a = parseBlock();
298: aelse = NULL;
299: if (token.value == TOKelse)
300: { nextToken();
301: aelse = parseBlock();
302: }
303: s = new StaticIfDeclaration(condition, a, aelse);
304: break;
305: }
306: else if (token.value == TOKimport)
307: {
308: s = parseImport(decldefs, 1);
309: }
310: else
311: { stc = STCstatic;
312: goto Lstc2;
313: }
314: break;
315:
316: case TOKconst:
317: if (peekNext() == TOKlparen)
318: goto Ldeclaration;
319: stc = STCconst;
320: goto Lstc;
321:
322: case TOKimmutable:
323: if (peekNext() == TOKlparen)
324: goto Ldeclaration;
325: stc = STCimmutable;
326: goto Lstc;
327:
328: case TOKshared:
329: { TOK next = peekNext();
330: if (next == TOKlparen)
331: goto Ldeclaration;
332: if (next == TOKstatic)
333: { TOK next2 = peekNext2();
334: if (next2 == TOKthis)
335: { s = parseSharedStaticCtor();
336: break;
337: }
338: if (next2 == TOKtilde)
339: { s = parseSharedStaticDtor();
340: break;
341: }
342: }
343: stc = STCshared;
344: goto Lstc;
345: }
346:
347: case TOKwild:
348: if (peekNext() == TOKlparen)
349: goto Ldeclaration;
350: stc = STCwild;
351: goto Lstc;
352:
353: case TOKfinal: stc = STCfinal; goto Lstc;
354: case TOKauto: stc = STCauto; goto Lstc;
355: case TOKscope: stc = STCscope; goto Lstc;
356: case TOKoverride: stc = STCoverride; goto Lstc;
357: case TOKabstract: stc = STCabstract; goto Lstc;
358: case TOKsynchronized: stc = STCsynchronized; goto Lstc;
359: case TOKdeprecated: stc = STCdeprecated; goto Lstc;
360: #if DMDV2
361: case TOKnothrow: stc = STCnothrow; goto Lstc;
362: case TOKpure: stc = STCpure; goto Lstc;
363: case TOKref: stc = STCref; goto Lstc;
364: case TOKtls: stc = STCtls; goto Lstc;
365: case TOKgshared: stc = STCgshared; goto Lstc;
366: //case TOKmanifest: stc = STCmanifest; goto Lstc;
367: case TOKat: stc = parseAttribute(); goto Lstc;
368: #endif
369:
370: Lstc:
371: if (storageClass & stc)
372: error("redundant storage class %s", Token::toChars(token.value));
373: composeStorageClass(storageClass | stc);
374: nextToken();
375: Lstc2:
376: storageClass |= stc;
377: switch (token.value)
378: {
379: case TOKconst:
380: case TOKinvariant:
381: case TOKimmutable:
382: case TOKshared:
383: case TOKwild:
384: // If followed by a (, it is not a storage class
385: if (peek(&token)->value == TOKlparen)
386: break;
387: if (token.value == TOKconst)
388: stc = STCconst;
389: else if (token.value == TOKshared)
390: stc = STCshared;
391: else if (token.value == TOKwild)
392: stc = STCwild;
393: else
394: stc = STCimmutable;
395: goto Lstc;
396: case TOKfinal: stc = STCfinal; goto Lstc;
397: case TOKauto: stc = STCauto; goto Lstc;
398: case TOKscope: stc = STCscope; goto Lstc;
399: case TOKoverride: stc = STCoverride; goto Lstc;
400: case TOKabstract: stc = STCabstract; goto Lstc;
401: case TOKsynchronized: stc = STCsynchronized; goto Lstc;
402: case TOKdeprecated: stc = STCdeprecated; goto Lstc;
403: case TOKnothrow: stc = STCnothrow; goto Lstc;
404: case TOKpure: stc = STCpure; goto Lstc;
405: case TOKref: stc = STCref; goto Lstc;
406: case TOKtls: stc = STCtls; goto Lstc;
407: case TOKgshared: stc = STCgshared; goto Lstc;
408: //case TOKmanifest: stc = STCmanifest; goto Lstc;
409: case TOKat: stc = parseAttribute(); goto Lstc;
410: default:
411: break;
412: }
413:
414: /* Look for auto initializers:
415: * storage_class identifier = initializer;
416: */
417: if (token.value == TOKidentifier &&
418: peek(&token)->value == TOKassign)
419: {
420: a = parseAutoDeclarations(storageClass, comment);
421: decldefs->append(a);
422: continue;
423: }
424:
425: /* Look for return type inference for template functions.
426: */
427: Token *tk;
428: if (token.value == TOKidentifier &&
429: (tk = peek(&token))->value == TOKlparen &&
430: skipParens(tk, &tk) &&
431: ((tk = peek(tk)), 1) &&
432: skipAttributes(tk, &tk) &&
433: (tk->value == TOKlparen ||
434: tk->value == TOKlcurly)
435: )
436: {
437: a = parseDeclarations(storageClass, comment);
438: decldefs->append(a);
439: continue;
440: }
441: a = parseBlock();
442: s = new StorageClassDeclaration(storageClass, a);
443: break;
444:
445: case TOKextern:
446: if (peek(&token)->value != TOKlparen)
447: { stc = STCextern;
448: goto Lstc;
449: }
450: {
451: enum LINK linksave = linkage;
452: linkage = parseLinkage();
453: a = parseBlock();
454: s = new LinkDeclaration(linkage, a);
455: linkage = linksave;
456: break;
457: }
458: case TOKprivate: prot = PROTprivate; goto Lprot;
459: case TOKpackage: prot = PROTpackage; goto Lprot;
460: case TOKprotected: prot = PROTprotected; goto Lprot;
461: case TOKpublic: prot = PROTpublic; goto Lprot;
462: case TOKexport: prot = PROTexport; goto Lprot;
463:
464: Lprot:
465: nextToken();
466: switch (token.value)
467: {
468: case TOKprivate:
469: case TOKpackage:
470: case TOKprotected:
471: case TOKpublic:
472: case TOKexport:
473: error("redundant protection attribute");
474: break;
475: }
476: a = parseBlock();
477: s = new ProtDeclaration(prot, a);
478: break;
479:
480: case TOKalign:
481: { unsigned n;
482:
483: s = NULL;
484: nextToken();
485: if (token.value == TOKlparen)
486: {
487: nextToken();
488: if (token.value == TOKint32v && token.uns64value > 0)
489: n = (unsigned)token.uns64value;
490: else
491: { error("positive integer expected, not %s", token.toChars());
492: n = 1;
493: }
494: nextToken();
495: check(TOKrparen);
496: }
497: else
498: n = global.structalign; // default
499:
500: a = parseBlock();
501: s = new AlignDeclaration(n, a);
502: break;
503: }
504:
505: case TOKpragma:
506: { Identifier *ident;
507: Expressions *args = NULL;
508:
509: nextToken();
510: check(TOKlparen);
511: if (token.value != TOKidentifier)
512: { error("pragma(identifier expected");
513: goto Lerror;
514: }
515: ident = token.ident;
516: nextToken();
517: if (token.value == TOKcomma && peekNext() != TOKrparen)
518: args = parseArguments(); // pragma(identifier, args...)
519: else
520: check(TOKrparen); // pragma(identifier)
521:
522: if (token.value == TOKsemicolon)
523: a = NULL;
524: else
525: a = parseBlock();
526: s = new PragmaDeclaration(loc, ident, args, a);
527: break;
528: }
529:
530: case TOKdebug:
531: nextToken();
532: if (token.value == TOKassign)
533: {
534: nextToken();
535: if (token.value == TOKidentifier)
536: s = new DebugSymbol(loc, token.ident);
537: else if (token.value == TOKint32v)
538: s = new DebugSymbol(loc, (unsigned)token.uns64value);
539: else
540: { error("identifier or integer expected, not %s", token.toChars());
541: s = NULL;
542: }
543: nextToken();
544: if (token.value != TOKsemicolon)
545: error("semicolon expected");
546: nextToken();
547: break;
548: }
549:
550: condition = parseDebugCondition();
551: goto Lcondition;
552:
553: case TOKversion:
554: nextToken();
555: if (token.value == TOKassign)
556: {
557: nextToken();
558: if (token.value == TOKidentifier)
559: s = new VersionSymbol(loc, token.ident);
560: else if (token.value == TOKint32v)
561: s = new VersionSymbol(loc, (unsigned)token.uns64value);
562: else
563: { error("identifier or integer expected, not %s", token.toChars());
564: s = NULL;
565: }
566: nextToken();
567: if (token.value != TOKsemicolon)
568: error("semicolon expected");
569: nextToken();
570: break;
571: }
572: condition = parseVersionCondition();
573: goto Lcondition;
574:
575: Lcondition:
576: a = parseBlock();
577: aelse = NULL;
578: if (token.value == TOKelse)
579: { nextToken();
580: aelse = parseBlock();
581: }
582: s = new ConditionalDeclaration(condition, a, aelse);
583: break;
584:
585: case TOKsemicolon: // empty declaration
586: //error("empty declaration");
587: nextToken();
588: continue;
589:
590: default:
591: error("Declaration expected, not '%s'",token.toChars());
592: Lerror:
593: while (token.value != TOKsemicolon && token.value != TOKeof)
594: nextToken();
595: nextToken();
596: s = NULL;
597: continue;
598: }
599: if (s)
600: { decldefs->push(s);
601: addComment(s, comment);
602: }
603: } while (!once);
604: return decldefs;
605: }
606:
607: /*********************************************
608: * Give error on conflicting storage classes.
609: */
610:
611: #if DMDV2
612: void Parser::composeStorageClass(StorageClass stc)
613: {
614: StorageClass u = stc;
615: u &= STCconst | STCimmutable | STCmanifest;
616: if (u & (u - 1))
617: error("conflicting storage class %s", Token::toChars(token.value));
618: u = stc;
619: u &= STCgshared | STCshared | STCtls;
620: if (u & (u - 1))
621: error("conflicting storage class %s", Token::toChars(token.value));
622: u = stc;
623: u &= STCsafe | STCsystem | STCtrusted;
624: if (u & (u - 1))
625: error("conflicting attribute @%s", token.toChars());
626: }
627: #endif
628:
629: /***********************************************
630: * Parse storage class, lexer is on '@'
631: */
632:
633: #if DMDV2
634: StorageClass Parser::parseAttribute()
635: {
636: nextToken();
637: StorageClass stc = 0;
638: if (token.value != TOKidentifier)
639: {
640: error("identifier expected after @, not %s", token.toChars());
641: }
642: else if (token.ident == Id::property)
643: stc = STCproperty;
644: else if (token.ident == Id::safe)
645: stc = STCsafe;
646: else if (token.ident == Id::trusted)
647: stc = STCtrusted;
648: else if (token.ident == Id::system)
649: stc = STCsystem;
650: else if (token.ident == Id::disable)
651: stc = STCdisable;
652: else
653: error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars());
654: return stc;
655: }
656: #endif
657:
658: /***********************************************
659: * Parse const/immutable/shared/inout/nothrow/pure postfix
660: */
661:
662: StorageClass Parser::parsePostfix()
663: {
664: StorageClass stc = 0;
665:
666: while (1)
667: {
668: switch (token.value)
669: {
670: case TOKconst: stc |= STCconst; break;
671: case TOKinvariant:
672: if (!global.params.useDeprecated)
673: error("use of 'invariant' rather than 'immutable' is deprecated");
674: case TOKimmutable: stc |= STCimmutable; break;
675: case TOKshared: stc |= STCshared; break;
676: case TOKwild: stc |= STCwild; break;
677: case TOKnothrow: stc |= STCnothrow; break;
678: case TOKpure: stc |= STCpure; break;
679: case TOKat: stc |= parseAttribute(); break;
680:
681: default:
682: composeStorageClass(stc);
683: return stc;
684: }
685: nextToken();
686: }
687: }
688:
689: /********************************************
690: * Parse declarations after an align, protection, or extern decl.
691: */
692:
693: Dsymbols *Parser::parseBlock()
694: {
695: Dsymbols *a = NULL;
696: Dsymbol *s;
warning C4101: 's' : unreferenced local variable
697:
698: //printf("parseBlock()\n");
699: switch (token.value)
700: {
701: case TOKsemicolon:
702: error("declaration expected following attribute, not ';'");
703: nextToken();
704: break;
705:
706: case TOKeof:
707: error("declaration expected following attribute, not EOF");
708: break;
709:
710: case TOKlcurly:
711: nextToken();
712: a = parseDeclDefs(0);
713: if (token.value != TOKrcurly)
714: { /* { */
715: error("matching '}' expected, not %s", token.toChars());
716: }
717: else
718: nextToken();
719: break;
720:
721: case TOKcolon:
722: nextToken();
723: #if 0
724: a = NULL;
725: #else
726: a = parseDeclDefs(0); // grab declarations up to closing curly bracket
727: #endif
728: break;
729:
730: default:
731: a = parseDeclDefs(1);
732: break;
733: }
734: return a;
735: }
736:
737: /**********************************
738: * Parse a static assertion.
739: */
740:
741: StaticAssert *Parser::parseStaticAssert()
742: {
743: Loc loc = this->loc;
744: Expression *exp;
745: Expression *msg = NULL;
746:
747: //printf("parseStaticAssert()\n");
748: nextToken();
749: check(TOKlparen);
750: exp = parseAssignExp();
751: if (token.value == TOKcomma)
752: { nextToken();
753: msg = parseAssignExp();
754: }
755: check(TOKrparen);
756: check(TOKsemicolon);
757: return new StaticAssert(loc, exp, msg);
758: }
759:
760: /***********************************
761: * Parse typeof(expression).
762: * Current token is on the 'typeof'.
763: */
764:
765: #if DMDV2
766: TypeQualified *Parser::parseTypeof()
767: { TypeQualified *t;
768: Loc loc = this->loc;
769:
770: nextToken();
771: check(TOKlparen);
772: if (token.value == TOKreturn) // typeof(return)
773: {
774: nextToken();
775: t = new TypeReturn(loc);
776: }
777: else
778: { Expression *exp = parseExpression(); // typeof(expression)
779: t = new TypeTypeof(loc, exp);
780: }
781: check(TOKrparen);
782: return t;
783: }
784: #endif
785:
786: /***********************************
787: * Parse extern (linkage)
788: * The parser is on the 'extern' token.
789: */
790:
791: enum LINK Parser::parseLinkage()
792: {
793: enum LINK link = LINKdefault;
794: nextToken();
795: assert(token.value == TOKlparen);
796: nextToken();
797: if (token.value == TOKidentifier)
798: { Identifier *id = token.ident;
799:
800: nextToken();
801: if (id == Id::Windows)
802: link = LINKwindows;
803: else if (id == Id::Pascal)
804: link = LINKpascal;
805: else if (id == Id::D)
806: link = LINKd;
807: else if (id == Id::C)
808: {
809: link = LINKc;
810: if (token.value == TOKplusplus)
811: { link = LINKcpp;
812: nextToken();
813: }
814: }
815: else if (id == Id::System)
816: {
817: #if _WIN32
818: link = LINKwindows;
819: #else
820: link = LINKc;
821: #endif
822: }
823: else
824: {
825: error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
826: link = LINKd;
827: }
828: }
829: else
830: {
831: link = LINKd; // default
832: }
833: check(TOKrparen);
834: return link;
835: }
836:
837: /**************************************
838: * Parse a debug conditional
839: */
840:
841: Condition *Parser::parseDebugCondition()
842: {
843: Condition *c;
844:
845: if (token.value == TOKlparen)
846: {
847: nextToken();
848: unsigned level = 1;
849: Identifier *id = NULL;
850:
851: if (token.value == TOKidentifier)
852: id = token.ident;
853: else if (token.value == TOKint32v)
854: level = (unsigned)token.uns64value;
855: else
856: error("identifier or integer expected, not %s", token.toChars());
857: nextToken();
858: check(TOKrparen);
859: c = new DebugCondition(mod, level, id);
860: }
861: else
862: c = new DebugCondition(mod, 1, NULL);
863: return c;
864:
865: }
866:
867: /**************************************
868: * Parse a version conditional
869: */
870:
871: Condition *Parser::parseVersionCondition()
872: {
873: Condition *c;
874: unsigned level = 1;
875: Identifier *id = NULL;
876:
877: if (token.value == TOKlparen)
878: {
879: nextToken();
880: if (token.value == TOKidentifier)
881: id = token.ident;
882: else if (token.value == TOKint32v)
883: level = (unsigned)token.uns64value;
884: #if DMDV2
885: /* Allow:
886: * version (unittest)
887: * even though unittest is a keyword
888: */
889: else if (token.value == TOKunittest)
890: id = Lexer::idPool(Token::toChars(TOKunittest));
891: #endif
892: else
893: error("identifier or integer expected, not %s", token.toChars());
894: nextToken();
895: check(TOKrparen);
896:
897: }
898: else
899: error("(condition) expected following version");
900: c = new VersionCondition(mod, level, id);
901: return c;
902:
903: }
904:
905: /***********************************************
906: * static if (expression)
907: * body
908: * else
909: * body
910: */
911:
912: Condition *Parser::parseStaticIfCondition()
913: { Expression *exp;
914: Condition *condition;
915: Dsymbols *aif;
warning C4101: 'aif' : unreferenced local variable
916: Dsymbols *aelse;
warning C4101: 'aelse' : unreferenced local variable
917: Loc loc = this->loc;
918:
919: nextToken();
920: if (token.value == TOKlparen)
921: {
922: nextToken();
923: exp = parseAssignExp();
924: check(TOKrparen);
925: }
926: else
927: { error("(expression) expected following static if");
928: exp = NULL;
929: }
930: condition = new StaticIfCondition(loc, exp);
931: return condition;
932: }
933:
934:
935: /*****************************************
936: * Parse a constructor definition:
937: * this(parameters) { body }
938: * or postblit:
939: * this(this) { body }
940: * or constructor template:
941: * this(templateparameters)(parameters) { body }
942: * Current token is 'this'.
943: */
944:
945: Dsymbol *Parser::parseCtor()
946: {
947: Loc loc = this->loc;
948:
949: nextToken();
950: if (token.value == TOKlparen && peek(&token)->value == TOKthis)
951: { // this(this) { ... }
952: nextToken();
953: nextToken();
954: check(TOKrparen);
955: PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
956: parseContracts(f);
957: return f;
958: }
959:
960: /* Look ahead to see if:
961: * this(...)(...)
962: * which is a constructor template
963: */
964: TemplateParameters *tpl = NULL;
965: if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
966: { tpl = parseTemplateParameterList();
967:
968: int varargs;
969: Parameters *parameters = parseParameters(&varargs);
970: StorageClass stc = parsePostfix();
971:
972: Expression *constraint = tpl ? parseConstraint() : NULL;
973:
974: Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
975: CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
976: parseContracts(f);
977:
978: // Wrap a template around it
979: Dsymbols *decldefs = new Dsymbols();
980: decldefs->push(f);
981: TemplateDeclaration *tempdecl =
982: new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs, 0);
983: return tempdecl;
984: }
985:
986: /* Just a regular constructor
987: */
988: int varargs;
989: Parameters *parameters = parseParameters(&varargs);
990: StorageClass stc = parsePostfix();
991: Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
992: CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf);
993: parseContracts(f);
994: return f;
995: }
996:
997: /*****************************************
998: * Parse a postblit definition:
999: * =this() { body }
1000: * Current token is '='.
1001: */
1002:
1003: PostBlitDeclaration *Parser::parsePostBlit()
1004: {
1005: Loc loc = this->loc;
1006:
1007: nextToken();
1008: check(TOKthis);
1009: check(TOKlparen);
1010: check(TOKrparen);
1011:
1012: PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
1013: parseContracts(f);
1014: return f;
1015: }
1016:
1017: /*****************************************
1018: * Parse a destructor definition:
1019: * ~this() { body }
1020: * Current token is '~'.
1021: */
1022:
1023: DtorDeclaration *Parser::parseDtor()
1024: {
1025: DtorDeclaration *f;
1026: Loc loc = this->loc;
1027:
1028: nextToken();
1029: check(TOKthis);
1030: check(TOKlparen);
1031: check(TOKrparen);
1032:
1033: f = new DtorDeclaration(loc, 0);
1034: parseContracts(f);
1035: return f;
1036: }
1037:
1038: /*****************************************
1039: * Parse a static constructor definition:
1040: * static this() { body }
1041: * Current token is 'this'.
1042: */
1043:
1044: StaticCtorDeclaration *Parser::parseStaticCtor()
1045: {
1046: Loc loc = this->loc;
1047:
1048: nextToken();
1049: check(TOKlparen);
1050: check(TOKrparen);
1051:
1052: StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, 0);
1053: parseContracts(f);
1054: return f;
1055: }
1056:
1057: /*****************************************
1058: * Parse a shared static constructor definition:
1059: * shared static this() { body }
1060: * Current token is 'shared'.
1061: */
1062:
1063: SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor()
1064: {
1065: Loc loc = this->loc;
1066:
1067: nextToken();
1068: nextToken();
1069: nextToken();
1070: check(TOKlparen);
1071: check(TOKrparen);
1072:
1073: SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0);
1074: parseContracts(f);
1075: return f;
1076: }
1077:
1078: /*****************************************
1079: * Parse a static destructor definition:
1080: * static ~this() { body }
1081: * Current token is '~'.
1082: */
1083:
1084: StaticDtorDeclaration *Parser::parseStaticDtor()
1085: {
1086: Loc loc = this->loc;
1087:
1088: nextToken();
1089: check(TOKthis);
1090: check(TOKlparen);
1091: check(TOKrparen);
1092:
1093: StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, 0);
1094: parseContracts(f);
1095: return f;
1096: }
1097:
1098: /*****************************************
1099: * Parse a shared static destructor definition:
1100: * shared static ~this() { body }
1101: * Current token is 'shared'.
1102: */
1103:
1104: SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor()
1105: {
1106: Loc loc = this->loc;
1107:
1108: nextToken();
1109: nextToken();
1110: nextToken();
1111: check(TOKthis);
1112: check(TOKlparen);
1113: check(TOKrparen);
1114:
1115: SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0);
1116: parseContracts(f);
1117: return f;
1118: }
1119:
1120: /*****************************************
1121: * Parse an invariant definition:
1122: * invariant() { body }
1123: * Current token is 'invariant'.
1124: */
1125:
1126: InvariantDeclaration *Parser::parseInvariant()
1127: {
1128: InvariantDeclaration *f;
1129: Loc loc = this->loc;
1130:
1131: nextToken();
1132: if (token.value == TOKlparen) // optional ()
1133: {
1134: nextToken();
1135: check(TOKrparen);
1136: }
1137:
1138: f = new InvariantDeclaration(loc, 0);
1139: f->fbody = parseStatement(PScurly);
1140: return f;
1141: }
1142:
1143: /*****************************************
1144: * Parse a unittest definition:
1145: * unittest { body }
1146: * Current token is 'unittest'.
1147: */
1148:
1149: UnitTestDeclaration *Parser::parseUnitTest()
1150: {
1151: UnitTestDeclaration *f;
1152: Statement *body;
1153: Loc loc = this->loc;
1154:
1155: nextToken();
1156:
1157: body = parseStatement(PScurly);
1158:
1159: f = new UnitTestDeclaration(loc, this->loc);
1160: f->fbody = body;
1161: return f;
1162: }
1163:
1164: /*****************************************
1165: * Parse a new definition:
1166: * new(arguments) { body }
1167: * Current token is 'new'.
1168: */
1169:
1170: NewDeclaration *Parser::parseNew()
1171: {
1172: NewDeclaration *f;
1173: Parameters *arguments;
1174: int varargs;
1175: Loc loc = this->loc;
1176:
1177: nextToken();
1178: arguments = parseParameters(&varargs);
1179: f = new NewDeclaration(loc, 0, arguments, varargs);
1180: parseContracts(f);
1181: return f;
1182: }
1183:
1184: /*****************************************
1185: * Parse a delete definition:
1186: * delete(arguments) { body }
1187: * Current token is 'delete'.
1188: */
1189:
1190: DeleteDeclaration *Parser::parseDelete()
1191: {
1192: DeleteDeclaration *f;
1193: Parameters *arguments;
1194: int varargs;
1195: Loc loc = this->loc;
1196:
1197: nextToken();
1198: arguments = parseParameters(&varargs);
1199: if (varargs)
1200: error("... not allowed in delete function parameter list");
1201: f = new DeleteDeclaration(loc, 0, arguments);
1202: parseContracts(f);
1203: return f;
1204: }
1205:
1206: /**********************************************
1207: * Parse parameter list.
1208: */
1209:
1210: Parameters *Parser::parseParameters(int *pvarargs)
1211: {
1212: Parameters *arguments = new Parameters();
warning C6211: Leaking memory 'return value' due to an exception. Consider using a local catch block to clean up memory: Lines: 1212, 1213, 1214, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1226, 1228, 1238, 1239, 1240, 1310, 1311, 1312, 1313, 1315, 1317, 1319, 1322, 1323, 1324, 1330, 1334, 1347, 1348
1213: int varargs = 0;
1214: int hasdefault = 0;
1215:
1216: check(TOKlparen);
1217: while (1)
1218: { Type *tb;
warning C4101: 'tb' : unreferenced local variable
1219: Identifier *ai = NULL;
1220: Type *at;
1221: Parameter *a;
1222: StorageClass storageClass = 0;
1223: StorageClass stc;
1224: Expression *ae;
1225:
1226: for (;1; nextToken())
1227: {
1228: switch (token.value)
1229: {
1230: case TOKrparen:
1231: break;
1232:
1233: case TOKdotdotdot:
1234: varargs = 1;
1235: nextToken();
1236: break;
1237:
1238: case TOKconst:
1239: if (peek(&token)->value == TOKlparen)
1240: goto Ldefault;
1241: stc = STCconst;
1242: goto L2;
1243:
1244: case TOKinvariant:
1245: case TOKimmutable:
1246: if (peek(&token)->value == TOKlparen)
1247: goto Ldefault;
1248: stc = STCimmutable;
1249: goto L2;
1250:
1251: case TOKshared:
1252: if (peek(&token)->value == TOKlparen)
1253: goto Ldefault;
1254: stc = STCshared;
1255: goto L2;
1256:
1257: case TOKwild:
1258: if (peek(&token)->value == TOKlparen)
1259: goto Ldefault;
1260: stc = STCwild;
1261: goto L2;
1262:
1263: case TOKin: stc = STCin; goto L2;
1264: case TOKout: stc = STCout; goto L2;
1265: #if D1INOUT
1266: case TOKinout:
1267: #endif
1268: case TOKref: stc = STCref; goto L2;
1269: case TOKlazy: stc = STClazy; goto L2;
1270: case TOKscope: stc = STCscope; goto L2;
1271: case TOKfinal: stc = STCfinal; goto L2;
1272: case TOKauto: stc = STCauto; goto L2;
1273: L2:
1274: if (storageClass & stc ||
1275: (storageClass & STCin && stc & (STCconst | STCscope)) ||
1276: (stc & STCin && storageClass & (STCconst | STCscope))
1277: )
1278: error("redundant storage class %s", Token::toChars(token.value));
1279: storageClass |= stc;
1280: composeStorageClass(storageClass);
1281: continue;
1282:
1283: #if 0
1284: case TOKstatic: stc = STCstatic; goto L2;
1285: case TOKauto: storageClass = STCauto; goto L4;
1286: case TOKalias: storageClass = STCalias; goto L4;
1287: L4:
1288: nextToken();
1289: if (token.value == TOKidentifier)
1290: { ai = token.ident;
1291: nextToken();
1292: }
1293: else
1294: ai = NULL;
1295: at = NULL; // no type
1296: ae = NULL; // no default argument
1297: if (token.value == TOKassign) // = defaultArg
1298: { nextToken();
1299: ae = parseDefaultInitExp();
1300: hasdefault = 1;
1301: }
1302: else
1303: { if (hasdefault)
1304: error("default argument expected for alias %s",
1305: ai ? ai->toChars() : "");
1306: }
1307: goto L3;
1308: #endif
1309:
1310: default:
1311: Ldefault:
1312: stc = storageClass & (STCin | STCout | STCref | STClazy);
1313: if (stc & (stc - 1)) // if stc is not a power of 2
1314: error("incompatible parameter storage classes");
1315: if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1316: error("out cannot be const");
1317: if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout))
1318: error("out cannot be immutable");
1319: if ((storageClass & STCscope) &&
1320: (storageClass & (STCref | STCout)))
1321: error("scope cannot be ref or out");
1322: at = parseType(&ai);
1323: ae = NULL;
1324: if (token.value == TOKassign) // = defaultArg
1325: { nextToken();
1326: ae = parseDefaultInitExp();
1327: hasdefault = 1;
1328: }
1329: else
1330: { if (hasdefault)
1331: error("default argument expected for %s",
1332: ai ? ai->toChars() : at->toChars());
1333: }
1334: if (token.value == TOKdotdotdot)
1335: { /* This is:
1336: * at ai ...
1337: */
1338:
1339: if (storageClass & (STCout | STCref))
1340: error("variadic argument cannot be out or ref");
1341: varargs = 2;
1342: a = new Parameter(storageClass, at, ai, ae);
1343: arguments->push(a);
1344: nextToken();
1345: break;
1346: }
1347: L3:
warning C4102: 'L3' : unreferenced label
1348: a = new Parameter(storageClass, at, ai, ae);
1349: arguments->push(a);
1350: if (token.value == TOKcomma)
1351: { nextToken();
1352: goto L1;
1353: }
1354: break;
1355: }
1356: break;
1357: }
1358: break;
1359:
1360: L1: ;
1361: }
1362: check(TOKrparen);
1363: *pvarargs = varargs;
1364: return arguments;
1365: }
1366:
1367:
1368: /*************************************
1369: */
1370:
1371: EnumDeclaration *Parser::parseEnum()
1372: { EnumDeclaration *e;
1373: Identifier *id;
1374: Type *memtype;
1375: Loc loc = this->loc;
1376:
1377: //printf("Parser::parseEnum()\n");
1378: nextToken();
1379: if (token.value == TOKidentifier)
1380: { id = token.ident;
1381: nextToken();
1382: }
1383: else
1384: id = NULL;
1385:
1386: if (token.value == TOKcolon)
1387: {
1388: nextToken();
1389: memtype = parseBasicType();
1390: memtype = parseDeclarator(memtype, NULL, NULL);
1391: }
1392: else
1393: memtype = NULL;
1394:
1395: e = new EnumDeclaration(loc, id, memtype);
1396: if (token.value == TOKsemicolon && id)
1397: nextToken();
1398: else if (token.value == TOKlcurly)
1399: {
1400: //printf("enum definition\n");
1401: e->members = new Dsymbols();
1402: nextToken();
1403: unsigned char *comment = token.blockComment;
1404: while (token.value != TOKrcurly)
1405: {
1406: /* Can take the following forms:
1407: * 1. ident
1408: * 2. ident = value
1409: * 3. type ident = value
1410: */
1411:
1412: loc = this->loc;
1413:
1414: Type *type = NULL;
1415: Identifier *ident;
1416: Token *tp = peek(&token);
1417: if (token.value == TOKidentifier &&
1418: (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
1419: {
1420: ident = token.ident;
1421: type = NULL;
1422: nextToken();
1423: }
1424: else
1425: {
1426: type = parseType(&ident, NULL);
1427: if (id || memtype)
1428: error("type only allowed if anonymous enum and no enum type");
1429: }
1430:
1431: Expression *value;
1432: if (token.value == TOKassign)
1433: {
1434: nextToken();
1435: value = parseAssignExp();
1436: }
1437: else
1438: { value = NULL;
1439: if (type)
1440: error("if type, there must be an initializer");
1441: }
1442:
1443: EnumMember *em = new EnumMember(loc, ident, value, type);
1444: e->members->push(em);
1445:
1446: if (token.value == TOKrcurly)
1447: ;
1448: else
1449: { addComment(em, comment);
1450: comment = NULL;
1451: check(TOKcomma);
1452: }
1453: addComment(em, comment);
1454: comment = token.blockComment;
1455: }
1456: nextToken();
1457: }
1458: else
1459: error("enum declaration is invalid");
1460:
1461: //printf("-parseEnum() %s\n", e->toChars());
1462: return e;
1463: }
1464:
1465: /********************************
1466: * Parse struct, union, interface, class.
1467: */
1468:
1469: Dsymbol *Parser::parseAggregate()
1470: { AggregateDeclaration *a = NULL;
1471: int anon = 0;
1472: enum TOK tok;
1473: Identifier *id;
1474: TemplateParameters *tpl = NULL;
1475: Expression *constraint = NULL;
1476:
1477: //printf("Parser::parseAggregate()\n");
1478: tok = token.value;
1479: nextToken();
1480: if (token.value != TOKidentifier)
1481: { id = NULL;
1482: }
1483: else
1484: { id = token.ident;
1485: nextToken();
1486:
1487: if (token.value == TOKlparen)
1488: { // Class template declaration.
1489:
1490: // Gather template parameter list
1491: tpl = parseTemplateParameterList();
1492: constraint = parseConstraint();
1493: }
1494: }
1495:
1496: Loc loc = this->loc;
1497: switch (tok)
1498: { case TOKclass:
1499: case TOKinterface:
1500: {
1501: if (!id)
1502: error("anonymous classes not allowed");
1503:
1504: // Collect base class(es)
1505: BaseClasses *baseclasses = NULL;
1506: if (token.value == TOKcolon)
1507: {
1508: nextToken();
1509: baseclasses = parseBaseClasses();
1510:
1511: if (token.value != TOKlcurly)
1512: error("members expected");
1513: }
1514:
1515: if (tok == TOKclass)
1516: a = new ClassDeclaration(loc, id, baseclasses);
1517: else
1518: a = new InterfaceDeclaration(loc, id, baseclasses);
1519: break;
1520: }
1521:
1522: case TOKstruct:
1523: if (id)
1524: a = new StructDeclaration(loc, id);
1525: else
1526: anon = 1;
1527: break;
1528:
1529: case TOKunion:
1530: if (id)
1531: a = new UnionDeclaration(loc, id);
1532: else
1533: anon = 2;
1534: break;
1535:
1536: default:
1537: assert(0);
1538: break;
1539: }
1540: if (a && token.value == TOKsemicolon)
1541: { nextToken();
1542: }
1543: else if (token.value == TOKlcurly)
1544: {
1545: //printf("aggregate definition\n");
1546: nextToken();
1547: Dsymbols *decl = parseDeclDefs(0);
1548: if (token.value != TOKrcurly)
1549: error("} expected following member declarations in aggregate");
1550: nextToken();
1551: if (anon)
1552: {
1553: /* Anonymous structs/unions are more like attributes.
1554: */
1555: return new AnonDeclaration(loc, anon - 1, decl);
1556: }
1557: else
1558: a->members = decl;
1559: }
1560: else
1561: {
1562: error("{ } expected following aggregate declaration");
1563: a = new StructDeclaration(loc, NULL);
1564: }
1565:
1566: if (tpl)
1567: { // Wrap a template around the aggregate declaration
1568:
1569: Dsymbols *decldefs = new Dsymbols();
1570: decldefs->push(a);
1571: TemplateDeclaration *tempdecl =
1572: new TemplateDeclaration(loc, id, tpl, constraint, decldefs, 0);
1573: return tempdecl;
1574: }
1575:
1576: return a;
1577: }
1578:
1579: /*******************************************
1580: */
1581:
1582: BaseClasses *Parser::parseBaseClasses()
1583: {
1584: BaseClasses *baseclasses = new BaseClasses();
1585:
1586: for (; 1; nextToken())
1587: {
1588: enum PROT protection = PROTpublic;
1589: switch (token.value)
1590: {
1591: case TOKprivate:
1592: protection = PROTprivate;
1593: nextToken();
1594: break;
1595: case TOKpackage:
1596: protection = PROTpackage;
1597: nextToken();
1598: break;
1599: case TOKprotected:
1600: protection = PROTprotected;
1601: nextToken();
1602: break;
1603: case TOKpublic:
1604: protection = PROTpublic;
1605: nextToken();
1606: break;
1607: }
1608: if (token.value == TOKidentifier)
1609: {
1610: BaseClass *b = new BaseClass(parseBasicType(), protection);
1611: baseclasses->push(b);
1612: if (token.value != TOKcomma)
1613: break;
1614: }
1615: else
1616: {
1617: error("base classes expected instead of %s", token.toChars());
1618: return NULL;
1619: }
1620: }
1621: return baseclasses;
1622: }
1623:
1624: /**************************************
1625: * Parse constraint.
1626: * Constraint is of the form:
1627: * if ( ConstraintExpression )
1628: */
1629:
1630: #if DMDV2
1631: Expression *Parser::parseConstraint()
1632: { Expression *e = NULL;
1633:
1634: if (token.value == TOKif)
1635: {
1636: nextToken(); // skip over 'if'
1637: check(TOKlparen);
1638: e = parseExpression();
1639: check(TOKrparen);
1640: }
1641: return e;
1642: }
1643: #endif
1644:
1645: /**************************************
1646: * Parse a TemplateDeclaration.
1647: */
1648:
1649: TemplateDeclaration *Parser::parseTemplateDeclaration(int ismixin)
1650: {
1651: TemplateDeclaration *tempdecl;
1652: Identifier *id;
1653: TemplateParameters *tpl;
1654: Dsymbols *decldefs;
1655: Expression *constraint = NULL;
1656: Loc loc = this->loc;
1657:
1658: nextToken();
1659: if (token.value != TOKidentifier)
1660: { error("TemplateIdentifier expected following template");
1661: goto Lerr;
1662: }
1663: id = token.ident;
1664: nextToken();
1665: tpl = parseTemplateParameterList();
1666: if (!tpl)
1667: goto Lerr;
1668:
1669: constraint = parseConstraint();
1670:
1671: if (token.value != TOKlcurly)
1672: { error("members of template declaration expected");
1673: goto Lerr;
1674: }
1675: else
1676: {
1677: nextToken();
1678: decldefs = parseDeclDefs(0);
1679: if (token.value != TOKrcurly)
1680: { error("template member expected");
1681: goto Lerr;
1682: }
1683: nextToken();
1684: }
1685:
1686: tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
1687: return tempdecl;
1688:
1689: Lerr:
1690: return NULL;
1691: }
1692:
1693: /******************************************
1694: * Parse template parameter list.
1695: * Input:
1696: * flag 0: parsing "( list )"
1697: * 1: parsing non-empty "list )"
1698: */
1699:
1700: TemplateParameters *Parser::parseTemplateParameterList(int flag)
1701: {
1702: TemplateParameters *tpl = new TemplateParameters();
warning C6211: Leaking memory 'tpl' due to an exception. Consider using a local catch block to clean up memory: Lines: 1702, 1704, 1708, 1711, 1712, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1727, 1728, 1766, 1786, 1797, 1821, 1822, 1824, 1825
warning C6211: Leaking memory 'return value' due to an exception. Consider using a local catch block to clean up memory: Lines: 1702, 1704, 1708, 1711, 1712, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1727, 1728, 1766, 1786, 1797, 1821, 1822, 1827, 1832, 1837
1703:
1704: if (!flag && token.value != TOKlparen)
1705: { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1706: goto Lerr;
1707: }
1708: nextToken();
1709:
1710: // Get array of TemplateParameters
1711: if (flag || token.value != TOKrparen)
1712: { int isvariadic = 0;
1713:
1714: while (token.value != TOKrparen)
1715: { TemplateParameter *tp;
1716: Identifier *tp_ident = NULL;
1717: Type *tp_spectype = NULL;
1718: Type *tp_valtype = NULL;
1719: Type *tp_defaulttype = NULL;
1720: Expression *tp_specvalue = NULL;
1721: Expression *tp_defaultvalue = NULL;
1722: Token *t;
1723:
1724: // Get TemplateParameter
1725:
1726: // First, look ahead to see if it is a TypeParameter or a ValueParameter
1727: t = peek(&token);
1728: if (token.value == TOKalias)
1729: { // AliasParameter
1730: nextToken();
1731: Type *spectype = NULL;
1732: if (isDeclaration(&token, 2, TOKreserved, NULL))
1733: {
1734: spectype = parseType(&tp_ident);
1735: }
1736: else
1737: {
1738: if (token.value != TOKidentifier)
1739: { error("identifier expected for template alias parameter");
1740: goto Lerr;
1741: }
1742: tp_ident = token.ident;
1743: nextToken();
1744: }
1745: Object *spec = NULL;
1746: if (token.value == TOKcolon) // : Type
1747: {
1748: nextToken();
1749: if (isDeclaration(&token, 0, TOKreserved, NULL))
1750: spec = parseType();
1751: else
1752: spec = parseCondExp();
1753: }
1754: Object *def = NULL;
1755: if (token.value == TOKassign) // = Type
1756: {
1757: nextToken();
1758: if (isDeclaration(&token, 0, TOKreserved, NULL))
1759: def = parseType();
1760: else
1761: def = parseCondExp();
1762: }
1763: tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
1764: }
1765: else if (t->value == TOKcolon || t->value == TOKassign ||
1766: t->value == TOKcomma || t->value == TOKrparen)
1767: { // TypeParameter
1768: if (token.value != TOKidentifier)
1769: { error("identifier expected for template type parameter");
1770: goto Lerr;
1771: }
1772: tp_ident = token.ident;
1773: nextToken();
1774: if (token.value == TOKcolon) // : Type
1775: {
1776: nextToken();
1777: tp_spectype = parseType();
1778: }
1779: if (token.value == TOKassign) // = Type
1780: {
1781: nextToken();
1782: tp_defaulttype = parseType();
1783: }
1784: tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1785: }
1786: else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1787: { // ident...
1788: if (isvariadic)
1789: error("variadic template parameter must be last");
1790: isvariadic = 1;
1791: tp_ident = token.ident;
1792: nextToken();
1793: nextToken();
1794: tp = new TemplateTupleParameter(loc, tp_ident);
1795: }
1796: #if DMDV2
1797: else if (token.value == TOKthis)
1798: { // ThisParameter
1799: nextToken();
1800: if (token.value != TOKidentifier)
1801: { error("identifier expected for template this parameter");
1802: goto Lerr;
1803: }
1804: tp_ident = token.ident;
1805: nextToken();
1806: if (token.value == TOKcolon) // : Type
1807: {
1808: nextToken();
1809: tp_spectype = parseType();
1810: }
1811: if (token.value == TOKassign) // = Type
1812: {
1813: nextToken();
1814: tp_defaulttype = parseType();
1815: }
1816: tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1817: }
1818: #endif
1819: else
1820: { // ValueParameter
1821: tp_valtype = parseType(&tp_ident);
1822: if (!tp_ident)
1823: {
1824: error("identifier expected for template value parameter");
1825: tp_ident = new Identifier("error", TOKidentifier);
1826: }
1827: if (token.value == TOKcolon) // : CondExpression
1828: {
1829: nextToken();
1830: tp_specvalue = parseCondExp();
1831: }
1832: if (token.value == TOKassign) // = CondExpression
1833: {
1834: nextToken();
1835: tp_defaultvalue = parseDefaultInitExp();
1836: }
1837: tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1838: }
1839: tpl->push(tp);
1840: if (token.value != TOKcomma)
1841: break;
1842: nextToken();
1843: }
1844: }
1845: check(TOKrparen);
1846: Lerr:
1847: return tpl;
1848: }
1849:
1850: /******************************************
1851: * Parse template mixin.
1852: * mixin Foo;
1853: * mixin Foo!(args);
1854: * mixin a.b.c!(args).Foo!(args);
1855: * mixin Foo!(args) identifier;
1856: * mixin typeof(expr).identifier!(args);
1857: */
1858:
1859: Dsymbol *Parser::parseMixin()
1860: {
1861: TemplateMixin *tm;
1862: Identifier *id;
1863: Type *tqual;
1864: Objects *tiargs;
1865: Identifiers *idents;
1866:
1867: //printf("parseMixin()\n");
1868: nextToken();
1869: tqual = NULL;
1870: if (token.value == TOKdot)
1871: {
1872: id = Id::empty;
1873: }
1874: else
1875: {
1876: if (token.value == TOKtypeof)
1877: {
1878: tqual = parseTypeof();
1879: check(TOKdot);
1880: }
1881: if (token.value != TOKidentifier)
1882: {
1883: error("identifier expected, not %s", token.toChars());
1884: id = Id::empty;
1885: }
1886: else
1887: id = token.ident;
1888: nextToken();
1889: }
1890:
1891: idents = new Identifiers();
1892: while (1)
1893: {
1894: tiargs = NULL;
1895: if (token.value == TOKnot)
1896: {
1897: nextToken();
1898: if (token.value == TOKlparen)
1899: tiargs = parseTemplateArgumentList();
1900: else
1901: tiargs = parseTemplateArgument();
1902: }
1903:
1904: if (token.value != TOKdot)
1905: break;
1906:
1907: if (tiargs)
1908: { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1909: tempinst->tiargs = tiargs;
1910: id = (Identifier *)tempinst;
1911: tiargs = NULL;
1912: }
1913: idents->push(id);
1914:
1915: nextToken();
1916: if (token.value != TOKidentifier)
1917: { error("identifier expected following '.' instead of '%s'", token.toChars());
1918: break;
1919: }
1920: id = token.ident;
1921: nextToken();
1922: }
1923: idents->push(id);
1924:
1925: if (token.value == TOKidentifier)
1926: {
1927: id = token.ident;
1928: nextToken();
1929: }
1930: else
1931: id = NULL;
1932:
1933: tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1934: if (token.value != TOKsemicolon)
1935: error("';' expected after mixin");
1936: nextToken();
1937:
1938: return tm;
1939: }
1940:
1941: /******************************************
1942: * Parse template argument list.
1943: * Input:
1944: * current token is opening '('
1945: * Output:
1946: * current token is one after closing ')'
1947: */
1948:
1949: Objects *Parser::parseTemplateArgumentList()
1950: {
1951: //printf("Parser::parseTemplateArgumentList()\n");
1952: if (token.value != TOKlparen && token.value != TOKlcurly)
1953: { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1954: return new Objects();
1955: }
1956: return parseTemplateArgumentList2();
1957: }
1958:
1959: Objects *Parser::parseTemplateArgumentList2()
1960: {
1961: //printf("Parser::parseTemplateArgumentList2()\n");
1962: Objects *tiargs = new Objects();
1963: enum TOK endtok = TOKrparen;
1964: nextToken();
1965:
1966: // Get TemplateArgumentList
1967: while (token.value != endtok)
1968: {
1969: // See if it is an Expression or a Type
1970: if (isDeclaration(&token, 0, TOKreserved, NULL))
1971: { // Template argument is a type
1972: Type *ta = parseType();
1973: tiargs->push(ta);
1974: }
1975: else
1976: { // Template argument is an expression
1977: Expression *ea = parseAssignExp();
1978:
1979: if (ea->op == TOKfunction)
1980: { FuncLiteralDeclaration *fd = ((FuncExp *)ea)->fd;
1981: if (fd->type->ty == Tfunction)
1982: {
1983: TypeFunction *tf = (TypeFunction *)fd->type;
1984: /* If there are parameters that consist of only an identifier,
1985: * rather than assuming the identifier is a type, as we would
1986: * for regular function declarations, assume the identifier
1987: * is the parameter name, and we're building a template with
1988: * a deduced type.
1989: */
1990: TemplateParameters *tpl = NULL;
1991: for (int i = 0; i < tf->parameters->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
1992: { Parameter *param = tf->parameters->tdata()[i];
1993: if (param->ident == NULL &&
1994: param->type &&
1995: param->type->ty == Tident &&
1996: ((TypeIdentifier *)param->type)->idents.dim == 0
1997: )
1998: {
1999: /* Switch parameter type to parameter identifier,
2000: * parameterize with template type parameter _T
2001: */
2002: TypeIdentifier *pt = (TypeIdentifier *)param->type;
2003: param->ident = pt->ident;
2004: Identifier *id = Lexer::uniqueId("__T");
2005: param->type = new TypeIdentifier(pt->loc, id);
2006: TemplateParameter *tp = new TemplateTypeParameter(fd->loc, id, NULL, NULL);
2007: if (!tpl)
2008: tpl = new TemplateParameters();
2009: tpl->push(tp);
2010: }
2011: }
2012:
2013: if (tpl)
2014: { // Wrap a template around function fd
2015: Dsymbols *decldefs = new Dsymbols();
2016: decldefs->push(fd);
2017: TemplateDeclaration *tempdecl =
2018: new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0);
2019: tempdecl->literal = 1; // it's a template 'literal'
2020: tiargs->push(tempdecl);
2021: goto L1;
2022: }
2023: }
2024: }
2025:
2026: tiargs->push(ea);
2027: }
2028: L1:
2029: if (token.value != TOKcomma)
2030: break;
2031: nextToken();
2032: }
2033: check(endtok, "template argument list");
2034: return tiargs;
2035: }
2036:
2037: /*****************************
2038: * Parse single template argument, to support the syntax:
2039: * foo!arg
2040: * Input:
2041: * current token is the arg
2042: */
2043:
2044: Objects *Parser::parseTemplateArgument()
2045: {
2046: //printf("parseTemplateArgument()\n");
2047: Objects *tiargs = new Objects();
warning C6211: Leaking memory 'tiargs' due to an exception. Consider using a local catch block to clean up memory: Lines: 2047, 2048, 2049, 2051, 2052
2048: Type *ta;
2049: switch (token.value)
2050: {
2051: case TOKidentifier:
2052: ta = new TypeIdentifier(loc, token.ident);
2053: goto LabelX;
2054:
2055: case BASIC_TYPES_X(ta):
2056: tiargs->push(ta);
2057: nextToken();
2058: break;
2059:
2060: case TOKint32v:
2061: case TOKuns32v:
2062: case TOKint64v:
2063: case TOKuns64v:
2064: case TOKfloat32v:
2065: case TOKfloat64v:
2066: case TOKfloat80v:
2067: case TOKimaginary32v:
2068: case TOKimaginary64v:
2069: case TOKimaginary80v:
2070: case TOKnull:
2071: case TOKtrue:
2072: case TOKfalse:
2073: case TOKcharv:
2074: case TOKwcharv:
2075: case TOKdcharv:
2076: case TOKstring:
2077: case TOKfile:
2078: case TOKline:
2079: case TOKthis:
2080: { // Template argument is an expression
2081: Expression *ea = parsePrimaryExp();
2082: tiargs->push(ea);
2083: break;
2084: }
2085:
2086: default:
2087: error("template argument expected following !");
2088: break;
2089: }
2090: if (token.value == TOKnot)
2091: error("multiple ! arguments are not allowed");
2092: return tiargs;
2093: }
2094:
2095: Import *Parser::parseImport(Dsymbols *decldefs, int isstatic)
2096: { Import *s;
2097: Identifier *id;
2098: Identifier *aliasid = NULL;
2099: Identifiers *a;
2100: Loc loc;
2101:
2102: //printf("Parser::parseImport()\n");
2103: do
2104: {
2105: L1:
2106: nextToken();
2107: if (token.value != TOKidentifier)
2108: { error("Identifier expected following import");
2109: break;
2110: }
2111:
2112: loc = this->loc;
2113: a = NULL;
2114: id = token.ident;
2115: nextToken();
2116: if (!aliasid && token.value == TOKassign)
2117: {
2118: aliasid = id;
2119: goto L1;
2120: }
2121: while (token.value == TOKdot)
2122: {
2123: if (!a)
2124: a = new Identifiers();
2125: a->push(id);
2126: nextToken();
2127: if (token.value != TOKidentifier)
2128: { error("identifier expected following package");
2129: break;
2130: }
2131: id = token.ident;
2132: nextToken();
2133: }
2134:
2135: s = new Import(loc, a, id, aliasid, isstatic);
2136: decldefs->push(s);
2137:
2138: /* Look for
2139: * : alias=name, alias=name;
2140: * syntax.
2141: */
2142: if (token.value == TOKcolon)
2143: {
2144: do
2145: { Identifier *name;
2146:
2147: nextToken();
2148: if (token.value != TOKidentifier)
2149: { error("Identifier expected following :");
2150: break;
2151: }
2152: Identifier *alias = token.ident;
2153: nextToken();
2154: if (token.value == TOKassign)
2155: {
2156: nextToken();
2157: if (token.value != TOKidentifier)
2158: { error("Identifier expected following %s=", alias->toChars());
2159: break;
2160: }
2161: name = token.ident;
2162: nextToken();
2163: }
2164: else
2165: { name = alias;
2166: alias = NULL;
2167: }
2168: s->addAlias(name, alias);
2169: } while (token.value == TOKcomma);
2170: break; // no comma-separated imports of this form
2171: }
2172:
2173: aliasid = NULL;
2174: } while (token.value == TOKcomma);
2175:
2176: if (token.value == TOKsemicolon)
2177: nextToken();
2178: else
2179: {
2180: error("';' expected");
2181: nextToken();
2182: }
2183:
2184: return NULL;
2185: }
2186:
2187: #if DMDV2
2188: Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
2189: { Type *t;
2190:
2191: /* Take care of the storage class prefixes that
2192: * serve as type attributes:
2193: * const shared, shared const, const, invariant, shared
2194: */
2195: if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen ||
2196: token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen)
2197: {
2198: nextToken();
2199: nextToken();
2200: /* shared const type
2201: */
2202: t = parseType(pident, tpl);
2203: t = t->makeSharedConst();
2204: return t;
2205: }
2206: else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen ||
2207: token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen)
2208: {
2209: nextToken();
2210: nextToken();
2211: /* shared wild type
2212: */
2213: t = parseType(pident, tpl);
2214: t = t->makeSharedWild();
2215: return t;
2216: }
2217: else if (token.value == TOKconst && peekNext() != TOKlparen)
2218: {
2219: nextToken();
2220: /* const type
2221: */
2222: t = parseType(pident, tpl);
2223: t = t->makeConst();
2224: return t;
2225: }
2226: else if ((token.value == TOKinvariant || token.value == TOKimmutable) &&
2227: peekNext() != TOKlparen)
2228: {
2229: nextToken();
2230: /* invariant type
2231: */
2232: t = parseType(pident, tpl);
2233: t = t->makeInvariant();
2234: return t;
2235: }
2236: else if (token.value == TOKshared && peekNext() != TOKlparen)
2237: {
2238: nextToken();
2239: /* shared type
2240: */
2241: t = parseType(pident, tpl);
2242: t = t->makeShared();
2243: return t;
2244: }
2245: else if (token.value == TOKwild && peekNext() != TOKlparen)
2246: {
2247: nextToken();
2248: /* wild type
2249: */
2250: t = parseType(pident, tpl);
2251: t = t->makeWild();
2252: return t;
2253: }
2254: else
2255: t = parseBasicType();
2256: t = parseDeclarator(t, pident, tpl);
2257: return t;
2258: }
2259: #endif
2260:
2261: Type *Parser::parseBasicType()
2262: { Type *t;
2263: Identifier *id;
2264: TypeQualified *tid;
2265:
2266: //printf("parseBasicType()\n");
2267: switch (token.value)
2268: {
2269: case BASIC_TYPES_X(t):
2270: nextToken();
2271: break;
2272:
2273: case TOKidentifier:
2274: id = token.ident;
2275: nextToken();
2276: if (token.value == TOKnot)
2277: { // ident!(template_arguments)
2278: TemplateInstance *tempinst = new TemplateInstance(loc, id);
2279: nextToken();
2280: if (token.value == TOKlparen)
2281: // ident!(template_arguments)
2282: tempinst->tiargs = parseTemplateArgumentList();
2283: else
2284: // ident!template_argument
2285: tempinst->tiargs = parseTemplateArgument();
2286: tid = new TypeInstance(loc, tempinst);
2287: goto Lident2;
2288: }
2289: Lident:
2290: tid = new TypeIdentifier(loc, id);
2291: Lident2:
2292: while (token.value == TOKdot)
2293: { nextToken();
2294: if (token.value != TOKidentifier)
2295: { error("identifier expected following '.' instead of '%s'", token.toChars());
2296: break;
2297: }
2298: id = token.ident;
2299: nextToken();
2300: if (token.value == TOKnot)
2301: {
2302: TemplateInstance *tempinst = new TemplateInstance(loc, id);
2303: nextToken();
2304: if (token.value == TOKlparen)
2305: // ident!(template_arguments)
2306: tempinst->tiargs = parseTemplateArgumentList();
2307: else
2308: // ident!template_argument
2309: tempinst->tiargs = parseTemplateArgument();
2310: tid->addIdent((Identifier *)tempinst);
2311: }
2312: else
2313: tid->addIdent(id);
2314: }
2315: t = tid;
2316: break;
2317:
2318: case TOKdot:
2319: // Leading . as in .foo
2320: id = Id::empty;
2321: goto Lident;
2322:
2323: case TOKtypeof:
2324: // typeof(expression)
2325: tid = parseTypeof();
2326: goto Lident2;
2327:
2328: case TOKconst:
2329: // const(type)
2330: nextToken();
2331: check(TOKlparen);
2332: t = parseType();
2333: check(TOKrparen);
2334: if (t->isShared())
2335: t = t->makeSharedConst();
2336: else
2337: t = t->makeConst();
2338: break;
2339:
2340: case TOKinvariant:
2341: if (!global.params.useDeprecated)
2342: error("use of 'invariant' rather than 'immutable' is deprecated");
2343: case TOKimmutable:
2344: // invariant(type)
2345: nextToken();
2346: check(TOKlparen);
2347: t = parseType();
2348: check(TOKrparen);
2349: t = t->makeInvariant();
2350: break;
2351:
2352: case TOKshared:
2353: // shared(type)
2354: nextToken();
2355: check(TOKlparen);
2356: t = parseType();
2357: check(TOKrparen);
2358: if (t->isConst())
2359: t = t->makeSharedConst();
2360: else if (t->isWild())
2361: t = t->makeSharedWild();
2362: else
2363: t = t->makeShared();
2364: break;
2365:
2366: case TOKwild:
2367: // wild(type)
2368: nextToken();
2369: check(TOKlparen);
2370: t = parseType();
2371: check(TOKrparen);
2372: if (t->isShared())
2373: t = t->makeSharedWild();
2374: else
2375: t = t->makeWild();
2376: break;
2377:
2378: default:
2379: error("basic type expected, not %s", token.toChars());
2380: t = Type::tint32;
2381: break;
2382: }
2383: return t;
2384: }
2385:
2386: /******************************************
2387: * Parse things that follow the initial type t.
2388: * t *
2389: * t []
2390: * t [type]
2391: * t [expression]
2392: * t [expression .. expression]
2393: * t function
2394: * t delegate
2395: */
2396:
2397: Type *Parser::parseBasicType2(Type *t)
2398: {
2399: //printf("parseBasicType2()\n");
2400: while (1)
2401: {
2402: switch (token.value)
2403: {
2404: case TOKmul:
2405: t = new TypePointer(t);
2406: nextToken();
2407: continue;
2408:
2409: case TOKlbracket:
2410: // Handle []. Make sure things like
2411: // int[3][1] a;
2412: // is (array[1] of array[3] of int)
2413: nextToken();
2414: if (token.value == TOKrbracket)
2415: {
2416: t = new TypeDArray(t); // []
2417: nextToken();
2418: }
2419: else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2420: { // It's an associative array declaration
2421:
2422: //printf("it's an associative array\n");
2423: Type *index = parseType(); // [ type ]
2424: t = new TypeAArray(t, index);
2425: check(TOKrbracket);
2426: }
2427: else
2428: {
2429: //printf("it's type[expression]\n");
2430: inBrackets++;
2431: Expression *e = parseAssignExp(); // [ expression ]
2432: if (token.value == TOKslice)
2433: {
2434: nextToken();
2435: Expression *e2 = parseAssignExp(); // [ exp .. exp ]
2436: t = new TypeSlice(t, e, e2);
2437: }
2438: else
2439: t = new TypeSArray(t,e);
2440: inBrackets--;
2441: check(TOKrbracket);
2442: }
2443: continue;
2444:
2445: case TOKdelegate:
2446: case TOKfunction:
2447: { // Handle delegate declaration:
2448: // t delegate(parameter list) nothrow pure
2449: // t function(parameter list) nothrow pure
2450: Parameters *arguments;
2451: int varargs;
2452: enum TOK save = token.value;
2453:
2454: nextToken();
2455: arguments = parseParameters(&varargs);
2456:
2457: StorageClass stc = parsePostfix();
2458: if (stc & (STCconst | STCimmutable | STCshared | STCwild))
2459: error("const/immutable/shared/inout attributes are only valid for non-static member functions");
2460:
2461: TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
2462:
2463: if (save == TOKdelegate)
2464: t = new TypeDelegate(tf);
2465: else
2466: t = new TypePointer(tf); // pointer to function
2467: continue;
2468: }
2469:
2470: default:
2471: return t;
2472: }
2473: assert(0);
2474: }
2475: assert(0);
2476: return NULL;
2477: }
2478:
2479: Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl, StorageClass storage_class)
2480: { Type *ts;
2481:
2482: //printf("parseDeclarator(tpl = %p)\n", tpl);
2483: t = parseBasicType2(t);
2484:
2485: switch (token.value)
2486: {
2487:
2488: case TOKidentifier:
2489: if (pident)
2490: *pident = token.ident;
2491: else
2492: error("unexpected identifer '%s' in declarator", token.ident->toChars());
2493: ts = t;
2494: nextToken();
2495: break;
2496:
2497: case TOKlparen:
2498: if (peekNext() == TOKmul || // like: T (*fp)();
2499: peekNext() == TOKlparen // like: T ((*fp))();
2500: /* || peekNext() == TOKlbracket*/) // like: T ([] a)
2501: {
2502: /* Parse things with parentheses around the identifier, like:
2503: * int (*ident[3])[]
2504: * although the D style would be:
2505: * int[]*[3] ident
2506: */
2507: if (!global.params.useDeprecated)
2508: {
2509: error("C-style function pointer and pointer to array syntax is deprecated. Use 'function' to declare function pointers");
2510: }
2511: nextToken();
2512: ts = parseDeclarator(t, pident);
2513: check(TOKrparen);
2514: break;
2515: }
2516: ts = t;
2517: {
2518: Token *peekt = &token;
2519: /* Completely disallow C-style things like:
2520: * T (a);
2521: * Improve error messages for the common bug of a missing return type
2522: * by looking to see if (a) looks like a parameter list.
2523: */
2524: if (isParameters(&peekt)) {
2525: error("function declaration without return type. "
2526: "(Note that constructors are always named 'this')");
2527: }
2528: else
2529: error("unexpected ( in declarator");
2530: }
2531: break;
2532:
2533: default:
2534: ts = t;
2535: break;
2536: }
2537:
2538: // parse DeclaratorSuffixes
2539: while (1)
2540: {
2541: switch (token.value)
2542: {
2543: #if CARRAYDECL
2544: /* Support C style array syntax:
2545: * int ident[]
2546: * as opposed to D-style:
2547: * int[] ident
2548: */
2549: case TOKlbracket:
2550: { // This is the old C-style post [] syntax.
2551: TypeNext *ta;
2552: nextToken();
2553: if (token.value == TOKrbracket)
2554: { // It's a dynamic array
2555: ta = new TypeDArray(t); // []
2556: nextToken();
2557: }
2558: else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2559: { // It's an associative array
2560:
2561: //printf("it's an associative array\n");
2562: Type *index = parseType(); // [ type ]
2563: check(TOKrbracket);
2564: ta = new TypeAArray(t, index);
2565: }
2566: else
2567: {
2568: //printf("It's a static array\n");
2569: Expression *e = parseAssignExp(); // [ expression ]
2570: ta = new TypeSArray(t, e);
2571: check(TOKrbracket);
2572: }
2573:
2574: /* Insert ta into
2575: * ts -> ... -> t
2576: * so that
2577: * ts -> ... -> ta -> t
2578: */
2579: Type **pt;
2580: for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2581: ;
2582: *pt = ta;
2583: continue;
2584: }
2585: #endif
2586: case TOKlparen:
2587: {
2588: if (tpl)
2589: {
2590: /* Look ahead to see if this is (...)(...),
2591: * i.e. a function template declaration
2592: */
2593: if (peekPastParen(&token)->value == TOKlparen)
2594: {
2595: //printf("function template declaration\n");
2596:
2597: // Gather template parameter list
2598: *tpl = parseTemplateParameterList();
2599: }
2600: }
2601:
2602: int varargs;
2603: Parameters *arguments = parseParameters(&varargs);
2604:
2605: /* Parse const/immutable/shared/inout/nothrow/pure postfix
2606: */
2607: StorageClass stc = parsePostfix();
2608: stc |= storage_class; // merge prefix storage classes
2609: Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
2610:
2611: if (stc & STCconst)
2612: { if (tf->isShared())
2613: tf = tf->makeSharedConst();
2614: else
2615: tf = tf->makeConst();
2616: }
2617: if (stc & STCimmutable)
2618: tf = tf->makeInvariant();
2619: if (stc & STCshared)
2620: { if (tf->isConst())
2621: tf = tf->makeSharedConst();
2622: else
2623: tf = tf->makeShared();
2624: }
2625: if (stc & STCwild)
2626: { if (tf->isShared())
2627: tf = tf->makeSharedWild();
2628: else
2629: tf = tf->makeWild();
2630: }
2631:
2632: /* Insert tf into
2633: * ts -> ... -> t
2634: * so that
2635: * ts -> ... -> tf -> t
2636: */
2637: Type **pt;
2638: for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2639: ;
2640: *pt = tf;
2641: break;
2642: }
2643: }
2644: break;
2645: }
2646:
2647: return ts;
2648: }
2649:
2650: /**********************************
2651: * Parse Declarations.
2652: * These can be:
2653: * 1. declarations at global/class level
2654: * 2. declarations at statement level
2655: * Return array of Declaration *'s.
2656: */
2657:
2658: Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *comment)
2659: {
2660: StorageClass stc;
2661: Type *ts;
2662: Type *t;
2663: Type *tfirst;
2664: Identifier *ident;
2665: Dsymbols *a;
2666: enum TOK tok = TOKreserved;
2667: enum LINK link = linkage;
2668:
2669: //printf("parseDeclarations() %s\n", token.toChars());
2670: if (!comment)
2671: comment = token.blockComment;
2672:
2673: if (storage_class)
2674: { ts = NULL; // infer type
2675: goto L2;
2676: }
2677:
2678: switch (token.value)
2679: {
2680: case TOKalias:
2681: /* Look for:
2682: * alias identifier this;
2683: */
2684: tok = token.value;
2685: nextToken();
2686: if (token.value == TOKidentifier && peek(&token)->value == TOKthis)
2687: {
2688: AliasThis *s = new AliasThis(this->loc, token.ident);
2689: nextToken();
2690: check(TOKthis);
2691: check(TOKsemicolon);
2692: a = new Dsymbols();
2693: a->push(s);
2694: addComment(s, comment);
2695: return a;
2696: }
2697: break;
2698: case TOKtypedef:
2699: tok = token.value;
2700: nextToken();
2701: break;
2702: }
2703:
2704: storage_class = STCundefined;
2705: while (1)
2706: {
2707: switch (token.value)
2708: {
2709: case TOKconst:
2710: if (peek(&token)->value == TOKlparen)
2711: break; // const as type constructor
2712: stc = STCconst; // const as storage class
2713: goto L1;
2714:
2715: case TOKinvariant:
2716: case TOKimmutable:
2717: if (peek(&token)->value == TOKlparen)
2718: break;
2719: stc = STCimmutable;
2720: goto L1;
2721:
2722: case TOKshared:
2723: if (peek(&token)->value == TOKlparen)
2724: break;
2725: stc = STCshared;
2726: goto L1;
2727:
2728: case TOKwild:
2729: if (peek(&token)->value == TOKlparen)
2730: break;
2731: stc = STCwild;
2732: goto L1;
2733:
2734: case TOKstatic: stc = STCstatic; goto L1;
2735: case TOKfinal: stc = STCfinal; goto L1;
2736: case TOKauto: stc = STCauto; goto L1;
2737: case TOKscope: stc = STCscope; goto L1;
2738: case TOKoverride: stc = STCoverride; goto L1;
2739: case TOKabstract: stc = STCabstract; goto L1;
2740: case TOKsynchronized: stc = STCsynchronized; goto L1;
2741: case TOKdeprecated: stc = STCdeprecated; goto L1;
2742: #if DMDV2
2743: case TOKnothrow: stc = STCnothrow; goto L1;
2744: case TOKpure: stc = STCpure; goto L1;
2745: case TOKref: stc = STCref; goto L1;
2746: case TOKtls: stc = STCtls; goto L1;
2747: case TOKgshared: stc = STCgshared; goto L1;
2748: case TOKenum: stc = STCmanifest; goto L1;
2749: case TOKat: stc = parseAttribute(); goto L1;
2750: #endif
2751: L1:
2752: if (storage_class & stc)
2753: error("redundant storage class '%s'", token.toChars());
2754: storage_class = storage_class | stc;
2755: composeStorageClass(storage_class);
2756: nextToken();
2757: continue;
2758:
2759: case TOKextern:
2760: if (peek(&token)->value != TOKlparen)
2761: { stc = STCextern;
2762: goto L1;
2763: }
2764:
2765: link = parseLinkage();
2766: continue;
2767:
2768: default:
2769: break;
2770: }
2771: break;
2772: }
2773:
2774: /* Look for auto initializers:
2775: * storage_class identifier = initializer;
2776: */
2777: if (storage_class &&
2778: token.value == TOKidentifier &&
2779: peek(&token)->value == TOKassign)
2780: {
2781: return parseAutoDeclarations(storage_class, comment);
2782: }
2783:
2784: if (token.value == TOKclass)
2785: {
2786: AggregateDeclaration *s = (AggregateDeclaration *)parseAggregate();
2787: s->storage_class |= storage_class;
2788: Dsymbols *a = new Dsymbols();
warning C6246: Local declaration of 'a' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2665' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 2665
2789: a->push(s);
2790: addComment(s, comment);
2791: return a;
2792: }
2793:
2794: /* Look for return type inference for template functions.
2795: */
2796: {
2797: Token *tk;
2798: if (storage_class &&
2799: token.value == TOKidentifier &&
2800: (tk = peek(&token))->value == TOKlparen &&
2801: skipParens(tk, &tk) &&
2802: peek(tk)->value == TOKlparen)
2803: {
2804: ts = NULL;
2805: }
2806: else
2807: {
2808: ts = parseBasicType();
2809: ts = parseBasicType2(ts);
2810: }
2811: }
2812:
2813: L2:
2814: tfirst = NULL;
2815: a = new Dsymbols();
warning C6211: Leaking memory 'a' due to an exception. Consider using a local catch block to clean up memory: Lines: 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2670, 2671, 2673, 2674, 2675, 2813, 2814, 2815, 2817, 2819, 2820, 2822, 2823, 2824, 2825, 2826, 2830, 2831, 2833, 2875, 2923, 2924, 2930
warning C6211: Leaking memory 'return value' due to an exception. Consider using a local catch block to clean up memory: Lines: 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2670, 2671, 2673, 2674, 2675, 2813, 2814, 2815, 2817, 2819, 2820, 2822, 2823, 2824, 2825, 2826, 2830, 2831, 2833, 2875, 2923, 2924, 2926, 2927, 2930
2816:
2817: while (1)
2818: {
2819: Loc loc = this->loc;
2820: TemplateParameters *tpl = NULL;
2821:
2822: ident = NULL;
2823: t = parseDeclarator(ts, &ident, &tpl, storage_class);
2824: assert(t);
2825: if (!tfirst)
2826: tfirst = t;
2827: else if (t != tfirst)
2828: error("multiple declarations must have the same type, not %s and %s",
2829: tfirst->toChars(), t->toChars());
2830: if (!ident)
2831: error("no identifier for declarator %s", t->toChars());
2832:
2833: if (tok == TOKtypedef || tok == TOKalias)
2834: { Declaration *v;
2835: Initializer *init = NULL;
2836:
2837: if (token.value == TOKassign)
2838: {
2839: nextToken();
2840: init = parseInitializer();
2841: }
2842: if (tok == TOKtypedef)
2843: v = new TypedefDeclaration(loc, ident, t, init);
2844: else
2845: { if (init)
2846: error("alias cannot have initializer");
2847: v = new AliasDeclaration(loc, ident, t);
2848: }
2849: v->storage_class = storage_class;
2850: if (link == linkage)
2851: a->push(v);
2852: else
2853: {
2854: Dsymbols *ax = new Dsymbols();
2855: ax->push(v);
2856: Dsymbol *s = new LinkDeclaration(link, ax);
2857: a->push(s);
2858: }
2859: switch (token.value)
2860: { case TOKsemicolon:
2861: nextToken();
2862: addComment(v, comment);
2863: break;
2864:
2865: case TOKcomma:
2866: nextToken();
2867: addComment(v, comment);
2868: continue;
2869:
2870: default:
2871: error("semicolon expected to close %s declaration", Token::toChars(tok));
2872: break;
2873: }
2874: }
2875: else if (t->ty == Tfunction)
2876: {
2877: TypeFunction *tf = (TypeFunction *)t;
2878: Expression *constraint = NULL;
2879: #if 0
2880: if (Parameter::isTPL(tf->parameters))
2881: {
2882: if (!tpl)
2883: tpl = new TemplateParameters();
2884: }
2885: #endif
2886:
2887: //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
2888:
2889: FuncDeclaration *f =
2890: new FuncDeclaration(loc, 0, ident, storage_class, t);
2891: addComment(f, comment);
2892: if (tpl)
2893: constraint = parseConstraint();
2894: parseContracts(f);
2895: addComment(f, NULL);
2896: Dsymbol *s;
2897: if (link == linkage)
2898: {
2899: s = f;
2900: }
2901: else
2902: {
2903: Dsymbols *ax = new Dsymbols();
2904: ax->push(f);
2905: s = new LinkDeclaration(link, ax);
2906: }
2907: /* A template parameter list means it's a function template
2908: */
2909: if (tpl)
2910: {
2911: // Wrap a template around the function declaration
2912: Dsymbols *decldefs = new Dsymbols();
2913: decldefs->push(s);
2914: TemplateDeclaration *tempdecl =
2915: new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs, 0);
2916: s = tempdecl;
2917: }
2918: addComment(s, comment);
2919: a->push(s);
2920: }
2921: else
2922: {
2923: Initializer *init = NULL;
2924: if (token.value == TOKassign)
2925: {
2926: nextToken();
2927: init = parseInitializer();
2928: }
2929:
2930: VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
2931: v->storage_class = storage_class;
2932: if (link == linkage)
2933: a->push(v);
2934: else
2935: {
2936: Dsymbols *ax = new Dsymbols();
2937: ax->push(v);
2938: Dsymbol *s = new LinkDeclaration(link, ax);
2939: a->push(s);
2940: }
2941: switch (token.value)
2942: { case TOKsemicolon:
2943: nextToken();
2944: addComment(v, comment);
2945: break;
2946:
2947: case TOKcomma:
2948: nextToken();
2949: addComment(v, comment);
2950: continue;
2951:
2952: default:
2953: error("semicolon expected, not '%s'", token.toChars());
2954: break;
2955: }
2956: }
2957: break;
2958: }
2959: return a;
2960: }
2961:
2962: /*****************************************
2963: * Parse auto declarations of the form:
2964: * storageClass ident = init, ident = init, ... ;
2965: * and return the array of them.
2966: * Starts with token on the first ident.
2967: * Ends with scanner past closing ';'
2968: */
2969:
2970: #if DMDV2
2971: Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment)
2972: {
2973: Dsymbols *a = new Dsymbols;
warning C6211: Leaking memory 'a' due to an exception. Consider using a local catch block to clean up memory: Lines: 2973, 2975, 2977, 2978, 2979, 2980, 2981, 2982
2974:
2975: while (1)
2976: {
2977: Identifier *ident = token.ident;
2978: nextToken(); // skip over ident
2979: assert(token.value == TOKassign);
2980: nextToken(); // skip over '='
2981: Initializer *init = parseInitializer();
2982: VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2983: v->storage_class = storageClass;
2984: a->push(v);
2985: if (token.value == TOKsemicolon)
2986: {
2987: nextToken();
2988: addComment(v, comment);
2989: }
2990: else if (token.value == TOKcomma)
2991: {
2992: nextToken();
2993: if (token.value == TOKidentifier &&
2994: peek(&token)->value == TOKassign)
2995: {
2996: addComment(v, comment);
2997: continue;
2998: }
2999: else
3000: error("Identifier expected following comma");
3001: }
3002: else
3003: error("semicolon expected following auto declaration, not '%s'", token.toChars());
3004: break;
3005: }
3006: return a;
3007: }
3008: #endif
3009:
3010: /*****************************************
3011: * Parse contracts following function declaration.
3012: */
3013:
3014: void Parser::parseContracts(FuncDeclaration *f)
3015: {
3016: enum LINK linksave = linkage;
3017:
3018: // The following is irrelevant, as it is overridden by sc->linkage in
3019: // TypeFunction::semantic
3020: linkage = LINKd; // nested functions have D linkage
3021: L1:
3022: switch (token.value)
3023: {
3024: case TOKlcurly:
3025: if (f->frequire || f->fensure)
3026: error("missing body { ... } after in or out");
3027: f->fbody = parseStatement(PSsemi);
3028: f->endloc = endloc;
3029: break;
3030:
3031: case TOKbody:
3032: nextToken();
3033: f->fbody = parseStatement(PScurly);
3034: f->endloc = endloc;
3035: break;
3036:
3037: case TOKsemicolon:
3038: if (f->frequire || f->fensure)
3039: error("missing body { ... } after in or out");
3040: nextToken();
3041: break;
3042:
3043: #if 0 // Do we want this for function declarations, so we can do:
3044: // int x, y, foo(), z;
3045: case TOKcomma:
3046: nextToken();
3047: continue;
3048: #endif
3049:
3050: #if 0 // Dumped feature
3051: case TOKthrow:
3052: if (!f->fthrows)
3053: f->fthrows = new Types();
3054: nextToken();
3055: check(TOKlparen);
3056: while (1)
3057: {
3058: Type *tb = parseBasicType();
3059: f->fthrows->push(tb);
3060: if (token.value == TOKcomma)
3061: { nextToken();
3062: continue;
3063: }
3064: break;
3065: }
3066: check(TOKrparen);
3067: goto L1;
3068: #endif
3069:
3070: case TOKin:
3071: nextToken();
3072: if (f->frequire)
3073: error("redundant 'in' statement");
3074: f->frequire = parseStatement(PScurly | PSscope);
3075: goto L1;
3076:
3077: case TOKout:
3078: // parse: out (identifier) { statement }
3079: nextToken();
3080: if (token.value != TOKlcurly)
3081: {
3082: check(TOKlparen);
3083: if (token.value != TOKidentifier)
3084: error("(identifier) following 'out' expected, not %s", token.toChars());
3085: f->outId = token.ident;
3086: nextToken();
3087: check(TOKrparen);
3088: }
3089: if (f->fensure)
3090: error("redundant 'out' statement");
3091: f->fensure = parseStatement(PScurly | PSscope);
3092: goto L1;
3093:
3094: default:
3095: if (!f->frequire && !f->fensure) // allow these even with no body
3096: error("semicolon expected following function declaration");
3097: break;
3098: }
3099: linkage = linksave;
3100: }
3101:
3102: /*****************************************
3103: * Parse initializer for variable declaration.
3104: */
3105:
3106: Initializer *Parser::parseInitializer()
3107: {
3108: StructInitializer *is;
3109: ArrayInitializer *ia;
3110: ExpInitializer *ie;
3111: Expression *e;
3112: Identifier *id;
3113: Initializer *value;
3114: int comma;
3115: Loc loc = this->loc;
3116: Token *t;
3117: int braces;
3118: int brackets;
3119:
3120: switch (token.value)
3121: {
3122: case TOKlcurly:
3123: /* Scan ahead to see if it is a struct initializer or
3124: * a function literal.
3125: * If it contains a ';', it is a function literal.
3126: * Treat { } as a struct initializer.
3127: */
3128: braces = 1;
3129: for (t = peek(&token); 1; t = peek(t))
3130: {
3131: switch (t->value)
3132: {
3133: case TOKsemicolon:
3134: case TOKreturn:
3135: goto Lexpression;
3136:
3137: case TOKlcurly:
3138: braces++;
3139: continue;
3140:
3141: case TOKrcurly:
3142: if (--braces == 0)
3143: break;
3144: continue;
3145:
3146: case TOKeof:
3147: break;
3148:
3149: default:
3150: continue;
3151: }
3152: break;
3153: }
3154:
3155: is = new StructInitializer(loc);
3156: nextToken();
3157: comma = 0;
3158: while (1)
3159: {
3160: switch (token.value)
3161: {
3162: case TOKidentifier:
3163: if (comma == 1)
3164: error("comma expected separating field initializers");
3165: t = peek(&token);
3166: if (t->value == TOKcolon)
3167: {
3168: id = token.ident;
3169: nextToken();
3170: nextToken(); // skip over ':'
3171: }
3172: else
3173: { id = NULL;
3174: }
3175: value = parseInitializer();
3176: is->addInit(id, value);
3177: comma = 1;
3178: continue;
3179:
3180: case TOKcomma:
3181: nextToken();
3182: comma = 2;
3183: continue;
3184:
3185: case TOKrcurly: // allow trailing comma's
3186: nextToken();
3187: break;
3188:
3189: case TOKeof:
3190: error("found EOF instead of initializer");
3191: break;
3192:
3193: default:
3194: if (comma == 1)
3195: error("comma expected separating field initializers");
3196: value = parseInitializer();
3197: is->addInit(NULL, value);
3198: comma = 1;
3199: continue;
3200: //error("found '%s' instead of field initializer", token.toChars());
3201: //break;
3202: }
3203: break;
3204: }
3205: return is;
3206:
3207: case TOKlbracket:
3208: /* Scan ahead to see if it is an array initializer or
3209: * an expression.
3210: * If it ends with a ';' ',' or '}', it is an array initializer.
3211: */
3212: brackets = 1;
3213: for (t = peek(&token); 1; t = peek(t))
3214: {
3215: switch (t->value)
3216: {
3217: case TOKlbracket:
3218: brackets++;
3219: continue;
3220:
3221: case TOKrbracket:
3222: if (--brackets == 0)
3223: { t = peek(t);
3224: if (t->value != TOKsemicolon &&
3225: t->value != TOKcomma &&
3226: t->value != TOKrbracket &&
3227: t->value != TOKrcurly)
3228: goto Lexpression;
3229: break;
3230: }
3231: continue;
3232:
3233: case TOKeof:
3234: break;
3235:
3236: default:
3237: continue;
3238: }
3239: break;
3240: }
3241:
3242: ia = new ArrayInitializer(loc);
3243: nextToken();
3244: comma = 0;
3245: while (1)
3246: {
3247: switch (token.value)
3248: {
3249: default:
3250: if (comma == 1)
3251: { error("comma expected separating array initializers, not %s", token.toChars());
3252: nextToken();
3253: break;
3254: }
3255: e = parseAssignExp();
3256: if (!e)
3257: break;
3258: if (token.value == TOKcolon)
3259: {
3260: nextToken();
3261: value = parseInitializer();
3262: }
3263: else
3264: { value = new ExpInitializer(e->loc, e);
3265: e = NULL;
3266: }
3267: ia->addInit(e, value);
3268: comma = 1;
3269: continue;
3270:
3271: case TOKlcurly:
3272: case TOKlbracket:
3273: if (comma == 1)
3274: error("comma expected separating array initializers, not %s", token.toChars());
3275: value = parseInitializer();
3276: ia->addInit(NULL, value);
3277: comma = 1;
3278: continue;
3279:
3280: case TOKcomma:
3281: nextToken();
3282: comma = 2;
3283: continue;
3284:
3285: case TOKrbracket: // allow trailing comma's
3286: nextToken();
3287: break;
3288:
3289: case TOKeof:
3290: error("found '%s' instead of array initializer", token.toChars());
3291: break;
3292: }
3293: break;
3294: }
3295: return ia;
3296:
3297: case TOKvoid:
3298: t = peek(&token);
3299: if (t->value == TOKsemicolon || t->value == TOKcomma)
3300: {
3301: nextToken();
3302: return new VoidInitializer(loc);
3303: }
3304: goto Lexpression;
3305:
3306: default:
3307: Lexpression:
3308: e = parseAssignExp();
3309: ie = new ExpInitializer(loc, e);
3310: return ie;
3311: }
3312: }
3313:
3314: /*****************************************
3315: * Parses default argument initializer expression that is an assign expression,
3316: * with special handling for __FILE__ and __LINE__.
3317: */
3318:
3319: #if DMDV2
3320: Expression *Parser::parseDefaultInitExp()
3321: {
3322: if (token.value == TOKfile ||
3323: token.value == TOKline)
3324: {
3325: Token *t = peek(&token);
3326: if (t->value == TOKcomma || t->value == TOKrparen)
3327: { Expression *e;
3328:
3329: if (token.value == TOKfile)
3330: e = new FileInitExp(loc);
3331: else
3332: e = new LineInitExp(loc);
3333: nextToken();
3334: return e;
3335: }
3336: }
3337:
3338: Expression *e = parseAssignExp();
3339: return e;
3340: }
3341: #endif
3342:
3343: /*****************************************
3344: * Input:
3345: * flags PSxxxx
3346: */
3347:
3348: Statement *Parser::parseStatement(int flags)
3349: { Statement *s;
3350: Token *t;
3351: Condition *condition;
3352: Statement *ifbody;
3353: Statement *elsebody;
3354: bool isfinal;
3355: Loc loc = this->loc;
3356:
3357: //printf("parseStatement()\n");
3358:
3359: if (flags & PScurly && token.value != TOKlcurly)
3360: error("statement expected to be { }, not %s", token.toChars());
3361:
3362: switch (token.value)
3363: {
3364: case TOKidentifier:
3365: /* A leading identifier can be a declaration, label, or expression.
3366: * The easiest case to check first is label:
3367: */
3368: t = peek(&token);
3369: if (t->value == TOKcolon)
3370: { // It's a label
3371:
3372: Identifier *ident = token.ident;
3373: nextToken();
3374: nextToken();
3375: s = parseStatement(PSsemi);
3376: s = new LabelStatement(loc, ident, s);
3377: break;
3378: }
3379: // fallthrough to TOKdot
3380: case TOKdot:
3381: case TOKtypeof:
3382: if (isDeclaration(&token, 2, TOKreserved, NULL))
3383: goto Ldeclaration;
3384: else
3385: goto Lexp;
3386: break;
3387:
3388: case TOKassert:
3389: case TOKthis:
3390: case TOKsuper:
3391: case TOKint32v:
3392: case TOKuns32v:
3393: case TOKint64v:
3394: case TOKuns64v:
3395: case TOKfloat32v:
3396: case TOKfloat64v:
3397: case TOKfloat80v:
3398: case TOKimaginary32v:
3399: case TOKimaginary64v:
3400: case TOKimaginary80v:
3401: case TOKcharv:
3402: case TOKwcharv:
3403: case TOKdcharv:
3404: case TOKnull:
3405: case TOKtrue:
3406: case TOKfalse:
3407: case TOKstring:
3408: case TOKlparen:
3409: case TOKcast:
3410: case TOKmul:
3411: case TOKmin:
3412: case TOKadd:
3413: case TOKtilde:
3414: case TOKnot:
3415: case TOKplusplus:
3416: case TOKminusminus:
3417: case TOKnew:
3418: case TOKdelete:
3419: case TOKdelegate:
3420: case TOKfunction:
3421: case TOKtypeid:
3422: case TOKis:
3423: case TOKlbracket:
3424: #if DMDV2
3425: case TOKtraits:
3426: case TOKfile:
3427: case TOKline:
3428: #endif
3429: Lexp:
3430: {
3431: Expression *exp = parseExpression();
3432: check(TOKsemicolon, "statement");
3433: s = new ExpStatement(loc, exp);
3434: break;
3435: }
3436:
3437: case TOKstatic:
3438: { // Look ahead to see if it's static assert() or static if()
3439:
3440: Token *t = peek(&token);
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3441: if (t->value == TOKassert)
3442: {
3443: nextToken();
3444: s = new StaticAssertStatement(parseStaticAssert());
3445: break;
3446: }
3447: if (t->value == TOKif)
3448: {
3449: nextToken();
3450: condition = parseStaticIfCondition();
3451: goto Lcondition;
3452: }
3453: if (t->value == TOKstruct || t->value == TOKunion || t->value == TOKclass)
3454: {
3455: nextToken();
3456: Dsymbols *a = parseBlock();
3457: Dsymbol *d = new StorageClassDeclaration(STCstatic, a);
3458: s = new ExpStatement(loc, d);
3459: if (flags & PSscope)
3460: s = new ScopeStatement(loc, s);
3461: break;
3462: }
3463: if (t->value == TOKimport)
3464: { nextToken();
3465: Dsymbols *imports = new Dsymbols();
3466: parseImport(imports, 1); // static import ...
3467: s = new ImportStatement(loc, imports);
3468: break;
3469: }
3470: goto Ldeclaration;
3471: }
3472:
3473: case TOKfinal:
3474: if (peekNext() == TOKswitch)
3475: {
3476: nextToken();
3477: isfinal = TRUE;
3478: goto Lswitch;
3479: }
3480: goto Ldeclaration;
3481:
3482: case BASIC_TYPES:
3483: case TOKtypedef:
3484: case TOKalias:
3485: case TOKconst:
3486: case TOKauto:
3487: case TOKextern:
3488: case TOKinvariant:
3489: #if DMDV2
3490: case TOKimmutable:
3491: case TOKshared:
3492: case TOKwild:
3493: case TOKnothrow:
3494: case TOKpure:
3495: case TOKref:
3496: case TOKtls:
3497: case TOKgshared:
3498: case TOKat:
3499: #endif
3500: // case TOKtypeof:
3501: Ldeclaration:
3502: { Dsymbols *a;
3503:
3504: a = parseDeclarations(STCundefined, NULL);
3505: if (a->dim > 1)
3506: {
3507: Statements *as = new Statements();
warning C6211: Leaking memory 'as' due to an exception. Consider using a local catch block to clean up memory: Lines: 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3359, 3362, 3364, 3368, 3369, 3380, 3381, 3382, 3383, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3501, 3502, 3504, 3505, 3507, 3508, 3509, 3511, 3512
3508: as->reserve(a->dim);
3509: for (int i = 0; i < a->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
3510: {
3511: Dsymbol *d = a->tdata()[i];
3512: s = new ExpStatement(loc, d);
3513: as->push(s);
3514: }
3515: s = new CompoundDeclarationStatement(loc, as);
3516: }
3517: else if (a->dim == 1)
3518: {
3519: Dsymbol *d = a->tdata()[0];
3520: s = new ExpStatement(loc, d);
3521: }
3522: else
3523: assert(0);
3524: if (flags & PSscope)
3525: s = new ScopeStatement(loc, s);
3526: break;
3527: }
3528:
3529: case TOKstruct:
3530: case TOKunion:
3531: case TOKclass:
3532: case TOKinterface:
3533: { Dsymbol *d;
3534:
3535: d = parseAggregate();
3536: s = new ExpStatement(loc, d);
3537: break;
3538: }
3539:
3540: case TOKenum:
3541: { /* Determine if this is a manifest constant declaration,
3542: * or a conventional enum.
3543: */
3544: Dsymbol *d;
3545: Token *t = peek(&token);
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3546: if (t->value == TOKlcurly || t->value == TOKcolon)
3547: d = parseEnum();
3548: else if (t->value != TOKidentifier)
3549: goto Ldeclaration;
3550: else
3551: {
3552: t = peek(t);
3553: if (t->value == TOKlcurly || t->value == TOKcolon ||
3554: t->value == TOKsemicolon)
3555: d = parseEnum();
3556: else
3557: goto Ldeclaration;
3558: }
3559: s = new ExpStatement(loc, d);
3560: break;
3561: }
3562:
3563: case TOKmixin:
3564: { t = peek(&token);
3565: if (t->value == TOKlparen)
3566: { // mixin(string)
3567: Expression *e = parseAssignExp();
3568: check(TOKsemicolon);
3569: if (e->op == TOKmixin)
3570: {
3571: CompileExp *cpe = (CompileExp *)e;
3572: s = new CompileStatement(loc, cpe->e1);
3573: }
3574: else
3575: {
3576: s = new ExpStatement(loc, e);
3577: }
3578: break;
3579: }
3580: Dsymbol *d = parseMixin();
3581: s = new ExpStatement(loc, d);
3582: break;
3583: }
3584:
3585: case TOKlcurly:
3586: {
3587: nextToken();
3588: //if (token.value == TOKsemicolon)
3589: //error("use '{ }' for an empty statement, not a ';'");
3590: Statements *statements = new Statements();
3591: while (token.value != TOKrcurly && token.value != TOKeof)
3592: {
3593: statements->push(parseStatement(PSsemi | PScurlyscope));
3594: }
3595: endloc = this->loc;
3596: s = new CompoundStatement(loc, statements);
3597: if (flags & (PSscope | PScurlyscope))
3598: s = new ScopeStatement(loc, s);
3599: check(TOKrcurly, "compound statement");
3600: break;
3601: }
3602:
3603: case TOKwhile:
3604: { Expression *condition;
warning C6246: Local declaration of 'condition' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3351' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3351
3605: Statement *body;
3606:
3607: nextToken();
3608: check(TOKlparen);
3609: condition = parseExpression();
3610: check(TOKrparen);
3611: body = parseStatement(PSscope);
3612: s = new WhileStatement(loc, condition, body);
3613: break;
3614: }
3615:
3616: case TOKsemicolon:
3617: if (!(flags & PSsemi))
3618: error("use '{ }' for an empty statement, not a ';'");
3619: nextToken();
3620: s = new ExpStatement(loc, (Expression *)NULL);
3621: break;
3622:
3623: case TOKdo:
3624: { Statement *body;
3625: Expression *condition;
warning C6246: Local declaration of 'condition' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3351' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3351
3626:
3627: nextToken();
3628: body = parseStatement(PSscope);
3629: check(TOKwhile);
3630: check(TOKlparen);
3631: condition = parseExpression();
3632: check(TOKrparen);
3633: s = new DoStatement(loc, body, condition);
3634: break;
3635: }
3636:
3637: case TOKfor:
3638: {
3639: Statement *init;
3640: Expression *condition;
warning C6246: Local declaration of 'condition' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3351' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3351
3641: Expression *increment;
3642: Statement *body;
3643:
3644: nextToken();
3645: check(TOKlparen);
3646: if (token.value == TOKsemicolon)
3647: { init = NULL;
3648: nextToken();
3649: }
3650: else
3651: { init = parseStatement(0);
3652: }
3653: if (token.value == TOKsemicolon)
3654: {
3655: condition = NULL;
3656: nextToken();
3657: }
3658: else
3659: {
3660: condition = parseExpression();
3661: check(TOKsemicolon, "for condition");
3662: }
3663: if (token.value == TOKrparen)
3664: { increment = NULL;
3665: nextToken();
3666: }
3667: else
3668: { increment = parseExpression();
3669: check(TOKrparen);
3670: }
3671: body = parseStatement(PSscope);
3672: s = new ForStatement(loc, init, condition, increment, body);
3673: if (init)
3674: s = new ScopeStatement(loc, s);
3675: break;
3676: }
3677:
3678: case TOKforeach:
3679: case TOKforeach_reverse:
3680: {
3681: enum TOK op = token.value;
3682:
3683: nextToken();
3684: check(TOKlparen);
3685:
3686: Parameters *arguments = new Parameters();
3687:
3688: while (1)
3689: {
3690: Identifier *ai = NULL;
3691: Type *at;
3692:
3693: StorageClass storageClass = 0;
3694: if (token.value == TOKref
3695: #if D1INOUT
3696: || token.value == TOKinout
3697: #endif
3698: )
3699: { storageClass = STCref;
3700: nextToken();
3701: }
3702: if (token.value == TOKidentifier)
3703: {
3704: Token *t = peek(&token);
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3705: if (t->value == TOKcomma || t->value == TOKsemicolon)
3706: { ai = token.ident;
3707: at = NULL; // infer argument type
3708: nextToken();
3709: goto Larg;
3710: }
3711: }
3712: at = parseType(&ai);
3713: if (!ai)
3714: error("no identifier for declarator %s", at->toChars());
3715: Larg:
3716: Parameter *a = new Parameter(storageClass, at, ai, NULL);
3717: arguments->push(a);
3718: if (token.value == TOKcomma)
3719: { nextToken();
3720: continue;
3721: }
3722: break;
3723: }
3724: check(TOKsemicolon);
3725:
3726: Expression *aggr = parseExpression();
3727: if (token.value == TOKslice && arguments->dim == 1)
3728: {
3729: Parameter *a = arguments->tdata()[0];
3730: delete arguments;
3731: nextToken();
3732: Expression *upr = parseExpression();
3733: check(TOKrparen);
3734: Statement *body = parseStatement(0);
3735: s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3736: }
3737: else
3738: {
3739: check(TOKrparen);
3740: Statement *body = parseStatement(0);
3741: s = new ForeachStatement(loc, op, arguments, aggr, body);
3742: }
3743: break;
3744: }
3745:
3746: case TOKif:
3747: { Parameter *arg = NULL;
3748: Expression *condition;
warning C6246: Local declaration of 'condition' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3351' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3351
3749: Statement *ifbody;
warning C6246: Local declaration of 'ifbody' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3352' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3352
3750: Statement *elsebody;
warning C6246: Local declaration of 'elsebody' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3353' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3353
3751:
3752: nextToken();
3753: check(TOKlparen);
3754:
3755: if (token.value == TOKauto)
3756: {
3757: nextToken();
3758: if (token.value == TOKidentifier)
3759: {
3760: Token *t = peek(&token);
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3761: if (t->value == TOKassign)
3762: {
3763: arg = new Parameter(0, NULL, token.ident, NULL);
3764: nextToken();
3765: nextToken();
3766: }
3767: else
3768: { error("= expected following auto identifier");
3769: goto Lerror;
3770: }
3771: }
3772: else
3773: { error("identifier expected following auto");
3774: goto Lerror;
3775: }
3776: }
3777: else if (isDeclaration(&token, 2, TOKassign, NULL))
3778: {
3779: Type *at;
3780: Identifier *ai;
3781:
3782: at = parseType(&ai);
3783: check(TOKassign);
3784: arg = new Parameter(0, at, ai, NULL);
3785: }
3786:
3787: // Check for " ident;"
3788: else if (token.value == TOKidentifier)
3789: {
3790: Token *t = peek(&token);
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3791: if (t->value == TOKcomma || t->value == TOKsemicolon)
3792: {
3793: arg = new Parameter(0, NULL, token.ident, NULL);
3794: nextToken();
3795: nextToken();
3796: if (1 || !global.params.useDeprecated)
3797: error("if (v; e) is deprecated, use if (auto v = e)");
3798: }
3799: }
3800:
3801: condition = parseExpression();
3802: check(TOKrparen);
3803: ifbody = parseStatement(PSscope);
3804: if (token.value == TOKelse)
3805: {
3806: nextToken();
3807: elsebody = parseStatement(PSscope);
3808: }
3809: else
3810: elsebody = NULL;
3811: if (condition && ifbody)
3812: s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3813: else
3814: s = NULL; // don't propagate parsing errors
3815: break;
3816: }
3817:
3818: case TOKscope:
3819: if (peek(&token)->value != TOKlparen)
3820: goto Ldeclaration; // scope used as storage class
3821: nextToken();
3822: check(TOKlparen);
3823: if (token.value != TOKidentifier)
3824: { error("scope identifier expected");
3825: goto Lerror;
3826: }
3827: else
3828: { TOK t = TOKon_scope_exit;
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
3829: Identifier *id = token.ident;
3830:
3831: if (id == Id::exit)
3832: t = TOKon_scope_exit;
3833: else if (id == Id::failure)
3834: t = TOKon_scope_failure;
3835: else if (id == Id::success)
3836: t = TOKon_scope_success;
3837: else
3838: error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3839: nextToken();
3840: check(TOKrparen);
3841: Statement *st = parseStatement(PScurlyscope);
3842: s = new OnScopeStatement(loc, t, st);
3843: break;
3844: }
3845:
3846: case TOKdebug:
3847: nextToken();
3848: condition = parseDebugCondition();
3849: goto Lcondition;
3850:
3851: case TOKversion:
3852: nextToken();
3853: condition = parseVersionCondition();
3854: goto Lcondition;
3855:
3856: Lcondition:
3857: ifbody = parseStatement(0 /*PSsemi*/);
3858: elsebody = NULL;
3859: if (token.value == TOKelse)
3860: {
3861: nextToken();
3862: elsebody = parseStatement(0 /*PSsemi*/);
3863: }
3864: s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3865: break;
3866:
3867: case TOKpragma:
3868: { Identifier *ident;
3869: Expressions *args = NULL;
3870: Statement *body;
3871:
3872: nextToken();
3873: check(TOKlparen);
3874: if (token.value != TOKidentifier)
3875: { error("pragma(identifier expected");
3876: goto Lerror;
3877: }
3878: ident = token.ident;
3879: nextToken();
3880: if (token.value == TOKcomma && peekNext() != TOKrparen)
3881: args = parseArguments(); // pragma(identifier, args...);
3882: else
3883: check(TOKrparen); // pragma(identifier);
3884: if (token.value == TOKsemicolon)
3885: { nextToken();
3886: body = NULL;
3887: }
3888: else
3889: body = parseStatement(PSsemi);
3890: s = new PragmaStatement(loc, ident, args, body);
3891: break;
3892: }
3893:
3894: case TOKswitch:
3895: isfinal = FALSE;
3896: goto Lswitch;
3897:
3898: Lswitch:
3899: {
3900: nextToken();
3901: check(TOKlparen);
3902: Expression *condition = parseExpression();
warning C6246: Local declaration of 'condition' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3351' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3351
3903: check(TOKrparen);
3904: Statement *body = parseStatement(PSscope);
3905: s = new SwitchStatement(loc, condition, body, isfinal);
3906: break;
3907: }
3908:
3909: case TOKcase:
3910: { Expression *exp;
3911: Statements *statements;
3912: Expressions cases; // array of Expression's
3913: Expression *last = NULL;
3914:
3915: while (1)
3916: {
3917: nextToken();
3918: exp = parseAssignExp();
3919: cases.push(exp);
3920: if (token.value != TOKcomma)
3921: break;
3922: }
3923: check(TOKcolon);
3924:
3925: #if DMDV2
3926: /* case exp: .. case last:
3927: */
3928: if (token.value == TOKslice)
3929: {
3930: if (cases.dim > 1)
3931: error("only one case allowed for start of case range");
3932: nextToken();
3933: check(TOKcase);
3934: last = parseAssignExp();
3935: check(TOKcolon);
3936: }
3937: #endif
3938:
3939: statements = new Statements();
3940: while (token.value != TOKcase &&
3941: token.value != TOKdefault &&
3942: token.value != TOKeof &&
3943: token.value != TOKrcurly)
3944: {
3945: statements->push(parseStatement(PSsemi | PScurlyscope));
3946: }
3947: s = new CompoundStatement(loc, statements);
3948: s = new ScopeStatement(loc, s);
3949:
3950: #if DMDV2
3951: if (last)
3952: {
3953: s = new CaseRangeStatement(loc, exp, last, s);
3954: }
3955: else
3956: #endif
3957: {
3958: // Keep cases in order by building the case statements backwards
3959: for (int i = cases.dim; i; i--)
3960: {
3961: exp = cases.tdata()[i - 1];
3962: s = new CaseStatement(loc, exp, s);
3963: }
3964: }
3965: break;
3966: }
3967:
3968: case TOKdefault:
3969: {
3970: Statements *statements;
3971:
3972: nextToken();
3973: check(TOKcolon);
3974:
3975: statements = new Statements();
3976: while (token.value != TOKcase &&
3977: token.value != TOKdefault &&
3978: token.value != TOKeof &&
3979: token.value != TOKrcurly)
3980: {
3981: statements->push(parseStatement(PSsemi | PScurlyscope));
3982: }
3983: s = new CompoundStatement(loc, statements);
3984: s = new ScopeStatement(loc, s);
3985: s = new DefaultStatement(loc, s);
3986: break;
3987: }
3988:
3989: case TOKreturn:
3990: { Expression *exp;
3991:
3992: nextToken();
3993: if (token.value == TOKsemicolon)
3994: exp = NULL;
3995: else
3996: exp = parseExpression();
3997: check(TOKsemicolon, "return statement");
3998: s = new ReturnStatement(loc, exp);
3999: break;
4000: }
4001:
4002: case TOKbreak:
4003: { Identifier *ident;
4004:
4005: nextToken();
4006: if (token.value == TOKidentifier)
4007: { ident = token.ident;
4008: nextToken();
4009: }
4010: else
4011: ident = NULL;
4012: check(TOKsemicolon, "break statement");
4013: s = new BreakStatement(loc, ident);
4014: break;
4015: }
4016:
4017: case TOKcontinue:
4018: { Identifier *ident;
4019:
4020: nextToken();
4021: if (token.value == TOKidentifier)
4022: { ident = token.ident;
4023: nextToken();
4024: }
4025: else
4026: ident = NULL;
4027: check(TOKsemicolon, "continue statement");
4028: s = new ContinueStatement(loc, ident);
4029: break;
4030: }
4031:
4032: case TOKgoto:
4033: { Identifier *ident;
4034:
4035: nextToken();
4036: if (token.value == TOKdefault)
4037: {
4038: nextToken();
4039: s = new GotoDefaultStatement(loc);
4040: }
4041: else if (token.value == TOKcase)
4042: {
4043: Expression *exp = NULL;
4044:
4045: nextToken();
4046: if (token.value != TOKsemicolon)
4047: exp = parseExpression();
4048: s = new GotoCaseStatement(loc, exp);
4049: }
4050: else
4051: {
4052: if (token.value != TOKidentifier)
4053: { error("Identifier expected following goto");
4054: ident = NULL;
4055: }
4056: else
4057: { ident = token.ident;
4058: nextToken();
4059: }
4060: s = new GotoStatement(loc, ident);
4061: }
4062: check(TOKsemicolon, "goto statement");
4063: break;
4064: }
4065:
4066: case TOKsynchronized:
4067: { Expression *exp;
4068: Statement *body;
4069:
4070: nextToken();
4071: if (token.value == TOKlparen)
4072: {
4073: nextToken();
4074: exp = parseExpression();
4075: check(TOKrparen);
4076: }
4077: else
4078: exp = NULL;
4079: body = parseStatement(PSscope);
4080: s = new SynchronizedStatement(loc, exp, body);
4081: break;
4082: }
4083:
4084: case TOKwith:
4085: { Expression *exp;
4086: Statement *body;
4087:
4088: nextToken();
4089: check(TOKlparen);
4090: exp = parseExpression();
4091: check(TOKrparen);
4092: body = parseStatement(PSscope);
4093: s = new WithStatement(loc, exp, body);
4094: break;
4095: }
4096:
4097: case TOKtry:
4098: { Statement *body;
4099: Catches *catches = NULL;
4100: Statement *finalbody = NULL;
4101:
4102: nextToken();
4103: body = parseStatement(PSscope);
4104: while (token.value == TOKcatch)
4105: {
4106: Statement *handler;
4107: Catch *c;
4108: Type *t;
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3350' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3350
4109: Identifier *id;
4110: Loc loc = this->loc;
warning C6246: Local declaration of 'loc' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3355' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 3355
4111:
4112: nextToken();
4113: if (token.value == TOKlcurly)
4114: {
4115: t = NULL;
4116: id = NULL;
4117: }
4118: else
4119: {
4120: check(TOKlparen);
4121: id = NULL;
4122: t = parseType(&id);
4123: check(TOKrparen);
4124: }
4125: handler = parseStatement(0);
4126: c = new Catch(loc, t, id, handler);
4127: if (!catches)
4128: catches = new Catches();
4129: catches->push(c);
4130: }
4131:
4132: if (token.value == TOKfinally)
4133: { nextToken();
4134: finalbody = parseStatement(0);
4135: }
4136:
4137: s = body;
4138: if (!catches && !finalbody)
4139: error("catch or finally expected following try");
4140: else
4141: { if (catches)
4142: s = new TryCatchStatement(loc, body, catches);
4143: if (finalbody)
4144: s = new TryFinallyStatement(loc, s, finalbody);
4145: }
4146: break;
4147: }
4148:
4149: case TOKthrow:
4150: { Expression *exp;
4151:
4152: nextToken();
4153: exp = parseExpression();
4154: check(TOKsemicolon, "throw statement");
4155: s = new ThrowStatement(loc, exp);
4156: break;
4157: }
4158:
4159: case TOKvolatile:
4160: nextToken();
4161: s = parseStatement(PSsemi | PScurlyscope);
4162: #if DMDV2
4163: if (!global.params.useDeprecated)
4164: error("volatile statements deprecated; used synchronized statements instead");
4165: #endif
4166: s = new VolatileStatement(loc, s);
4167: break;
4168:
4169: case TOKasm:
4170: { Statements *statements;
4171: Identifier *label;
4172: Loc labelloc;
4173: Token *toklist;
4174: Token **ptoklist;
4175:
4176: // Parse the asm block into a sequence of AsmStatements,
4177: // each AsmStatement is one instruction.
4178: // Separate out labels.
4179: // Defer parsing of AsmStatements until semantic processing.
4180:
4181: nextToken();
4182: check(TOKlcurly);
4183: toklist = NULL;
4184: ptoklist = &toklist;
4185: label = NULL;
4186: statements = new Statements();
4187: while (1)
4188: {
4189: switch (token.value)
4190: {
4191: case TOKidentifier:
4192: if (!toklist)
4193: {
4194: // Look ahead to see if it is a label
4195: t = peek(&token);
4196: if (t->value == TOKcolon)
4197: { // It's a label
4198: label = token.ident;
4199: labelloc = this->loc;
4200: nextToken();
4201: nextToken();
4202: continue;
4203: }
4204: }
4205: goto Ldefault;
4206:
4207: case TOKrcurly:
4208: if (toklist || label)
4209: {
4210: error("asm statements must end in ';'");
4211: }
4212: break;
4213:
4214: case TOKsemicolon:
4215: s = NULL;
4216: if (toklist || label)
4217: { // Create AsmStatement from list of tokens we've saved
4218: s = new AsmStatement(this->loc, toklist);
4219: toklist = NULL;
4220: ptoklist = &toklist;
4221: if (label)
4222: { s = new LabelStatement(labelloc, label, s);
4223: label = NULL;
4224: }
4225: statements->push(s);
4226: }
4227: nextToken();
4228: continue;
4229:
4230: case TOKeof:
4231: /* { */
4232: error("matching '}' expected, not end of file");
4233: break;
4234:
4235: default:
4236: Ldefault:
4237: *ptoklist = new Token();
4238: memcpy(*ptoklist, &token, sizeof(Token));
4239: ptoklist = &(*ptoklist)->next;
4240: *ptoklist = NULL;
4241:
4242: nextToken();
4243: continue;
4244: }
4245: break;
4246: }
4247: s = new CompoundStatement(loc, statements);
4248: nextToken();
4249: break;
4250: }
4251:
4252: case TOKimport:
4253: { Dsymbols *imports = new Dsymbols();
4254: parseImport(imports, 0);
4255: s = new ImportStatement(loc, imports);
4256: break;
4257: }
4258:
4259: default:
4260: error("found '%s' instead of statement", token.toChars());
4261: goto Lerror;
4262:
4263: Lerror:
4264: while (token.value != TOKrcurly &&
4265: token.value != TOKsemicolon &&
4266: token.value != TOKeof)
4267: nextToken();
4268: if (token.value == TOKsemicolon)
4269: nextToken();
4270: s = NULL;
4271: break;
4272: }
4273:
4274: return s;
4275: }
4276:
4277: void Parser::check(enum TOK value)
4278: {
4279: check(loc, value);
4280: }
4281:
4282: void Parser::check(Loc loc, enum TOK value)
4283: {
4284: if (token.value != value)
4285: error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
4286: nextToken();
4287: }
4288:
4289: void Parser::check(enum TOK value, const char *string)
4290: {
4291: if (token.value != value)
4292: error("found '%s' when expecting '%s' following %s",
4293: token.toChars(), Token::toChars(value), string);
4294: nextToken();
4295: }
4296:
4297: void Parser::checkParens(enum TOK value, Expression *e)
4298: {
4299: if (precedence[e->op] == PREC_rel && !e->parens)
4300: error(loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
4301: }
4302:
4303: /************************************
4304: * Determine if the scanner is sitting on the start of a declaration.
4305: * Input:
4306: * needId 0 no identifier
4307: * 1 identifier optional
4308: * 2 must have identifier
4309: * Output:
4310: * if *pt is not NULL, it is set to the ending token, which would be endtok
4311: */
4312:
4313: int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
4314: {
4315: //printf("isDeclaration(needId = %d)\n", needId);
4316: int haveId = 0;
4317:
4318: #if DMDV2
4319: if ((t->value == TOKconst ||
4320: t->value == TOKinvariant ||
4321: t->value == TOKimmutable ||
4322: t->value == TOKwild ||
4323: t->value == TOKshared) &&
4324: peek(t)->value != TOKlparen)
4325: { /* const type
4326: * immutable type
4327: * shared type
4328: * wild type
4329: */
4330: t = peek(t);
4331: }
4332: #endif
4333:
4334: if (!isBasicType(&t))
4335: {
4336: goto Lisnot;
4337: }
4338: if (!isDeclarator(&t, &haveId, endtok))
4339: goto Lisnot;
4340: if ( needId == 1 ||
4341: (needId == 0 && !haveId) ||
4342: (needId == 2 && haveId))
4343: { if (pt)
4344: *pt = t;
4345: goto Lis;
4346: }
4347: else
4348: goto Lisnot;
4349:
4350: Lis:
4351: //printf("\tis declaration, t = %s\n", t->toChars());
4352: return TRUE;
4353:
4354: Lisnot:
4355: //printf("\tis not declaration\n");
4356: return FALSE;
4357: }
4358:
4359: int Parser::isBasicType(Token **pt)
4360: {
4361: // This code parallels parseBasicType()
4362: Token *t = *pt;
4363: Token *t2;
warning C4101: 't2' : unreferenced local variable
4364: int parens;
warning C4101: 'parens' : unreferenced local variable
4365: int haveId = 0;
4366:
4367: switch (t->value)
4368: {
4369: case BASIC_TYPES:
4370: t = peek(t);
4371: break;
4372:
4373: case TOKidentifier:
4374: L5:
4375: t = peek(t);
4376: if (t->value == TOKnot)
4377: {
4378: goto L4;
4379: }
4380: goto L3;
4381: while (1)
4382: {
4383: L2:
4384: t = peek(t);
4385: L3:
4386: if (t->value == TOKdot)
4387: {
4388: Ldot:
4389: t = peek(t);
4390: if (t->value != TOKidentifier)
4391: goto Lfalse;
4392: t = peek(t);
4393: if (t->value != TOKnot)
4394: goto L3;
4395: L4:
4396: /* Seen a !
4397: * Look for:
4398: * !( args ), !identifier, etc.
4399: */
4400: t = peek(t);
4401: switch (t->value)
4402: { case TOKidentifier:
4403: goto L5;
4404: case TOKlparen:
4405: if (!skipParens(t, &t))
4406: goto Lfalse;
4407: break;
4408: case BASIC_TYPES:
4409: case TOKint32v:
4410: case TOKuns32v:
4411: case TOKint64v:
4412: case TOKuns64v:
4413: case TOKfloat32v:
4414: case TOKfloat64v:
4415: case TOKfloat80v:
4416: case TOKimaginary32v:
4417: case TOKimaginary64v:
4418: case TOKimaginary80v:
4419: case TOKnull:
4420: case TOKtrue:
4421: case TOKfalse:
4422: case TOKcharv:
4423: case TOKwcharv:
4424: case TOKdcharv:
4425: case TOKstring:
4426: case TOKfile:
4427: case TOKline:
4428: goto L2;
4429: default:
4430: goto Lfalse;
4431: }
4432: }
4433: else
4434: break;
4435: }
4436: break;
4437:
4438: case TOKdot:
4439: goto Ldot;
4440:
4441: case TOKtypeof:
4442: /* typeof(exp).identifier...
4443: */
4444: t = peek(t);
4445: if (t->value != TOKlparen)
4446: goto Lfalse;
4447: if (!skipParens(t, &t))
4448: goto Lfalse;
4449: goto L2;
4450:
4451: case TOKconst:
4452: case TOKinvariant:
4453: case TOKimmutable:
4454: case TOKshared:
4455: case TOKwild:
4456: // const(type) or immutable(type) or shared(type) or wild(type)
4457: t = peek(t);
4458: if (t->value != TOKlparen)
4459: goto Lfalse;
4460: t = peek(t);
4461: if (!isDeclaration(t, 0, TOKrparen, &t))
4462: {
4463: goto Lfalse;
4464: }
4465: t = peek(t);
4466: break;
4467:
4468: default:
4469: goto Lfalse;
4470: }
4471: *pt = t;
4472: //printf("is\n");
4473: return TRUE;
4474:
4475: Lfalse:
4476: //printf("is not\n");
4477: return FALSE;
4478: }
4479:
4480: int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
4481: { // This code parallels parseDeclarator()
4482: Token *t = *pt;
4483: int parens;
4484:
4485: //printf("Parser::isDeclarator()\n");
4486: //t->print();
4487: if (t->value == TOKassign)
4488: return FALSE;
4489:
4490: while (1)
4491: {
4492: parens = FALSE;
4493: switch (t->value)
4494: {
4495: case TOKmul:
4496: //case TOKand:
4497: t = peek(t);
4498: continue;
4499:
4500: case TOKlbracket:
4501: t = peek(t);
4502: if (t->value == TOKrbracket)
4503: {
4504: t = peek(t);
4505: }
4506: else if (isDeclaration(t, 0, TOKrbracket, &t))
4507: { // It's an associative array declaration
4508: t = peek(t);
4509: }
4510: else
4511: {
4512: // [ expression ]
4513: // [ expression .. expression ]
4514: if (!isExpression(&t))
4515: return FALSE;
4516: if (t->value == TOKslice)
4517: { t = peek(t);
4518: if (!isExpression(&t))
4519: return FALSE;
4520: }
4521: if (t->value != TOKrbracket)
4522: return FALSE;
4523: t = peek(t);
4524: }
4525: continue;
4526:
4527: case TOKidentifier:
4528: if (*haveId)
4529: return FALSE;
4530: *haveId = TRUE;
4531: t = peek(t);
4532: break;
4533:
4534: case TOKlparen:
4535: t = peek(t);
4536:
4537: if (t->value == TOKrparen)
4538: return FALSE; // () is not a declarator
4539:
4540: /* Regard ( identifier ) as not a declarator
4541: * BUG: what about ( *identifier ) in
4542: * f(*p)(x);
4543: * where f is a class instance with overloaded () ?
4544: * Should we just disallow C-style function pointer declarations?
4545: */
4546: if (t->value == TOKidentifier)
4547: { Token *t2 = peek(t);
4548: if (t2->value == TOKrparen)
4549: return FALSE;
4550: }
4551:
4552:
4553: if (!isDeclarator(&t, haveId, TOKrparen))
4554: return FALSE;
4555: t = peek(t);
4556: parens = TRUE;
4557: break;
4558:
4559: case TOKdelegate:
4560: case TOKfunction:
4561: t = peek(t);
4562: if (!isParameters(&t))
4563: return FALSE;
4564: continue;
4565: }
4566: break;
4567: }
4568:
4569: while (1)
4570: {
4571: switch (t->value)
4572: {
4573: #if CARRAYDECL
4574: case TOKlbracket:
4575: parens = FALSE;
4576: t = peek(t);
4577: if (t->value == TOKrbracket)
4578: {
4579: t = peek(t);
4580: }
4581: else if (isDeclaration(t, 0, TOKrbracket, &t))
4582: { // It's an associative array declaration
4583: t = peek(t);
4584: }
4585: else
4586: {
4587: // [ expression ]
4588: if (!isExpression(&t))
4589: return FALSE;
4590: if (t->value != TOKrbracket)
4591: return FALSE;
4592: t = peek(t);
4593: }
4594: continue;
4595: #endif
4596:
4597: case TOKlparen:
4598: parens = FALSE;
4599: if (!isParameters(&t))
4600: return FALSE;
4601: #if DMDV2
4602: while (1)
4603: {
4604: switch (t->value)
4605: {
4606: case TOKconst:
4607: case TOKinvariant:
4608: case TOKimmutable:
4609: case TOKshared:
4610: case TOKwild:
4611: case TOKpure:
4612: case TOKnothrow:
4613: t = peek(t);
4614: continue;
4615: case TOKat:
4616: t = peek(t); // skip '@'
4617: t = peek(t); // skip identifier
4618: continue;
4619: default:
4620: break;
4621: }
4622: break;
4623: }
4624: #endif
4625: continue;
4626:
4627: // Valid tokens that follow a declaration
4628: case TOKrparen:
4629: case TOKrbracket:
4630: case TOKassign:
4631: case TOKcomma:
4632: case TOKsemicolon:
4633: case TOKlcurly:
4634: case TOKin:
4635: // The !parens is to disallow unnecessary parentheses
4636: if (!parens && (endtok == TOKreserved || endtok == t->value))
4637: { *pt = t;
4638: return TRUE;
4639: }
4640: return FALSE;
4641:
4642: default:
4643: return FALSE;
4644: }
4645: }
4646: }
4647:
4648:
4649: int Parser::isParameters(Token **pt)
4650: { // This code parallels parseParameters()
4651: Token *t = *pt;
4652:
4653: //printf("isParameters()\n");
4654: if (t->value != TOKlparen)
4655: return FALSE;
4656:
4657: t = peek(t);
4658: for (;1; t = peek(t))
4659: {
4660: L1:
4661: switch (t->value)
4662: {
4663: case TOKrparen:
4664: break;
4665:
4666: case TOKdotdotdot:
4667: t = peek(t);
4668: break;
4669:
4670: #if D1INOUT
4671: case TOKinout:
4672: #endif
4673: case TOKin:
4674: case TOKout:
4675: case TOKref:
4676: case TOKlazy:
4677: case TOKfinal:
4678: case TOKauto:
4679: continue;
4680:
4681: case TOKconst:
4682: case TOKinvariant:
4683: case TOKimmutable:
4684: case TOKshared:
4685: case TOKwild:
4686: t = peek(t);
4687: if (t->value == TOKlparen)
4688: {
4689: t = peek(t);
4690: if (!isDeclaration(t, 0, TOKrparen, &t))
4691: return FALSE;
4692: t = peek(t); // skip past closing ')'
4693: goto L2;
4694: }
4695: goto L1;
4696:
4697: #if 0
4698: case TOKstatic:
4699: continue;
4700: case TOKauto:
4701: case TOKalias:
4702: t = peek(t);
4703: if (t->value == TOKidentifier)
4704: t = peek(t);
4705: if (t->value == TOKassign)
4706: { t = peek(t);
4707: if (!isExpression(&t))
4708: return FALSE;
4709: }
4710: goto L3;
4711: #endif
4712:
4713: default:
4714: { if (!isBasicType(&t))
4715: return FALSE;
4716: L2:
4717: int tmp = FALSE;
4718: if (t->value != TOKdotdotdot &&
4719: !isDeclarator(&t, &tmp, TOKreserved))
4720: return FALSE;
4721: if (t->value == TOKassign)
4722: { t = peek(t);
4723: if (!isExpression(&t))
4724: return FALSE;
4725: }
4726: if (t->value == TOKdotdotdot)
4727: {
4728: t = peek(t);
4729: break;
4730: }
4731: }
4732: L3:
warning C4102: 'L3' : unreferenced label
4733: if (t->value == TOKcomma)
4734: {
4735: continue;
4736: }
4737: break;
4738: }
4739: break;
4740: }
4741: if (t->value != TOKrparen)
4742: return FALSE;
4743: t = peek(t);
4744: *pt = t;
4745: return TRUE;
4746: }
4747:
4748: int Parser::isExpression(Token **pt)
4749: {
4750: // This is supposed to determine if something is an expression.
4751: // What it actually does is scan until a closing right bracket
4752: // is found.
4753:
4754: Token *t = *pt;
4755: int brnest = 0;
4756: int panest = 0;
4757: int curlynest = 0;
4758:
4759: for (;; t = peek(t))
4760: {
4761: switch (t->value)
4762: {
4763: case TOKlbracket:
4764: brnest++;
4765: continue;
4766:
4767: case TOKrbracket:
4768: if (--brnest >= 0)
4769: continue;
4770: break;
4771:
4772: case TOKlparen:
4773: panest++;
4774: continue;
4775:
4776: case TOKcomma:
4777: if (brnest || panest)
4778: continue;
4779: break;
4780:
4781: case TOKrparen:
4782: if (--panest >= 0)
4783: continue;
4784: break;
4785:
4786: case TOKlcurly:
4787: curlynest++;
4788: continue;
4789:
4790: case TOKrcurly:
4791: if (--curlynest >= 0)
4792: continue;
4793: return FALSE;
4794:
4795: case TOKslice:
4796: if (brnest)
4797: continue;
4798: break;
4799:
4800: case TOKsemicolon:
4801: if (curlynest)
4802: continue;
4803: return FALSE;
4804:
4805: case TOKeof:
4806: return FALSE;
4807:
4808: default:
4809: continue;
4810: }
4811: break;
4812: }
4813:
4814: *pt = t;
4815: return TRUE;
4816: }
4817:
4818: /**********************************************
4819: * Skip over
4820: * instance foo.bar(parameters...)
4821: * Output:
4822: * if (pt), *pt is set to the token following the closing )
4823: * Returns:
4824: * 1 it's valid instance syntax
4825: * 0 invalid instance syntax
4826: */
4827:
4828: int Parser::isTemplateInstance(Token *t, Token **pt)
4829: {
4830: t = peek(t);
4831: if (t->value != TOKdot)
4832: {
4833: if (t->value != TOKidentifier)
4834: goto Lfalse;
4835: t = peek(t);
4836: }
4837: while (t->value == TOKdot)
4838: {
4839: t = peek(t);
4840: if (t->value != TOKidentifier)
4841: goto Lfalse;
4842: t = peek(t);
4843: }
4844: if (t->value != TOKlparen)
4845: goto Lfalse;
4846:
4847: // Skip over the template arguments
4848: while (1)
4849: {
4850: while (1)
4851: {
4852: t = peek(t);
4853: switch (t->value)
4854: {
4855: case TOKlparen:
4856: if (!skipParens(t, &t))
4857: goto Lfalse;
4858: continue;
4859: case TOKrparen:
4860: break;
4861: case TOKcomma:
4862: break;
4863: case TOKeof:
4864: case TOKsemicolon:
4865: goto Lfalse;
4866: default:
4867: continue;
4868: }
4869: break;
4870: }
4871:
4872: if (t->value != TOKcomma)
4873: break;
4874: }
4875: if (t->value != TOKrparen)
4876: goto Lfalse;
4877: t = peek(t);
4878: if (pt)
4879: *pt = t;
4880: return 1;
4881:
4882: Lfalse:
4883: return 0;
4884: }
4885:
4886: /*******************************************
4887: * Skip parens, brackets.
4888: * Input:
4889: * t is on opening (
4890: * Output:
4891: * *pt is set to closing token, which is ')' on success
4892: * Returns:
4893: * !=0 successful
4894: * 0 some parsing error
4895: */
4896:
4897: int Parser::skipParens(Token *t, Token **pt)
4898: {
4899: int parens = 0;
4900:
4901: while (1)
4902: {
4903: switch (t->value)
4904: {
4905: case TOKlparen:
4906: parens++;
4907: break;
4908:
4909: case TOKrparen:
4910: parens--;
4911: if (parens < 0)
4912: goto Lfalse;
4913: if (parens == 0)
4914: goto Ldone;
4915: break;
4916:
4917: case TOKeof:
4918: goto Lfalse;
4919:
4920: default:
4921: break;
4922: }
4923: t = peek(t);
4924: }
4925:
4926: Ldone:
4927: if (*pt)
4928: *pt = t;
4929: return 1;
4930:
4931: Lfalse:
4932: return 0;
4933: }
4934:
4935: /*******************************************
4936: * Skip attributes.
4937: * Input:
4938: * t is on a candidate attribute
4939: * Output:
4940: * *pt is set to first non-attribute token on success
4941: * Returns:
4942: * !=0 successful
4943: * 0 some parsing error
4944: */
4945:
4946: int Parser::skipAttributes(Token *t, Token **pt)
4947: {
4948: while (1)
4949: {
4950: switch (t->value)
4951: {
4952: case TOKconst:
4953: case TOKinvariant:
4954: case TOKimmutable:
4955: case TOKshared:
4956: case TOKwild:
4957: case TOKfinal:
4958: case TOKauto:
4959: case TOKscope:
4960: case TOKoverride:
4961: case TOKabstract:
4962: case TOKsynchronized:
4963: case TOKdeprecated:
4964: case TOKnothrow:
4965: case TOKpure:
4966: case TOKref:
4967: case TOKtls:
4968: case TOKgshared:
4969: //case TOKmanifest:
4970: break;
4971: case TOKat:
4972: if (parseAttribute() == STCundefined)
4973: break;
4974: goto Lerror;
4975: default:
4976: goto Ldone;
4977: }
4978: t = peek(t);
4979: }
4980:
4981: Ldone:
4982: if (*pt)
4983: *pt = t;
4984: return 1;
4985:
4986: Lerror:
4987: return 0;
4988: }
4989:
4990: /********************************* Expression Parser ***************************/
4991:
4992: Expression *Parser::parsePrimaryExp()
4993: { Expression *e;
4994: Type *t;
4995: Identifier *id;
4996: enum TOK save;
4997: Loc loc = this->loc;
4998:
4999: //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
5000: switch (token.value)
5001: {
5002: case TOKidentifier:
5003: id = token.ident;
5004: nextToken();
5005: if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
5006: { // identifier!(template-argument-list)
5007: TemplateInstance *tempinst;
5008:
5009: tempinst = new TemplateInstance(loc, id);
5010: nextToken();
5011: if (token.value == TOKlparen)
5012: // ident!(template_arguments)
5013: tempinst->tiargs = parseTemplateArgumentList();
5014: else
5015: // ident!template_argument
5016: tempinst->tiargs = parseTemplateArgument();
5017: e = new ScopeExp(loc, tempinst);
5018: }
5019: else
5020: e = new IdentifierExp(loc, id);
5021: break;
5022:
5023: case TOKdollar:
5024: if (!inBrackets)
5025: error("'$' is valid only inside [] of index or slice");
5026: e = new DollarExp(loc);
5027: nextToken();
5028: break;
5029:
5030: case TOKdot:
5031: // Signal global scope '.' operator with "" identifier
5032: e = new IdentifierExp(loc, Id::empty);
5033: break;
5034:
5035: case TOKthis:
5036: e = new ThisExp(loc);
5037: nextToken();
5038: break;
5039:
5040: case TOKsuper:
5041: e = new SuperExp(loc);
5042: nextToken();
5043: break;
5044:
5045: case TOKint32v:
5046: e = new IntegerExp(loc, token.int32value, Type::tint32);
5047: nextToken();
5048: break;
5049:
5050: case TOKuns32v:
5051: e = new IntegerExp(loc, token.uns32value, Type::tuns32);
5052: nextToken();
5053: break;
5054:
5055: case TOKint64v:
5056: e = new IntegerExp(loc, token.int64value, Type::tint64);
5057: nextToken();
5058: break;
5059:
5060: case TOKuns64v:
5061: e = new IntegerExp(loc, token.uns64value, Type::tuns64);
5062: nextToken();
5063: break;
5064:
5065: case TOKfloat32v:
5066: e = new RealExp(loc, token.float80value, Type::tfloat32);
5067: nextToken();
5068: break;
5069:
5070: case TOKfloat64v:
5071: e = new RealExp(loc, token.float80value, Type::tfloat64);
5072: nextToken();
5073: break;
5074:
5075: case TOKfloat80v:
5076: e = new RealExp(loc, token.float80value, Type::tfloat80);
5077: nextToken();
5078: break;
5079:
5080: case TOKimaginary32v:
5081: e = new RealExp(loc, token.float80value, Type::timaginary32);
5082: nextToken();
5083: break;
5084:
5085: case TOKimaginary64v:
5086: e = new RealExp(loc, token.float80value, Type::timaginary64);
5087: nextToken();
5088: break;
5089:
5090: case TOKimaginary80v:
5091: e = new RealExp(loc, token.float80value, Type::timaginary80);
5092: nextToken();
5093: break;
5094:
5095: case TOKnull:
5096: e = new NullExp(loc);
5097: nextToken();
5098: break;
5099:
5100: #if DMDV2
5101: case TOKfile:
5102: { const char *s = loc.filename ? loc.filename : mod->ident->toChars();
5103: e = new StringExp(loc, (char *)s, strlen(s), 0);
5104: nextToken();
5105: break;
5106: }
5107:
5108: case TOKline:
5109: e = new IntegerExp(loc, loc.linnum, Type::tint32);
5110: nextToken();
5111: break;
5112: #endif
5113:
5114: case TOKtrue:
5115: e = new IntegerExp(loc, 1, Type::tbool);
5116: nextToken();
5117: break;
5118:
5119: case TOKfalse:
5120: e = new IntegerExp(loc, 0, Type::tbool);
5121: nextToken();
5122: break;
5123:
5124: case TOKcharv:
5125: e = new IntegerExp(loc, token.uns32value, Type::tchar);
5126: nextToken();
5127: break;
5128:
5129: case TOKwcharv:
5130: e = new IntegerExp(loc, token.uns32value, Type::twchar);
5131: nextToken();
5132: break;
5133:
5134: case TOKdcharv:
5135: e = new IntegerExp(loc, token.uns32value, Type::tdchar);
5136: nextToken();
5137: break;
5138:
5139: case TOKstring:
5140: { unsigned char *s;
5141: unsigned len;
5142: unsigned char postfix;
5143:
5144: // cat adjacent strings
5145: s = token.ustring;
5146: len = token.len;
5147: postfix = token.postfix;
5148: while (1)
5149: {
5150: nextToken();
5151: if (token.value == TOKstring)
5152: { unsigned len1;
5153: unsigned len2;
5154: unsigned char *s2;
5155:
5156: if (token.postfix)
5157: { if (token.postfix != postfix)
5158: error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
5159: postfix = token.postfix;
5160: }
5161:
5162: len1 = len;
5163: len2 = token.len;
5164: len = len1 + len2;
5165: s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
5166: memcpy(s2, s, len1 * sizeof(unsigned char));
5167: memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
5168: s = s2;
5169: }
5170: else
5171: break;
5172: }
5173: e = new StringExp(loc, s, len, postfix);
5174: break;
5175: }
5176:
5177: case BASIC_TYPES_X(t):
5178: nextToken();
5179: L1:
warning C4102: 'L1' : unreferenced label
5180: check(TOKdot, t->toChars());
5181: if (token.value != TOKidentifier)
5182: { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
5183: goto Lerr;
5184: }
5185: e = typeDotIdExp(loc, t, token.ident);
5186: nextToken();
5187: break;
5188:
5189: case TOKtypeof:
5190: {
5191: t = parseTypeof();
5192: e = new TypeExp(loc, t);
5193: break;
5194: }
5195:
5196: case TOKtypeid:
5197: {
5198: nextToken();
5199: check(TOKlparen, "typeid");
5200: Object *o;
5201: if (isDeclaration(&token, 0, TOKreserved, NULL))
5202: { // argument is a type
5203: o = parseType();
5204: }
5205: else
5206: { // argument is an expression
5207: o = parseAssignExp();
5208: }
5209: check(TOKrparen);
5210: e = new TypeidExp(loc, o);
5211: break;
5212: }
5213:
5214: #if DMDV2
5215: case TOKtraits:
5216: { /* __traits(identifier, args...)
5217: */
5218: Identifier *ident;
5219: Objects *args = NULL;
5220:
5221: nextToken();
5222: check(TOKlparen);
5223: if (token.value != TOKidentifier)
5224: { error("__traits(identifier, args...) expected");
5225: goto Lerr;
5226: }
5227: ident = token.ident;
5228: nextToken();
5229: if (token.value == TOKcomma)
5230: args = parseTemplateArgumentList2(); // __traits(identifier, args...)
5231: else
5232: check(TOKrparen); // __traits(identifier)
5233:
5234: e = new TraitsExp(loc, ident, args);
5235: break;
5236: }
5237: #endif
5238:
5239: case TOKis:
5240: { Type *targ;
5241: Identifier *ident = NULL;
5242: Type *tspec = NULL;
5243: enum TOK tok = TOKreserved;
5244: enum TOK tok2 = TOKreserved;
5245: TemplateParameters *tpl = NULL;
5246: Loc loc = this->loc;
warning C6246: Local declaration of 'loc' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4997' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 4997
5247:
5248: nextToken();
5249: if (token.value == TOKlparen)
5250: {
5251: nextToken();
5252: targ = parseType(&ident);
5253: if (token.value == TOKcolon || token.value == TOKequal)
5254: {
5255: tok = token.value;
5256: nextToken();
5257: if (tok == TOKequal &&
5258: (token.value == TOKtypedef ||
5259: token.value == TOKstruct ||
5260: token.value == TOKunion ||
5261: token.value == TOKclass ||
5262: token.value == TOKsuper ||
5263: token.value == TOKenum ||
5264: token.value == TOKinterface ||
5265: token.value == TOKargTypes ||
5266: #if DMDV2
5267: token.value == TOKconst && peek(&token)->value == TOKrparen ||
5268: token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
5269: token.value == TOKimmutable && peek(&token)->value == TOKrparen ||
5270: token.value == TOKshared && peek(&token)->value == TOKrparen ||
5271: token.value == TOKwild && peek(&token)->value == TOKrparen ||
5272: #endif
5273: token.value == TOKfunction ||
5274: token.value == TOKdelegate ||
5275: token.value == TOKreturn))
5276: {
5277: tok2 = token.value;
5278: nextToken();
5279: }
5280: else
5281: {
5282: tspec = parseType();
5283: }
5284: }
5285: if (ident && tspec)
5286: {
5287: if (token.value == TOKcomma)
5288: tpl = parseTemplateParameterList(1);
5289: else
5290: { tpl = new TemplateParameters();
5291: check(TOKrparen);
5292: }
5293: TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
5294: tpl->insert(0, tp);
5295: }
5296: else
5297: check(TOKrparen);
5298: }
5299: else
5300: { error("(type identifier : specialization) expected following is");
5301: goto Lerr;
5302: }
5303: e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
5304: break;
5305: }
5306:
5307: case TOKassert:
5308: { Expression *msg = NULL;
5309:
5310: nextToken();
5311: check(TOKlparen, "assert");
5312: e = parseAssignExp();
5313: if (token.value == TOKcomma)
5314: { nextToken();
5315: msg = parseAssignExp();
5316: }
5317: check(TOKrparen);
5318: e = new AssertExp(loc, e, msg);
5319: break;
5320: }
5321:
5322: case TOKmixin:
5323: {
5324: nextToken();
5325: check(TOKlparen, "mixin");
5326: e = parseAssignExp();
5327: check(TOKrparen);
5328: e = new CompileExp(loc, e);
5329: break;
5330: }
5331:
5332: case TOKimport:
5333: {
5334: nextToken();
5335: check(TOKlparen, "import");
5336: e = parseAssignExp();
5337: check(TOKrparen);
5338: e = new FileExp(loc, e);
5339: break;
5340: }
5341:
5342: case TOKlparen:
5343: if (peekPastParen(&token)->value == TOKlcurly)
5344: { // (arguments) { statements... }
5345: save = TOKdelegate;
5346: goto case_delegate;
5347: }
5348: // ( expression )
5349: nextToken();
5350: e = parseExpression();
5351: e->parens = 1;
5352: check(loc, TOKrparen);
5353: break;
5354:
5355: case TOKlbracket:
5356: { /* Parse array literals and associative array literals:
5357: * [ value, value, value ... ]
5358: * [ key:value, key:value, key:value ... ]
5359: */
5360: Expressions *values = new Expressions();
5361: Expressions *keys = NULL;
5362:
5363: nextToken();
5364: while (token.value != TOKrbracket && token.value != TOKeof)
5365: {
5366: Expression *e = parseAssignExp();
warning C6246: Local declaration of 'e' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4993' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 4993
5367: if (token.value == TOKcolon && (keys || values->dim == 0))
5368: { nextToken();
5369: if (!keys)
5370: keys = new Expressions();
5371: keys->push(e);
5372: e = parseAssignExp();
5373: }
5374: else if (keys)
5375: { error("'key:value' expected for associative array literal");
5376: delete keys;
5377: keys = NULL;
5378: }
5379: values->push(e);
5380: if (token.value == TOKrbracket)
5381: break;
5382: check(TOKcomma);
5383: }
5384: check(loc, TOKrbracket);
5385:
5386: if (keys)
5387: e = new AssocArrayLiteralExp(loc, keys, values);
5388: else
5389: e = new ArrayLiteralExp(loc, values);
5390: break;
5391: }
5392:
5393: case TOKlcurly:
5394: // { statements... }
5395: save = TOKdelegate;
5396: goto case_delegate;
5397:
5398: case TOKfunction:
5399: case TOKdelegate:
5400: save = token.value;
5401: nextToken();
5402: case_delegate:
5403: {
5404: /* function type(parameters) { body } pure nothrow
5405: * delegate type(parameters) { body } pure nothrow
5406: * (parameters) { body }
5407: * { body }
5408: */
5409: Parameters *arguments;
5410: int varargs;
5411: FuncLiteralDeclaration *fd;
5412: Type *t;
warning C6246: Local declaration of 't' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4994' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 4994
5413: StorageClass stc = 0;
5414:
5415: if (token.value == TOKlcurly)
5416: {
5417: t = NULL;
5418: varargs = 0;
5419: arguments = new Parameters();
5420: }
5421: else
5422: {
5423: if (token.value == TOKlparen)
5424: t = NULL;
5425: else
5426: {
5427: t = parseBasicType();
5428: t = parseBasicType2(t); // function return type
5429: }
5430: arguments = parseParameters(&varargs);
5431: stc = parsePostfix();
5432: if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5433: error("const/immutable/shared/inout attributes are only valid for non-static member functions");
5434: }
5435:
5436: TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
5437:
5438: fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
5439: parseContracts(fd);
5440: e = new FuncExp(loc, fd);
5441: break;
5442: }
5443:
5444: default:
5445: error("expression expected, not '%s'", token.toChars());
5446: Lerr:
5447: // Anything for e, as long as it's not NULL
5448: e = new IntegerExp(loc, 0, Type::tint32);
5449: nextToken();
5450: break;
5451: }
5452: return e;
5453: }
5454:
5455: Expression *Parser::parsePostExp(Expression *e)
5456: {
5457: Loc loc;
5458:
5459: while (1)
5460: {
5461: loc = this->loc;
5462: switch (token.value)
5463: {
5464: case TOKdot:
5465: nextToken();
5466: if (token.value == TOKidentifier)
5467: { Identifier *id = token.ident;
5468:
5469: nextToken();
5470: if (token.value == TOKnot && peekNext() != TOKis)
5471: { // identifier!(template-argument-list)
5472: TemplateInstance *tempinst = new TemplateInstance(loc, id);
5473: Objects *tiargs;
5474: nextToken();
5475: if (token.value == TOKlparen)
5476: // ident!(template_arguments)
5477: tiargs = parseTemplateArgumentList();
5478: else
5479: // ident!template_argument
5480: tiargs = parseTemplateArgument();
5481: e = new DotTemplateInstanceExp(loc, e, id, tiargs);
5482: }
5483: else
5484: e = new DotIdExp(loc, e, id);
5485: continue;
5486: }
5487: else if (token.value == TOKnew)
5488: {
5489: e = parseNewExp(e);
5490: continue;
5491: }
5492: else
5493: error("identifier expected following '.', not '%s'", token.toChars());
5494: break;
5495:
5496: case TOKplusplus:
5497: e = new PostExp(TOKplusplus, loc, e);
5498: break;
5499:
5500: case TOKminusminus:
5501: e = new PostExp(TOKminusminus, loc, e);
5502: break;
5503:
5504: case TOKlparen:
5505: e = new CallExp(loc, e, parseArguments());
5506: continue;
5507:
5508: case TOKlbracket:
5509: { // array dereferences:
5510: // array[index]
5511: // array[]
5512: // array[lwr .. upr]
5513: Expression *index;
5514: Expression *upr;
5515:
5516: inBrackets++;
5517: nextToken();
5518: if (token.value == TOKrbracket)
5519: { // array[]
5520: inBrackets--;
5521: e = new SliceExp(loc, e, NULL, NULL);
5522: nextToken();
5523: }
5524: else
5525: {
5526: index = parseAssignExp();
5527: if (token.value == TOKslice)
5528: { // array[lwr .. upr]
5529: nextToken();
5530: upr = parseAssignExp();
5531: e = new SliceExp(loc, e, index, upr);
5532: }
5533: else
5534: { // array[index, i2, i3, i4, ...]
5535: Expressions *arguments = new Expressions();
5536: arguments->push(index);
5537: if (token.value == TOKcomma)
5538: {
5539: nextToken();
5540: while (token.value != TOKrbracket && token.value != TOKeof)
5541: {
5542: Expression *arg = parseAssignExp();
5543: arguments->push(arg);
5544: if (token.value == TOKrbracket)
5545: break;
5546: check(TOKcomma);
5547: }
5548: }
5549: e = new ArrayExp(loc, e, arguments);
warning C6211: Leaking memory 'e' due to an exception. Consider using a local catch block to clean up memory: Lines: 5457, 5459, 5461, 5462, 5508, 5513, 5514, 5516, 5517, 5518, 5526, 5527, 5535, 5536, 5537, 5549, 5551, 5552, 5459, 5461, 5462, 5508, 5513, 5514, 5516, 5517, 5518, 5526, 5527, 5535
5550: }
5551: check(TOKrbracket);
5552: inBrackets--;
5553: }
5554: continue;
5555: }
5556:
5557: default:
5558: return e;
5559: }
5560: nextToken();
5561: }
5562: }
5563:
5564: Expression *Parser::parseUnaryExp()
5565: { Expression *e;
5566: Loc loc = this->loc;
5567:
5568: switch (token.value)
5569: {
5570: case TOKand:
5571: nextToken();
5572: e = parseUnaryExp();
5573: e = new AddrExp(loc, e);
5574: break;
5575:
5576: case TOKplusplus:
5577: nextToken();
5578: e = parseUnaryExp();
5579: //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5580: e = new PreExp(TOKpreplusplus, loc, e);
5581: break;
5582:
5583: case TOKminusminus:
5584: nextToken();
5585: e = parseUnaryExp();
5586: //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5587: e = new PreExp(TOKpreminusminus, loc, e);
5588: break;
5589:
5590: case TOKmul:
5591: nextToken();
5592: e = parseUnaryExp();
5593: e = new PtrExp(loc, e);
5594: break;
5595:
5596: case TOKmin:
5597: nextToken();
5598: e = parseUnaryExp();
5599: e = new NegExp(loc, e);
5600: break;
5601:
5602: case TOKadd:
5603: nextToken();
5604: e = parseUnaryExp();
5605: e = new UAddExp(loc, e);
5606: break;
5607:
5608: case TOKnot:
5609: nextToken();
5610: e = parseUnaryExp();
5611: e = new NotExp(loc, e);
5612: break;
5613:
5614: case TOKtilde:
5615: nextToken();
5616: e = parseUnaryExp();
5617: e = new ComExp(loc, e);
5618: break;
5619:
5620: case TOKdelete:
5621: nextToken();
5622: e = parseUnaryExp();
5623: e = new DeleteExp(loc, e);
5624: break;
5625:
5626: case TOKnew:
5627: e = parseNewExp(NULL);
5628: break;
5629:
5630: case TOKcast: // cast(type) expression
5631: {
5632: nextToken();
5633: check(TOKlparen);
5634: /* Look for cast(), cast(const), cast(immutable),
5635: * cast(shared), cast(shared const), cast(wild), cast(shared wild)
5636: */
5637: unsigned m;
5638: if (token.value == TOKrparen)
5639: {
5640: m = 0;
5641: goto Lmod1;
5642: }
5643: else if (token.value == TOKconst && peekNext() == TOKrparen)
5644: {
5645: m = MODconst;
5646: goto Lmod2;
5647: }
5648: else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen)
5649: {
5650: m = MODimmutable;
5651: goto Lmod2;
5652: }
5653: else if (token.value == TOKshared && peekNext() == TOKrparen)
5654: {
5655: m = MODshared;
5656: goto Lmod2;
5657: }
5658: else if (token.value == TOKwild && peekNext() == TOKrparen)
5659: {
5660: m = MODwild;
5661: goto Lmod2;
5662: }
5663: else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() == TOKrparen ||
5664: token.value == TOKshared && peekNext() == TOKwild && peekNext2() == TOKrparen)
5665: {
5666: m = MODshared | MODwild;
5667: goto Lmod3;
5668: }
5669: else if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() == TOKrparen ||
5670: token.value == TOKshared && peekNext() == TOKconst && peekNext2() == TOKrparen)
5671: {
5672: m = MODshared | MODconst;
5673: Lmod3:
5674: nextToken();
5675: Lmod2:
5676: nextToken();
5677: Lmod1:
5678: nextToken();
5679: e = parseUnaryExp();
5680: e = new CastExp(loc, e, m);
5681: }
5682: else
5683: {
5684: Type *t = parseType(); // ( type )
5685: check(TOKrparen);
5686: e = parseUnaryExp();
5687: e = new CastExp(loc, e, t);
5688: }
5689: break;
5690: }
5691:
5692: case TOKwild:
5693: case TOKshared:
5694: case TOKconst:
5695: case TOKinvariant:
5696: case TOKimmutable: // immutable(type)(arguments)
5697: {
5698: Type *t = parseBasicType();
5699: if (token.value != TOKlparen)
5700: error("(arguments) expected following type");
5701: e = new TypeExp(loc, t);
5702: e = new CallExp(loc, e, parseArguments());
5703: break;
5704: }
5705:
5706:
5707: case TOKlparen:
5708: { Token *tk;
5709:
5710: tk = peek(&token);
5711: #if CCASTSYNTAX
5712: // If cast
5713: if (isDeclaration(tk, 0, TOKrparen, &tk))
5714: {
5715: tk = peek(tk); // skip over right parenthesis
5716: switch (tk->value)
5717: {
5718: case TOKnot:
5719: tk = peek(tk);
5720: if (tk->value == TOKis || tk->value == TOKin) // !is or !in
5721: break;
5722: case TOKdot:
5723: case TOKplusplus:
5724: case TOKminusminus:
5725: case TOKdelete:
5726: case TOKnew:
5727: case TOKlparen:
5728: case TOKidentifier:
5729: case TOKthis:
5730: case TOKsuper:
5731: case TOKint32v:
5732: case TOKuns32v:
5733: case TOKint64v:
5734: case TOKuns64v:
5735: case TOKfloat32v:
5736: case TOKfloat64v:
5737: case TOKfloat80v:
5738: case TOKimaginary32v:
5739: case TOKimaginary64v:
5740: case TOKimaginary80v:
5741: case TOKnull:
5742: case TOKtrue:
5743: case TOKfalse:
5744: case TOKcharv:
5745: case TOKwcharv:
5746: case TOKdcharv:
5747: case TOKstring:
5748: #if 0
5749: case TOKtilde:
5750: case TOKand:
5751: case TOKmul:
5752: case TOKmin:
5753: case TOKadd:
5754: #endif
5755: case TOKfunction:
5756: case TOKdelegate:
5757: case TOKtypeof:
5758: #if DMDV2
5759: case TOKfile:
5760: case TOKline:
5761: #endif
5762: case BASIC_TYPES: // (type)int.size
5763: { // (type) una_exp
5764: Type *t;
5765:
5766: nextToken();
5767: t = parseType();
5768: check(TOKrparen);
5769:
5770: // if .identifier
5771: if (token.value == TOKdot)
5772: {
5773: nextToken();
5774: if (token.value != TOKidentifier)
5775: { error("Identifier expected following (type).");
5776: return NULL;
5777: }
5778: e = typeDotIdExp(loc, t, token.ident);
5779: nextToken();
5780: e = parsePostExp(e);
5781: }
5782: else
5783: {
5784: e = parseUnaryExp();
5785: e = new CastExp(loc, e, t);
5786: error("C style cast illegal, use %s", e->toChars());
5787: }
5788: return e;
5789: }
5790: }
5791: }
5792: #endif
5793: e = parsePrimaryExp();
5794: e = parsePostExp(e);
5795: break;
5796: }
5797: default:
5798: e = parsePrimaryExp();
5799: e = parsePostExp(e);
5800: break;
5801: }
5802: assert(e);
5803:
5804: // ^^ is right associative and has higher precedence than the unary operators
5805: while (token.value == TOKpow)
5806: {
5807: nextToken();
5808: Expression *e2 = parseUnaryExp();
5809: e = new PowExp(loc, e, e2);
5810: }
5811:
5812: return e;
5813: }
5814:
5815: Expression *Parser::parseMulExp()
5816: { Expression *e;
5817: Expression *e2;
5818: Loc loc = this->loc;
5819:
5820: e = parseUnaryExp();
5821: while (1)
5822: {
5823: switch (token.value)
5824: {
5825: case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5826: case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5827: case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5828:
5829: default:
5830: break;
5831: }
5832: break;
5833: }
5834: return e;
5835: }
5836:
5837: Expression *Parser::parseAddExp()
5838: { Expression *e;
5839: Expression *e2;
5840: Loc loc = this->loc;
5841:
5842: e = parseMulExp();
5843: while (1)
5844: {
5845: switch (token.value)
5846: {
5847: case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5848: case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5849: case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5850:
5851: default:
5852: break;
5853: }
5854: break;
5855: }
5856: return e;
5857: }
5858:
5859: Expression *Parser::parseShiftExp()
5860: { Expression *e;
5861: Expression *e2;
5862: Loc loc = this->loc;
5863:
5864: e = parseAddExp();
5865: while (1)
5866: {
5867: switch (token.value)
5868: {
5869: case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5870: case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5871: case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5872:
5873: default:
5874: break;
5875: }
5876: break;
5877: }
5878: return e;
5879: }
5880:
5881: #if DMDV1
5882: Expression *Parser::parseRelExp()
5883: { Expression *e;
5884: Expression *e2;
5885: enum TOK op;
5886: Loc loc = this->loc;
5887:
5888: e = parseShiftExp();
5889: while (1)
5890: {
5891: switch (token.value)
5892: {
5893: case TOKlt:
5894: case TOKle:
5895: case TOKgt:
5896: case TOKge:
5897: case TOKunord:
5898: case TOKlg:
5899: case TOKleg:
5900: case TOKule:
5901: case TOKul:
5902: case TOKuge:
5903: case TOKug:
5904: case TOKue:
5905: op = token.value;
5906: nextToken();
5907: e2 = parseShiftExp();
5908: e = new CmpExp(op, loc, e, e2);
5909: continue;
5910:
5911: case TOKnot: // could be !in
5912: if (peekNext() == TOKin)
5913: {
5914: nextToken();
5915: nextToken();
5916: e2 = parseShiftExp();
5917: e = new InExp(loc, e, e2);
5918: e = new NotExp(loc, e);
5919: continue;
5920: }
5921: break;
5922:
5923: case TOKin:
5924: nextToken();
5925: e2 = parseShiftExp();
5926: e = new InExp(loc, e, e2);
5927: continue;
5928:
5929: default:
5930: break;
5931: }
5932: break;
5933: }
5934: return e;
5935: }
5936: #endif
5937:
5938: #if DMDV1
5939: Expression *Parser::parseEqualExp()
5940: { Expression *e;
5941: Expression *e2;
5942: Token *t;
5943: Loc loc = this->loc;
5944:
5945: e = parseRelExp();
5946: while (1)
5947: { enum TOK value = token.value;
5948:
5949: switch (value)
5950: {
5951: case TOKequal:
5952: case TOKnotequal:
5953: nextToken();
5954: e2 = parseRelExp();
5955: e = new EqualExp(value, loc, e, e2);
5956: continue;
5957:
5958: case TOKidentity:
5959: error("'===' is no longer legal, use 'is' instead");
5960: goto L1;
5961:
5962: case TOKnotidentity:
5963: error("'!==' is no longer legal, use '!is' instead");
5964: goto L1;
5965:
5966: case TOKis:
5967: value = TOKidentity;
5968: goto L1;
5969:
5970: case TOKnot:
5971: // Attempt to identify '!is'
5972: t = peek(&token);
5973: if (t->value != TOKis)
5974: break;
5975: nextToken();
5976: value = TOKnotidentity;
5977: goto L1;
5978:
5979: L1:
5980: nextToken();
5981: e2 = parseRelExp();
5982: e = new IdentityExp(value, loc, e, e2);
5983: continue;
5984:
5985: default:
5986: break;
5987: }
5988: break;
5989: }
5990: return e;
5991: }
5992: #endif
5993:
5994: Expression *Parser::parseCmpExp()
5995: { Expression *e;
5996: Expression *e2;
5997: Token *t;
5998: Loc loc = this->loc;
5999:
6000: e = parseShiftExp();
6001: enum TOK op = token.value;
6002:
6003: switch (op)
6004: {
6005: case TOKequal:
6006: case TOKnotequal:
6007: nextToken();
6008: e2 = parseShiftExp();
6009: e = new EqualExp(op, loc, e, e2);
6010: break;
6011:
6012: case TOKis:
6013: op = TOKidentity;
6014: goto L1;
6015:
6016: case TOKnot:
6017: // Attempt to identify '!is'
6018: t = peek(&token);
6019: if (t->value == TOKin)
6020: {
6021: nextToken();
6022: nextToken();
6023: e2 = parseShiftExp();
6024: e = new InExp(loc, e, e2);
6025: e = new NotExp(loc, e);
6026: break;
6027: }
6028: if (t->value != TOKis)
6029: break;
6030: nextToken();
6031: op = TOKnotidentity;
6032: goto L1;
6033:
6034: L1:
6035: nextToken();
6036: e2 = parseShiftExp();
6037: e = new IdentityExp(op, loc, e, e2);
6038: break;
6039:
6040: case TOKlt:
6041: case TOKle:
6042: case TOKgt:
6043: case TOKge:
6044: case TOKunord:
6045: case TOKlg:
6046: case TOKleg:
6047: case TOKule:
6048: case TOKul:
6049: case TOKuge:
6050: case TOKug:
6051: case TOKue:
6052: nextToken();
6053: e2 = parseShiftExp();
6054: e = new CmpExp(op, loc, e, e2);
6055: break;
6056:
6057: case TOKin:
6058: nextToken();
6059: e2 = parseShiftExp();
6060: e = new InExp(loc, e, e2);
6061: break;
6062:
6063: default:
6064: break;
6065: }
6066: return e;
6067: }
6068:
6069: Expression *Parser::parseAndExp()
6070: {
6071: Loc loc = this->loc;
6072:
6073: Expression *e = parseCmpExp();
6074: while (token.value == TOKand)
6075: {
6076: checkParens(TOKand, e);
6077: nextToken();
6078: Expression *e2 = parseCmpExp();
6079: checkParens(TOKand, e2);
6080: e = new AndExp(loc,e,e2);
6081: loc = this->loc;
6082: }
6083: return e;
6084: }
6085:
6086: Expression *Parser::parseXorExp()
6087: {
6088: Loc loc = this->loc;
6089:
6090: Expression *e = parseAndExp();
6091: while (token.value == TOKxor)
6092: {
6093: checkParens(TOKxor, e);
6094: nextToken();
6095: Expression *e2 = parseAndExp();
6096: checkParens(TOKxor, e2);
6097: e = new XorExp(loc, e, e2);
6098: }
6099: return e;
6100: }
6101:
6102: Expression *Parser::parseOrExp()
6103: {
6104: Loc loc = this->loc;
6105:
6106: Expression *e = parseXorExp();
6107: while (token.value == TOKor)
6108: {
6109: checkParens(TOKor, e);
6110: nextToken();
6111: Expression *e2 = parseXorExp();
6112: checkParens(TOKor, e2);
6113: e = new OrExp(loc, e, e2);
6114: }
6115: return e;
6116: }
6117:
6118: Expression *Parser::parseAndAndExp()
6119: { Expression *e;
6120: Expression *e2;
6121: Loc loc = this->loc;
6122:
6123: e = parseOrExp();
6124: while (token.value == TOKandand)
6125: {
6126: nextToken();
6127: e2 = parseOrExp();
6128: e = new AndAndExp(loc, e, e2);
6129: }
6130: return e;
6131: }
6132:
6133: Expression *Parser::parseOrOrExp()
6134: { Expression *e;
6135: Expression *e2;
6136: Loc loc = this->loc;
6137:
6138: e = parseAndAndExp();
6139: while (token.value == TOKoror)
6140: {
6141: nextToken();
6142: e2 = parseAndAndExp();
6143: e = new OrOrExp(loc, e, e2);
6144: }
6145: return e;
6146: }
6147:
6148: Expression *Parser::parseCondExp()
6149: { Expression *e;
6150: Expression *e1;
6151: Expression *e2;
6152: Loc loc = this->loc;
6153:
6154: e = parseOrOrExp();
6155: if (token.value == TOKquestion)
6156: {
6157: nextToken();
6158: e1 = parseExpression();
6159: check(TOKcolon);
6160: e2 = parseCondExp();
6161: e = new CondExp(loc, e, e1, e2);
6162: }
6163: return e;
6164: }
6165:
6166: Expression *Parser::parseAssignExp()
6167: { Expression *e;
6168: Expression *e2;
6169: Loc loc;
6170:
6171: e = parseCondExp();
6172: while (1)
6173: {
6174: loc = this->loc;
6175: switch (token.value)
6176: {
6177: #define X(tok,ector) \
6178: case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
6179:
6180: X(TOKassign, AssignExp);
6181: X(TOKaddass, AddAssignExp);
6182: X(TOKminass, MinAssignExp);
6183: X(TOKmulass, MulAssignExp);
6184: X(TOKdivass, DivAssignExp);
6185: X(TOKmodass, ModAssignExp);
6186: X(TOKpowass, PowAssignExp);
6187: X(TOKandass, AndAssignExp);
6188: X(TOKorass, OrAssignExp);
6189: X(TOKxorass, XorAssignExp);
6190: X(TOKshlass, ShlAssignExp);
6191: X(TOKshrass, ShrAssignExp);
6192: X(TOKushrass, UshrAssignExp);
6193: X(TOKcatass, CatAssignExp);
6194:
6195: #undef X
6196: default:
6197: break;
6198: }
6199: break;
6200: }
6201: return e;
6202: }
6203:
6204: Expression *Parser::parseExpression()
6205: { Expression *e;
6206: Expression *e2;
6207: Loc loc = this->loc;
6208:
6209: //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
6210: e = parseAssignExp();
6211: while (token.value == TOKcomma)
6212: {
6213: nextToken();
6214: e2 = parseAssignExp();
6215: e = new CommaExp(loc, e, e2);
6216: loc = this->loc;
6217: }
6218: return e;
6219: }
6220:
6221:
6222: /*************************
6223: * Collect argument list.
6224: * Assume current token is ',', '(' or '['.
6225: */
6226:
6227: Expressions *Parser::parseArguments()
6228: { // function call
6229: Expressions *arguments;
6230: Expression *arg;
6231: enum TOK endtok;
6232:
6233: arguments = new Expressions();
6234: if (token.value == TOKlbracket)
6235: endtok = TOKrbracket;
6236: else
6237: endtok = TOKrparen;
6238:
6239: {
6240: nextToken();
6241: while (token.value != endtok)
6242: {
6243: arg = parseAssignExp();
6244: arguments->push(arg);
6245: if (token.value == endtok)
6246: break;
6247: check(TOKcomma);
6248: }
6249: check(endtok);
6250: }
6251: return arguments;
6252: }
6253:
6254: /*******************************************
6255: */
6256:
6257: Expression *Parser::parseNewExp(Expression *thisexp)
6258: { Type *t;
6259: Expressions *newargs;
6260: Expressions *arguments = NULL;
6261: Expression *e;
6262: Loc loc = this->loc;
6263:
6264: nextToken();
6265: newargs = NULL;
6266: if (token.value == TOKlparen)
6267: {
6268: newargs = parseArguments();
6269: }
6270:
6271: // An anonymous nested class starts with "class"
6272: if (token.value == TOKclass)
6273: {
6274: nextToken();
6275: if (token.value == TOKlparen)
6276: arguments = parseArguments();
6277:
6278: BaseClasses *baseclasses = NULL;
6279: if (token.value != TOKlcurly)
6280: baseclasses = parseBaseClasses();
6281:
6282: Identifier *id = NULL;
6283: ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
6284:
6285: if (token.value != TOKlcurly)
6286: { error("{ members } expected for anonymous class");
6287: cd->members = NULL;
6288: }
6289: else
6290: {
6291: nextToken();
6292: Dsymbols *decl = parseDeclDefs(0);
6293: if (token.value != TOKrcurly)
6294: error("class member expected");
6295: nextToken();
6296: cd->members = decl;
6297: }
6298:
6299: e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
6300:
6301: return e;
6302: }
6303:
6304: t = parseBasicType();
6305: t = parseBasicType2(t);
6306: if (t->ty == Taarray)
6307: { TypeAArray *taa = (TypeAArray *)t;
6308: Type *index = taa->index;
6309:
6310: Expression *e = index->toExpression();
warning C6246: Local declaration of 'e' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '6261' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 6261
6311: if (e)
6312: { arguments = new Expressions();
warning C6211: Leaking memory 'arguments' due to an exception. Consider using a local catch block to clean up memory: Lines: 6258, 6259, 6260, 6261, 6262, 6264, 6265, 6266, 6272, 6304, 6305, 6306, 6307, 6308, 6310, 6311, 6312, 6313, 6314
6313: arguments->push(e);
6314: t = new TypeDArray(taa->next);
6315: }
6316: else
6317: {
6318: error("need size of rightmost array, not type %s", index->toChars());
6319: return new NullExp(loc);
6320: }
6321: }
6322: else if (t->ty == Tsarray)
6323: {
6324: TypeSArray *tsa = (TypeSArray *)t;
6325: Expression *e = tsa->dim;
warning C6246: Local declaration of 'e' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '6261' of 'c:\projects\extern\d\dmd\src\parse.c': Lines: 6261
6326:
6327: arguments = new Expressions();
6328: arguments->push(e);
6329: t = new TypeDArray(tsa->next);
6330: }
6331: else if (token.value == TOKlparen)
6332: {
6333: arguments = parseArguments();
6334: }
6335: e = new NewExp(loc, thisexp, newargs, t, arguments);
6336: return e;
6337: }
6338:
6339: /**********************************************
6340: */
6341:
6342: void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
6343: {
6344: s->addComment(combineComments(blockComment, token.lineComment));
6345: token.lineComment = NULL;
6346: }
6347:
6348:
6349: /**********************************
6350: * Set operator precedence for each operator.
6351: */
6352:
6353: enum PREC precedence[TOKMAX];
6354:
6355: void initPrecedence()
6356: {
6357: for (int i = 0; i < TOKMAX; i++)
6358: precedence[i] = PREC_zero;
6359:
6360: precedence[TOKtype] = PREC_expr;
6361: precedence[TOKerror] = PREC_expr;
6362:
6363: precedence[TOKtypeof] = PREC_primary;
6364: precedence[TOKmixin] = PREC_primary;
6365:
6366: precedence[TOKdotvar] = PREC_primary;
6367: precedence[TOKimport] = PREC_primary;
6368: precedence[TOKidentifier] = PREC_primary;
6369: precedence[TOKthis] = PREC_primary;
6370: precedence[TOKsuper] = PREC_primary;
6371: precedence[TOKint64] = PREC_primary;
6372: precedence[TOKfloat64] = PREC_primary;
6373: precedence[TOKcomplex80] = PREC_primary;
6374: precedence[TOKnull] = PREC_primary;
6375: precedence[TOKstring] = PREC_primary;
6376: precedence[TOKarrayliteral] = PREC_primary;
6377: precedence[TOKassocarrayliteral] = PREC_primary;
6378: #if DMDV2
6379: precedence[TOKfile] = PREC_primary;
6380: precedence[TOKline] = PREC_primary;
6381: #endif
6382: precedence[TOKtypeid] = PREC_primary;
6383: precedence[TOKis] = PREC_primary;
6384: precedence[TOKassert] = PREC_primary;
6385: precedence[TOKhalt] = PREC_primary;
6386: precedence[TOKtemplate] = PREC_primary;
6387: precedence[TOKdsymbol] = PREC_primary;
6388: precedence[TOKfunction] = PREC_primary;
6389: precedence[TOKvar] = PREC_primary;
6390: precedence[TOKsymoff] = PREC_primary;
6391: precedence[TOKstructliteral] = PREC_primary;
6392: precedence[TOKarraylength] = PREC_primary;
6393: precedence[TOKremove] = PREC_primary;
6394: precedence[TOKtuple] = PREC_primary;
6395: #if DMDV2
6396: precedence[TOKtraits] = PREC_primary;
6397: precedence[TOKdefault] = PREC_primary;
6398: precedence[TOKoverloadset] = PREC_primary;
6399: #endif
6400:
6401: // post
6402: precedence[TOKdotti] = PREC_primary;
6403: precedence[TOKdot] = PREC_primary;
6404: precedence[TOKdottd] = PREC_primary;
6405: precedence[TOKdotexp] = PREC_primary;
6406: precedence[TOKdottype] = PREC_primary;
6407: // precedence[TOKarrow] = PREC_primary;
6408: precedence[TOKplusplus] = PREC_primary;
6409: precedence[TOKminusminus] = PREC_primary;
6410: #if DMDV2
6411: precedence[TOKpreplusplus] = PREC_primary;
6412: precedence[TOKpreminusminus] = PREC_primary;
6413: #endif
6414: precedence[TOKcall] = PREC_primary;
6415: precedence[TOKslice] = PREC_primary;
6416: precedence[TOKarray] = PREC_primary;
6417: precedence[TOKindex] = PREC_primary;
6418:
6419: precedence[TOKdelegate] = PREC_unary;
6420: precedence[TOKaddress] = PREC_unary;
6421: precedence[TOKstar] = PREC_unary;
6422: precedence[TOKneg] = PREC_unary;
6423: precedence[TOKuadd] = PREC_unary;
6424: precedence[TOKnot] = PREC_unary;
6425: precedence[TOKtobool] = PREC_add;
6426: precedence[TOKtilde] = PREC_unary;
6427: precedence[TOKdelete] = PREC_unary;
6428: precedence[TOKnew] = PREC_unary;
6429: precedence[TOKnewanonclass] = PREC_unary;
6430: precedence[TOKcast] = PREC_unary;
6431:
6432: #if DMDV2
6433: precedence[TOKpow] = PREC_pow;
6434: #endif
6435:
6436: precedence[TOKmul] = PREC_mul;
6437: precedence[TOKdiv] = PREC_mul;
6438: precedence[TOKmod] = PREC_mul;
6439:
6440: precedence[TOKadd] = PREC_add;
6441: precedence[TOKmin] = PREC_add;
6442: precedence[TOKcat] = PREC_add;
6443:
6444: precedence[TOKshl] = PREC_shift;
6445: precedence[TOKshr] = PREC_shift;
6446: precedence[TOKushr] = PREC_shift;
6447:
6448: precedence[TOKlt] = PREC_rel;
6449: precedence[TOKle] = PREC_rel;
6450: precedence[TOKgt] = PREC_rel;
6451: precedence[TOKge] = PREC_rel;
6452: precedence[TOKunord] = PREC_rel;
6453: precedence[TOKlg] = PREC_rel;
6454: precedence[TOKleg] = PREC_rel;
6455: precedence[TOKule] = PREC_rel;
6456: precedence[TOKul] = PREC_rel;
6457: precedence[TOKuge] = PREC_rel;
6458: precedence[TOKug] = PREC_rel;
6459: precedence[TOKue] = PREC_rel;
6460: precedence[TOKin] = PREC_rel;
6461:
6462: #if 0
6463: precedence[TOKequal] = PREC_equal;
6464: precedence[TOKnotequal] = PREC_equal;
6465: precedence[TOKidentity] = PREC_equal;
6466: precedence[TOKnotidentity] = PREC_equal;
6467: #else
6468: /* Note that we changed precedence, so that < and != have the same
6469: * precedence. This change is in the parser, too.
6470: */
6471: precedence[TOKequal] = PREC_rel;
6472: precedence[TOKnotequal] = PREC_rel;
6473: precedence[TOKidentity] = PREC_rel;
6474: precedence[TOKnotidentity] = PREC_rel;
6475: #endif
6476:
6477: precedence[TOKand] = PREC_and;
6478:
6479: precedence[TOKxor] = PREC_xor;
6480:
6481: precedence[TOKor] = PREC_or;
6482:
6483: precedence[TOKandand] = PREC_andand;
6484:
6485: precedence[TOKoror] = PREC_oror;
6486:
6487: precedence[TOKquestion] = PREC_cond;
6488:
6489: precedence[TOKassign] = PREC_assign;
6490: precedence[TOKconstruct] = PREC_assign;
6491: precedence[TOKblit] = PREC_assign;
6492: precedence[TOKaddass] = PREC_assign;
6493: precedence[TOKminass] = PREC_assign;
6494: precedence[TOKcatass] = PREC_assign;
6495: precedence[TOKmulass] = PREC_assign;
6496: precedence[TOKdivass] = PREC_assign;
6497: precedence[TOKmodass] = PREC_assign;
6498: #if DMDV2
6499: precedence[TOKpowass] = PREC_assign;
6500: #endif
6501: precedence[TOKshlass] = PREC_assign;
6502: precedence[TOKshrass] = PREC_assign;
6503: precedence[TOKushrass] = PREC_assign;
6504: precedence[TOKandass] = PREC_assign;
6505: precedence[TOKorass] = PREC_assign;
6506: precedence[TOKxorass] = PREC_assign;
6507:
6508: precedence[TOKcomma] = PREC_expr;
6509: precedence[TOKdeclaration] = PREC_expr;
6510: }
6511:
6512:
6513: