diff dmd/Parser.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 7427ded8caf7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/Parser.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,5951 @@
+module dmd.Parser;
+
+import dmd.Lexer;
+import dmd.PostBlitDeclaration;
+import dmd.FileInitExp;
+import dmd.LineInitExp;
+import dmd.EnumMember;
+import dmd.CtorDeclaration;
+import dmd.ShlAssignExp;
+import dmd.ShrAssignExp;
+import dmd.UshrAssignExp;
+import dmd.CatAssignExp;
+import dmd.StaticIfCondition;
+import dmd.TraitsExp;
+import dmd.BaseClass;
+import dmd.AssignExp;
+import dmd.TemplateInstance;
+import dmd.NewExp;
+import dmd.ArrayExp;
+import dmd.DotTemplateInstanceExp;
+import dmd.ClassDeclaration;
+import dmd.NewAnonClassExp;
+import dmd.InterfaceDeclaration;
+import dmd.StructDeclaration;
+import dmd.UnionDeclaration;
+import dmd.AnonDeclaration;
+import dmd.StructInitializer;
+import dmd.ArrayInitializer;
+import dmd.ExpInitializer;
+import dmd.TemplateAliasParameter;
+import dmd.TemplateTupleParameter;
+import dmd.TemplateThisParameter;
+import dmd.TemplateValueParameter;
+import dmd.VoidInitializer;
+import dmd.VersionCondition;
+import dmd.DotIdExp;
+import dmd.DebugCondition;
+import dmd.PostExp;
+import dmd.CallExp;
+import dmd.SliceExp;
+import dmd.FuncExp;
+import dmd.AssocArrayLiteralExp;
+import dmd.ArrayLiteralExp;
+import dmd.IsExp;
+import dmd.FuncLiteralDeclaration;
+import dmd.AssertExp;
+import dmd.CompileExp;
+import dmd.FileExp;
+import dmd.TemplateParameter;
+import dmd.TemplateTypeParameter;
+import dmd.TypeidExp;
+import dmd.StringExp;
+import dmd.ScopeExp;
+import dmd.IdentifierExp;
+import dmd.DollarExp;
+import dmd.ThisExp;
+import dmd.SuperExp;
+import dmd.NullExp;
+import dmd.RealExp;
+import dmd.TypeExp;
+import dmd.AddrExp;
+import dmd.MOD;
+import dmd.IntegerExp;
+import dmd.CastExp;
+import dmd.PtrExp;
+import dmd.NegExp;
+import dmd.XorAssignExp;
+import dmd.OrAssignExp;
+import dmd.UAddExp;
+import dmd.NotExp;
+import dmd.ComExp;
+import dmd.DeleteExp;
+import dmd.MulAssignExp;
+import dmd.ModAssignExp;
+import dmd.MinAssignExp;
+import dmd.DivAssignExp;
+import dmd.AndAssignExp;
+import dmd.AddAssignExp;
+import dmd.ModuleDeclaration;
+import dmd.CaseRangeStatement;
+import dmd.CommaExp;
+import dmd.XorExp;
+import dmd.CondExp;
+import dmd.CmpExp;
+import dmd.InExp;
+import dmd.OrOrExp;
+import dmd.OrExp;
+import dmd.AddExp;
+import dmd.MinExp;
+import dmd.CatExp;
+import dmd.AndAndExp;
+import dmd.EqualExp;
+import dmd.ShlExp;
+import dmd.ShrExp;
+import dmd.DivExp;
+import dmd.MulExp;
+import dmd.ModExp;
+import dmd.UshrExp;
+import dmd.IdentityExp;
+import dmd.AndExp;
+import dmd.Id;
+import dmd.LabelStatement;
+import dmd.ExpStatement;
+import dmd.StaticAssertStatement;
+import dmd.DeclarationStatement;
+import dmd.ScopeStatement;
+import dmd.PragmaStatement;
+import dmd.WhileStatement;
+import dmd.DoStatement;
+import dmd.ForStatement;
+import dmd.OnScopeStatement;
+import dmd.IfStatement;
+import dmd.SwitchStatement;
+import dmd.CaseStatement;
+import dmd.DefaultStatement;
+import dmd.GotoDefaultStatement;
+import dmd.GotoCaseStatement;
+import dmd.GotoStatement;
+import dmd.SynchronizedStatement;
+import dmd.WithStatement;
+import dmd.Catch;
+import dmd.TryCatchStatement;
+import dmd.TryFinallyStatement;
+import dmd.ThrowStatement;
+import dmd.VolatileStatement;
+import dmd.ReturnStatement;
+import dmd.BreakStatement;
+import dmd.ContinueStatement;
+import dmd.AsmStatement;
+import dmd.TypeReturn;
+import dmd.TypeTypeof;
+import dmd.ForeachRangeStatement;
+import dmd.ForeachStatement;
+import dmd.CompileStatement;
+import dmd.CompoundStatement;
+import dmd.ConditionalStatement;
+import dmd.CompoundDeclarationStatement;
+import dmd.Argument;
+import dmd.ParseStatementFlags;
+import dmd.TypeNext;
+import dmd.TypeInstance;
+import dmd.TypePointer;
+import dmd.TypeDArray;
+import dmd.TypeAArray;
+import dmd.TypeSlice;
+import dmd.TypeSArray;
+import dmd.TemplateInstance;
+import dmd.TypeIdentifier;
+import dmd.VarDeclaration;
+import dmd.TypeFunction;
+import dmd.TypeDelegate;
+import dmd.TY;
+import dmd.LinkDeclaration;
+import dmd.Declaration;
+import dmd.AggregateDeclaration;
+import dmd.TypedefDeclaration;
+import dmd.AliasDeclaration;
+import dmd.LINK;
+import dmd.Loc;
+import dmd.Module;
+import dmd.Array;
+import dmd.Expression;
+import dmd.TemplateDeclaration;
+import dmd.ArrayTypes;
+import dmd.Dsymbol;
+import dmd.StaticAssert;
+import dmd.TypeQualified;
+import dmd.Condition;
+import dmd.PostBlitDeclaration;
+import dmd.DtorDeclaration;
+import dmd.ConditionalDeclaration;
+import dmd.StaticCtorDeclaration;
+import dmd.StaticDtorDeclaration;
+import dmd.InvariantDeclaration;
+import dmd.UnitTestDeclaration;
+import dmd.NewDeclaration;
+import dmd.DeleteDeclaration;
+import dmd.EnumDeclaration;
+import dmd.Import;
+import dmd.Type;
+import dmd.Identifier;
+import dmd.FuncDeclaration;
+import dmd.Statement;
+import dmd.Initializer;
+import dmd.Token;
+import dmd.TOK;
+import dmd.ParseStatementFlags;
+import dmd.PROT;
+import dmd.STC;
+import dmd.Util;
+import dmd.CompileDeclaration;
+import dmd.StaticIfDeclaration;
+import dmd.StorageClassDeclaration;
+import dmd.LinkDeclaration;
+import dmd.ProtDeclaration;
+import dmd.AlignDeclaration;
+import dmd.PragmaDeclaration;
+import dmd.DebugSymbol;
+import dmd.VersionSymbol;
+import dmd.AliasThis;
+import dmd.Global;
+
+import core.stdc.string : memcpy;
+import core.stdc.stdlib : malloc;
+
+import std.contracts;
+
+class Parser : Lexer
+{
+    ModuleDeclaration md;
+    LINK linkage;
+    Loc endloc;			// set to location of last right curly
+    int inBrackets;		// inside [] of array index or slice
+
+    this(Module module_, ubyte* base, uint length, int doDocComment)
+	{
+		super(module_, base, 0, length, doDocComment, 0);
+		//printf("Parser.Parser()\n");
+		linkage = LINK.LINKd;
+		//nextToken();		// start up the scanner
+	}
+	
+    Array parseModule()
+	{
+		Array decldefs;
+
+		// ModuleDeclation leads off
+		if (token.value == TOK.TOKmodule)
+		{
+			ubyte* comment = token.blockComment;
+			bool safe = false;
+
+			nextToken();
+version (DMDV2) {
+			if (token.value == TOK.TOKlparen)
+			{
+				nextToken();
+				if (token.value != TOK.TOKidentifier)
+				{
+					error("module (system) identifier expected");
+					goto Lerr;
+				}
+				Identifier id = token.ident;
+
+				if (id is Id.system)
+					safe = true;
+				else
+					error("(safe) expected, not %s", id.toChars());
+				nextToken();
+				check(TOK.TOKrparen);
+			}
+}
+
+			if (token.value != TOK.TOKidentifier)
+			{
+				error("Identifier expected following module");
+				goto Lerr;
+			}
+			else
+			{
+				Array a = null;
+				Identifier id = token.ident;
+				while (nextToken() == TOK.TOKdot)
+				{
+					if (!a)
+						a = new Array();
+					a.push(cast(void*)id);
+					nextToken();
+					if (token.value != TOK.TOKidentifier)
+					{   error("Identifier expected following package");
+						goto Lerr;
+					}
+					id = token.ident;
+				}
+
+				md = new ModuleDeclaration(a, id, safe);
+
+				if (token.value != TOK.TOKsemicolon)
+					error("';' expected following module declaration instead of %s", token.toChars());
+
+				nextToken();
+				addComment(mod, comment);
+			}
+		}
+
+		decldefs = parseDeclDefs(0);
+		if (token.value != TOK.TOKeof)
+		{
+			error("unrecognized declaration");
+			goto Lerr;
+		}
+
+		return decldefs;
+
+	Lerr:
+		while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof)
+			nextToken();
+
+		nextToken();
+		return new Array();
+	}
+	
+    Array parseDeclDefs(int once)
+	{
+		Dsymbol s;
+		Array decldefs;
+		Array a;
+		Array aelse;
+		PROT prot;
+		STC stc;
+		STC storageClass;
+		Condition  condition;
+		ubyte* comment;
+
+		//printf("Parser.parseDeclDefs()\n");
+		decldefs = new Array();
+		do
+		{
+		comment = token.blockComment;
+		storageClass = STC.STCundefined;
+		switch (token.value)
+		{
+			case TOK.TOKenum:
+			{	/* Determine if this is a manifest constant declaration,
+			 * or a conventional enum.
+			 */
+			Token *t = peek(&token);
+			if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon)
+				s = parseEnum();
+			else if (t.value != TOK.TOKidentifier)
+				goto Ldeclaration;
+			else
+			{
+				t = peek(t);
+				if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon ||
+				t.value == TOK.TOKsemicolon)
+				s = parseEnum();
+				else
+				goto Ldeclaration;
+			}
+			break;
+			}
+
+			case TOK.TOKstruct:
+			case TOK.TOKunion:
+			case TOK.TOKclass:
+			case TOK.TOKinterface:
+			s = parseAggregate();
+			break;
+
+			case TOK.TOKimport:
+			s = parseImport(decldefs, 0);
+			break;
+
+			case TOK.TOKtemplate:
+			s = cast(Dsymbol)parseTemplateDeclaration();
+			break;
+
+			case TOK.TOKmixin:
+			{	Loc loc = this.loc;
+			if (peek(&token).value == TOK.TOKlparen)
+			{   // mixin(string)
+				nextToken();
+				check(TOK.TOKlparen, "mixin");
+				Expression e = parseAssignExp();
+				check(TOK.TOKrparen);
+				check(TOK.TOKsemicolon);
+				s = new CompileDeclaration(loc, e);
+				break;
+			}
+			s = parseMixin();
+			break;
+			}
+
+			case TOK.TOKwchar: case TOK.TOKdchar:
+			case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
+			case TOK.TOKint8: case TOK.TOKuns8:
+			case TOK.TOKint16: case TOK.TOKuns16:
+			case TOK.TOKint32: case TOK.TOKuns32:
+			case TOK.TOKint64: case TOK.TOKuns64:
+			case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
+			case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
+			case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
+			case TOK.TOKvoid:
+			case TOK.TOKalias:
+			case TOK.TOKtypedef:
+			case TOK.TOKidentifier:
+			case TOK.TOKtypeof:
+			case TOK.TOKdot:
+			Ldeclaration:
+			a = parseDeclarations(STC.STCundefined);
+			decldefs.append(a);
+			continue;
+
+			case TOK.TOKthis:
+			s = parseCtor();
+			break;
+
+static if (false) { // dead end, use this(this){} instead
+			case TOK.TOKassign:
+			s = parsePostBlit();
+			break;
+}
+			case TOK.TOKtilde:
+			s = parseDtor();
+			break;
+
+			case TOK.TOKinvariant:
+			{	Token *t;
+			t = peek(&token);
+			if (t.value == TOK.TOKlparen)
+			{
+				if (peek(t).value == TOK.TOKrparen)
+				// invariant() forms start of class invariant
+				s = parseInvariant();
+				else
+				// invariant(type)
+				goto Ldeclaration;
+			}
+			else
+			{
+				stc = STC.STCimmutable;
+				goto Lstc;
+			}
+			break;
+			}
+
+			case TOK.TOKunittest:
+			s = parseUnitTest();
+			break;
+
+			case TOK.TOKnew:
+			s = parseNew();
+			break;
+
+			case TOK.TOKdelete:
+			s = parseDelete();
+			break;
+
+			case TOK.TOKeof:
+			case TOK.TOKrcurly:
+			return decldefs;
+
+			case TOK.TOKstatic:
+			nextToken();
+			if (token.value == TOK.TOKthis)
+				s = parseStaticCtor();
+			else if (token.value == TOK.TOKtilde)
+				s = parseStaticDtor();
+			else if (token.value == TOK.TOKassert)
+				s = parseStaticAssert();
+			else if (token.value == TOK.TOKif)
+			{   condition = parseStaticIfCondition();
+				a = parseBlock();
+				aelse = null;
+				if (token.value == TOK.TOKelse)
+				{   nextToken();
+				aelse = parseBlock();
+				}
+				s = new StaticIfDeclaration(condition, a, aelse);
+				break;
+			}
+			else if (token.value == TOK.TOKimport)
+			{
+				s = parseImport(decldefs, 1);
+			}
+			else
+			{   stc = STC.STCstatic;
+				goto Lstc2;
+			}
+			break;
+
+			case TOK.TOKconst:
+			if (peek(&token).value == TOK.TOKlparen)
+				goto Ldeclaration;
+			stc = STC.STCconst;
+			goto Lstc;
+
+			case TOK.TOKimmutable:
+			if (peek(&token).value == TOK.TOKlparen)
+				goto Ldeclaration;
+			stc = STC.STCimmutable;
+			goto Lstc;
+
+			case TOK.TOKshared:
+			if (peek(&token).value == TOK.TOKlparen)
+				goto Ldeclaration;
+			stc = STC.STCshared;
+			goto Lstc;
+
+			case TOK.TOKfinal:	  stc = STC.STCfinal;	 goto Lstc;
+			case TOK.TOKauto:	  stc = STC.STCauto;	 goto Lstc;
+			case TOK.TOKscope:	  stc = STC.STCscope;	 goto Lstc;
+			case TOK.TOKoverride:	  stc = STC.STCoverride;	 goto Lstc;
+			case TOK.TOKabstract:	  stc = STC.STCabstract;	 goto Lstc;
+			case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc;
+			case TOK.TOKdeprecated:   stc = STC.STCdeprecated;	 goto Lstc;
+version (DMDV2) {
+			case TOK.TOKnothrow:      stc = STC.STCnothrow;	 goto Lstc;
+			case TOK.TOKpure:         stc = STC.STCpure;	 goto Lstc;
+			case TOK.TOKref:          stc = STC.STCref;          goto Lstc;
+			case TOK.TOKtls:          stc = STC.STCtls;		 goto Lstc;
+			case TOK.TOKgshared:      
+				stc = STC.STCgshared;	 goto Lstc;
+			//case TOK.TOKmanifest:	  stc = STC.STCmanifest;	 goto Lstc;
+}
+
+			Lstc:
+			if (storageClass & stc)
+				error("redundant storage class %s", Token.toChars(token.value));
+			composeStorageClass(storageClass | stc);
+			nextToken();
+			Lstc2:
+			storageClass |= stc;
+			switch (token.value)
+			{
+				case TOK.TOKconst:
+				case TOK.TOKinvariant:
+				case TOK.TOKimmutable:
+				case TOK.TOKshared:
+				// If followed by a (, it is not a storage class
+				if (peek(&token).value == TOK.TOKlparen)
+					break;
+				if (token.value == TOK.TOKconst)
+					stc = STC.STCconst;
+				else if (token.value == TOK.TOKshared)
+					stc = STC.STCshared;
+				else
+					stc = STC.STCimmutable;
+				goto Lstc;
+				case TOK.TOKfinal:	  stc = STC.STCfinal;	 goto Lstc;
+				case TOK.TOKauto:	  stc = STC.STCauto;	 goto Lstc;
+				case TOK.TOKscope:	  stc = STC.STCscope;	 goto Lstc;
+				case TOK.TOKoverride:	  stc = STC.STCoverride;	 goto Lstc;
+				case TOK.TOKabstract:	  stc = STC.STCabstract;	 goto Lstc;
+				case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc;
+				case TOK.TOKdeprecated:   stc = STC.STCdeprecated;	 goto Lstc;
+				case TOK.TOKnothrow:      stc = STC.STCnothrow;	 goto Lstc;
+				case TOK.TOKpure:         stc = STC.STCpure;	 goto Lstc;
+				case TOK.TOKref:          stc = STC.STCref;          goto Lstc;
+				case TOK.TOKtls:          stc = STC.STCtls;		 goto Lstc;
+				case TOK.TOKgshared:      stc = STC.STCgshared;	 goto Lstc;
+				//case TOK.TOKmanifest:	  stc = STC.STCmanifest;	 goto Lstc;
+				default:
+				break;
+			}
+
+			/* Look for auto initializers:
+			 *	storage_class identifier = initializer;
+			 */
+			if (token.value == TOK.TOKidentifier &&
+				peek(&token).value == TOK.TOKassign)
+			{
+				a = parseAutoDeclarations(storageClass, comment);
+				decldefs.append(a);
+				continue;
+			}
+
+			/* Look for return type inference for template functions.
+			 */
+			Token *tk;
+			if (token.value == TOK.TOKidentifier &&
+				(tk = peek(&token)).value == TOK.TOKlparen &&
+				skipParens(tk, &tk) &&
+				(peek(tk).value == TOK.TOKlparen ||
+				 peek(tk).value == TOK.TOKlcurly)
+			   )
+			{
+				a = parseDeclarations(storageClass);
+				decldefs.append(a);
+				continue;
+			}
+			a = parseBlock();
+			s = new StorageClassDeclaration(storageClass, a);
+			break;
+
+			case TOK.TOKextern:
+				if (peek(&token).value != TOK.TOKlparen)
+				{   
+					stc = STC.STCextern;
+					goto Lstc;
+				}
+				{
+					LINK linksave = linkage;
+					linkage = parseLinkage();
+					a = parseBlock();
+					s = new LinkDeclaration(linkage, a);
+					linkage = linksave;
+					break;
+				}
+
+			case TOK.TOKprivate:	prot = PROT.PROTprivate;	goto Lprot;
+			case TOK.TOKpackage:	prot = PROT.PROTpackage;	goto Lprot;
+			case TOK.TOKprotected:	prot = PROT.PROTprotected;	goto Lprot;
+			case TOK.TOKpublic:		prot = PROT.PROTpublic;		goto Lprot;
+			case TOK.TOKexport:		prot = PROT.PROTexport;		goto Lprot;
+				Lprot:
+				nextToken();
+				switch (token.value)
+				{
+					case TOK.TOKprivate:
+					case TOK.TOKpackage:
+					case TOK.TOKprotected:
+					case TOK.TOKpublic:
+					case TOK.TOKexport:
+						error("redundant protection attribute");
+						break;
+					default:
+						break;
+				}
+				a = parseBlock();
+				s = new ProtDeclaration(prot, a);
+				break;
+
+			case TOK.TOKalign:
+			{	uint n;
+
+			s = null;
+			nextToken();
+			if (token.value == TOK.TOKlparen)
+			{
+				nextToken();
+				if (token.value == TOK.TOKint32v)
+				n = cast(uint)token.uns64value;
+				else
+				{	error("integer expected, not %s", token.toChars());
+				n = 1;
+				}
+				nextToken();
+				check(TOK.TOKrparen);
+			}
+			else
+				n = global.structalign;		// default
+
+			a = parseBlock();
+			s = new AlignDeclaration(n, a);
+			break;
+			}
+
+			case TOK.TOKpragma:
+			{	Identifier ident;
+			Expressions args = null;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			if (token.value != TOK.TOKidentifier)
+			{   error("pragma(identifier expected");
+				goto Lerror;
+			}
+			ident = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen)
+				args = parseArguments();	// pragma(identifier, args...)
+			else
+				check(TOK.TOKrparen);		// pragma(identifier)
+
+			if (token.value == TOK.TOKsemicolon)
+				a = null;
+			else
+				a = parseBlock();
+			s = new PragmaDeclaration(loc, ident, args, a);
+			break;
+			}
+
+			case TOK.TOKdebug:
+			nextToken();
+			if (token.value == TOK.TOKassign)
+			{
+				nextToken();
+				if (token.value == TOK.TOKidentifier)
+				s = new DebugSymbol(loc, token.ident);
+				else if (token.value == TOK.TOKint32v)
+				s = new DebugSymbol(loc, cast(uint)token.uns64value);
+				else
+				{	error("identifier or integer expected, not %s", token.toChars());
+				s = null;
+				}
+				nextToken();
+				if (token.value != TOK.TOKsemicolon)
+				error("semicolon expected");
+				nextToken();
+				break;
+			}
+
+			condition = parseDebugCondition();
+			goto Lcondition;
+
+			case TOK.TOKversion:
+			nextToken();
+			if (token.value == TOK.TOKassign)
+			{
+				nextToken();
+				if (token.value == TOK.TOKidentifier)
+				s = new VersionSymbol(loc, token.ident);
+				else if (token.value == TOK.TOKint32v)
+				s = new VersionSymbol(loc, cast(uint)token.uns64value);
+				else
+				{	error("identifier or integer expected, not %s", token.toChars());
+				s = null;
+				}
+				nextToken();
+				if (token.value != TOK.TOKsemicolon)
+				error("semicolon expected");
+				nextToken();
+				break;
+			}
+			condition = parseVersionCondition();
+			goto Lcondition;
+
+			Lcondition:
+			a = parseBlock();
+			aelse = null;
+			if (token.value == TOK.TOKelse)
+			{   nextToken();
+				aelse = parseBlock();
+			}
+			s = new ConditionalDeclaration(condition, a, aelse);
+			break;
+
+			case TOK.TOKsemicolon:		// empty declaration
+			nextToken();
+			continue;
+
+			default:
+			error("Declaration expected, not '%s'",token.toChars());
+			Lerror:
+			while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof)
+				nextToken();
+			nextToken();
+			s = null;
+			continue;
+		}
+		if (s)
+		{   decldefs.push(cast(void*)s);
+			addComment(s, comment);
+		}
+		} while (!once);
+		return decldefs;
+	}
+	
+	/*****************************************
+	 * Parse auto declarations of the form:
+	 *   storageClass ident = init, ident = init, ... ;
+	 * and return the array of them.
+	 * Starts with token on the first ident.
+	 * Ends with scanner past closing ';'
+	 */
+version (DMDV2) {
+    Array parseAutoDeclarations(STC storageClass, ubyte* comment)
+	{
+		Array a = new Array;
+
+		while (true)
+		{
+			Identifier ident = token.ident;
+			nextToken();		// skip over ident
+			assert(token.value == TOKassign);
+			nextToken();		// skip over '='
+			Initializer init = parseInitializer();
+			VarDeclaration v = new VarDeclaration(loc, null, ident, init);
+			v.storage_class = storageClass;
+			a.push(cast(void*)v);
+			if (token.value == TOKsemicolon)
+			{
+				nextToken();
+				addComment(v, comment);
+			}
+			else if (token.value == TOKcomma)
+			{
+				nextToken();
+				if (token.value == TOKidentifier &&
+					peek(&token).value == TOKassign)
+				{
+					addComment(v, comment);
+					continue;
+				}
+				else
+					error("Identifier expected following comma");
+			}
+			else
+				error("semicolon expected following auto declaration, not '%s'", token.toChars());
+			break;
+		}
+		return a;
+	}
+}
+	/********************************************
+	 * Parse declarations after an align, protection, or extern decl.
+	 */
+    Array parseBlock()
+	{
+		Array a = null;
+		Dsymbol ss;
+
+		//printf("parseBlock()\n");
+		switch (token.value)
+		{
+		case TOK.TOKsemicolon:
+			error("declaration expected following attribute, not ';'");
+			nextToken();
+			break;
+
+		case TOK.TOKeof:
+			error("declaration expected following attribute, not EOF");
+			break;
+
+		case TOK.TOKlcurly:
+			nextToken();
+			a = parseDeclDefs(0);
+			if (token.value != TOK.TOKrcurly)
+			{   /* { */
+				error("matching '}' expected, not %s", token.toChars());
+			}
+			else
+				nextToken();
+			break;
+
+		case TOK.TOKcolon:
+			nextToken();
+static if (false) {
+			a = null;
+} else {
+			a = parseDeclDefs(0);	// grab declarations up to closing curly bracket
+}
+			break;
+
+		default:
+			a = parseDeclDefs(1);
+			break;
+		}
+		return a;
+	}
+	
+    void composeStorageClass(STC stc)
+	{
+		STC u = stc;
+		u &= STC.STCconst | STC.STCimmutable | STC.STCmanifest;
+		if (u & (u - 1))
+			error("conflicting storage class %s", Token.toChars(token.value));
+
+		u = stc;
+		u &= STC.STCgshared | STC.STCshared | STC.STCtls;
+		if (u & (u - 1))
+			error("conflicting storage class %s", Token.toChars(token.value));
+	}
+	
+	/**************************************
+	 * Parse constraint.
+	 * Constraint is of the form:
+	 *	if ( ConstraintExpression )
+	 */
+version (DMDV2) {
+    Expression parseConstraint()
+	{
+		Expression e = null;
+
+		if (token.value == TOKif)
+		{
+			nextToken();	// skip over 'if'
+			check(TOKlparen);
+			e = parseExpression();
+			check(TOKrparen);
+		}
+		return e;
+	}
+}
+	/**************************************
+	 * Parse a TemplateDeclaration.
+	 */
+    TemplateDeclaration parseTemplateDeclaration()
+	{
+		TemplateDeclaration tempdecl;
+		Identifier id;
+		TemplateParameters tpl;
+		Array decldefs;
+		Expression constraint = null;
+		Loc loc = this.loc;
+
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   
+			error("TemplateIdentifier expected following template");
+			goto Lerr;
+		}
+		id = token.ident;
+		nextToken();
+		tpl = parseTemplateParameterList();
+		if (!tpl)
+			goto Lerr;
+
+		constraint = parseConstraint();
+
+		if (token.value != TOKlcurly)
+		{	
+			error("members of template declaration expected");
+			goto Lerr;
+		}
+		else
+		{
+			nextToken();
+			decldefs = parseDeclDefs(0);
+			if (token.value != TOKrcurly)
+			{   
+				error("template member expected");
+				goto Lerr;
+			}
+			nextToken();
+		}
+
+		tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
+		return tempdecl;
+
+	Lerr:
+		return null;
+	}
+	
+	/******************************************
+	 * Parse template parameter list.
+	 * Input:
+	 *	flag	0: parsing "( list )"
+	 *		1: parsing non-empty "list )"
+	 */
+    TemplateParameters parseTemplateParameterList(int flag = 0)
+	{
+		TemplateParameters tpl = new TemplateParameters();
+
+		if (!flag && token.value != TOKlparen)
+		{   
+			error("parenthesized TemplateParameterList expected following TemplateIdentifier");
+			goto Lerr;
+		}
+		nextToken();
+
+		// Get array of TemplateParameters
+		if (flag || token.value != TOKrparen)
+		{	
+			int isvariadic = 0;
+
+			while (true)
+			{   
+				TemplateParameter tp;
+				Identifier tp_ident = null;
+				Type tp_spectype = null;
+				Type tp_valtype = null;
+				Type tp_defaulttype = null;
+				Expression tp_specvalue = null;
+				Expression tp_defaultvalue = null;
+				Token* t;
+
+				// Get TemplateParameter
+
+				// First, look ahead to see if it is a TypeParameter or a ValueParameter
+				t = peek(&token);
+				if (token.value == TOKalias)
+				{	
+					// AliasParameter
+					nextToken();
+					Type spectype = null;
+					if (isDeclaration(&token, 2, TOKreserved, null))
+					{
+						spectype = parseType(&tp_ident);
+					}
+					else
+					{
+						if (token.value != TOKidentifier)
+						{
+							error("identifier expected for template alias parameter");
+							goto Lerr;
+						}
+						tp_ident = token.ident;
+						nextToken();
+					}
+					Object spec = null;
+					if (token.value == TOKcolon)	// : Type
+					{
+						nextToken();
+						if (isDeclaration(&token, 0, TOKreserved, null))
+							spec = parseType();
+						else
+						spec = parseCondExp();
+					}
+					Object def = null;
+					if (token.value == TOKassign)	// = Type
+					{
+						nextToken();
+						if (isDeclaration(&token, 0, TOKreserved, null))
+							def = parseType();
+						else
+							def = parseCondExp();
+					}
+					tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
+				}
+				else if (t.value == TOKcolon || t.value == TOKassign ||
+					 t.value == TOKcomma || t.value == TOKrparen)
+				{	// TypeParameter
+					if (token.value != TOKidentifier)
+					{   error("identifier expected for template type parameter");
+						goto Lerr;
+					}
+					tp_ident = token.ident;
+					nextToken();
+					if (token.value == TOKcolon)	// : Type
+					{
+						nextToken();
+						tp_spectype = parseType();
+					}
+					if (token.value == TOKassign)	// = Type
+					{
+						nextToken();
+						tp_defaulttype = parseType();
+					}
+					tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+				}
+				else if (token.value == TOKidentifier && t.value == TOKdotdotdot)
+				{	// ident...
+					if (isvariadic)
+						error("variadic template parameter must be last");
+					isvariadic = 1;
+					tp_ident = token.ident;
+					nextToken();
+					nextToken();
+					tp = new TemplateTupleParameter(loc, tp_ident);
+				}
+///		version (DMDV2) {
+				else if (token.value == TOKthis)
+				{	// ThisParameter
+					nextToken();
+					if (token.value != TOKidentifier)
+					{   error("identifier expected for template this parameter");
+						goto Lerr;
+					}
+					tp_ident = token.ident;
+					nextToken();
+					if (token.value == TOKcolon)	// : Type
+					{
+						nextToken();
+						tp_spectype = parseType();
+					}
+					if (token.value == TOKassign)	// = Type
+					{
+						nextToken();
+						tp_defaulttype = parseType();
+					}
+					tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+				}
+///		}
+				else
+				{	// ValueParameter
+					tp_valtype = parseType(&tp_ident);
+					if (!tp_ident)
+					{
+						error("identifier expected for template value parameter");
+						tp_ident = new Identifier("error", TOKidentifier);
+					}
+					if (token.value == TOKcolon)	// : CondExpression
+					{
+						nextToken();
+						tp_specvalue = parseCondExp();
+					}
+					if (token.value == TOKassign)	// = CondExpression
+					{
+						nextToken();
+						tp_defaultvalue = parseDefaultInitExp();
+					}
+					tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+				}
+				tpl.push(cast(void*)tp);
+				if (token.value != TOKcomma)
+					break;
+				nextToken();
+			}
+		}
+		check(TOKrparen);
+
+	Lerr:
+		return tpl;
+	}
+	
+    Dsymbol parseMixin()
+	{
+		assert(false);
+	}
+	
+	/******************************************
+	 * Parse template argument list.
+	 * Input:
+	 * 	current token is opening '('
+	 * Output:
+	 *	current token is one after closing ')'
+	 */
+    Objects parseTemplateArgumentList()
+	{
+		//printf("Parser.parseTemplateArgumentList()\n");
+		if (token.value != TOKlparen && token.value != TOKlcurly)
+		{   
+			error("!(TemplateArgumentList) expected following TemplateIdentifier");
+			return new Objects();
+		}
+		return parseTemplateArgumentList2();
+	}
+	
+    Objects parseTemplateArgumentList2()
+	{
+		//printf("Parser.parseTemplateArgumentList2()\n");
+		Objects tiargs = new Objects();
+		TOK endtok = TOKrparen;
+		nextToken();
+
+		// Get TemplateArgumentList
+		if (token.value != endtok)
+		{
+			while (1)
+			{
+				// See if it is an Expression or a Type
+				if (isDeclaration(&token, 0, TOKreserved, null))
+				{	// Template argument is a type
+					Type ta = parseType();
+					tiargs.push(cast(void*)ta);
+				}
+				else
+				{	// Template argument is an expression
+					Expression ea = parseAssignExp();
+
+					if (ea.op == TOKfunction)
+					{   
+						FuncLiteralDeclaration fd = (cast(FuncExp)ea).fd;
+						if (fd.type.ty == Tfunction)
+						{
+							TypeFunction tf = cast(TypeFunction)fd.type;
+							/* If there are parameters that consist of only an identifier,
+							 * rather than assuming the identifier is a type, as we would
+							 * for regular function declarations, assume the identifier
+							 * is the parameter name, and we're building a template with
+							 * a deduced type.
+							 */
+							TemplateParameters tpl = null;
+							for (int i = 0; i < tf.parameters.dim; i++)
+							{   
+								Argument param = cast(Argument)tf.parameters.data[i];
+								if (param.ident is null &&
+									param.type &&
+									param.type.ty == Tident &&
+									(cast(TypeIdentifier)param.type).idents.dim == 0
+								   )
+								{
+									/* Switch parameter type to parameter identifier,
+									 * parameterize with template type parameter _T
+									 */
+									TypeIdentifier pt = cast(TypeIdentifier)param.type;
+									param.ident = pt.ident;
+									Identifier id = Lexer.uniqueId("__T");
+									param.type = new TypeIdentifier(pt.loc, id);
+									TemplateParameter tp = new TemplateTypeParameter(fd.loc, id, null, null);
+									if (!tpl)
+										tpl = new TemplateParameters();
+									tpl.push(cast(void*)tp);
+								}
+							}
+
+							if (tpl)
+							{   
+								// Wrap a template around function fd
+								Array decldefs = new Array();
+								decldefs.push(cast(void*)fd);
+								TemplateDeclaration tempdecl = new TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs);
+								tempdecl.literal = 1;	// it's a template 'literal'
+								tiargs.push(cast(void*)tempdecl);
+								goto L1;
+							}
+						}
+					}
+
+					tiargs.push(cast(void*)ea);
+				}
+			 L1:
+				if (token.value != TOKcomma)
+					break;
+				nextToken();
+			}
+		}
+		check(endtok, "template argument list");
+		return tiargs;
+	}
+	
+    Objects parseTemplateArgument()
+	{
+		assert(false);
+	}
+	
+	/**********************************
+	 * Parse a static assertion.
+	 */
+    StaticAssert parseStaticAssert()
+	{
+		Loc loc = this.loc;
+		Expression exp;
+		Expression msg = null;
+
+		//printf("parseStaticAssert()\n");
+		nextToken();
+		check(TOK.TOKlparen);
+		exp = parseAssignExp();
+		if (token.value == TOK.TOKcomma)
+		{	
+			nextToken();
+			msg = parseAssignExp();
+		}
+
+		check(TOK.TOKrparen);
+		check(TOK.TOKsemicolon);
+	
+		return new StaticAssert(loc, exp, msg);
+	}
+	
+    TypeQualified parseTypeof()
+	{
+		TypeQualified t;
+		Loc loc = this.loc;
+
+		nextToken();
+		check(TOK.TOKlparen);
+		if (token.value == TOK.TOKreturn)	// typeof(return)
+		{
+			nextToken();
+			t = new TypeReturn(loc);
+		}
+		else
+		{	
+			Expression exp = parseExpression();	// typeof(expression)
+			t = new TypeTypeof(loc, exp);
+		}
+		check(TOK.TOKrparen);
+		return t;
+	}
+	
+	/***********************************
+	 * Parse extern (linkage)
+	 * The parser is on the 'extern' token.
+	 */
+    LINK parseLinkage()
+	{
+		LINK link = LINK.LINKdefault;
+		nextToken();
+		assert(token.value == TOK.TOKlparen);
+		nextToken();
+		if (token.value == TOK.TOKidentifier)
+		{   
+			Identifier id = token.ident;
+
+			nextToken();
+			if (id == Id.Windows)
+				link = LINK.LINKwindows;
+			else if (id == Id.Pascal)
+				link = LINK.LINKpascal;
+			else if (id == Id.D)
+				link = LINK.LINKd;
+			else if (id == Id.C)
+			{
+				link = LINK.LINKc;
+				if (token.value == TOK.TOKplusplus)
+				{   
+					link = LINK.LINKcpp;
+					nextToken();
+				}
+			}
+			else if (id == Id.System)
+			{
+version (_WIN32) {
+				link = LINK.LINKwindows;
+} else {
+				link = LINK.LINKc;
+}
+			}
+			else
+			{
+				error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
+				link = LINK.LINKd;
+			}
+		}
+		else
+		{
+			link = LINK.LINKd;		// default
+		}
+		check(TOK.TOKrparen);
+
+		return link;
+	}
+
+
+	/**************************************
+	 * Parse a debug conditional
+	 */	
+    Condition parseDebugCondition()
+	{
+		Condition c;
+
+		if (token.value == TOK.TOKlparen)
+		{
+			nextToken();
+			uint level = 1;
+			Identifier id = null;
+
+			if (token.value == TOK.TOKidentifier)
+				id = token.ident;
+			else if (token.value == TOK.TOKint32v)
+				level = cast(uint)token.uns64value;
+			else
+				error("identifier or integer expected, not %s", token.toChars());
+
+			nextToken();
+			check(TOK.TOKrparen);
+
+			c = new DebugCondition(mod, level, id);
+		}
+		else
+			c = new DebugCondition(mod, 1, null);
+
+		return c;
+	}
+	
+	/**************************************
+	 * Parse a version conditional
+	 */
+    Condition parseVersionCondition()
+	{
+		Condition c;
+		uint level = 1;
+		Identifier id = null;
+
+		if (token.value == TOK.TOKlparen)
+		{
+			nextToken();
+			if (token.value == TOK.TOKidentifier)
+				id = token.ident;
+			else if (token.value == TOK.TOKint32v)
+				level = cast(uint)token.uns64value;
+			else {
+version (DMDV2) {
+				/* Allow:
+				 *    version (unittest)
+				 * even though unittest is a keyword
+				 */
+				if (token.value == TOK.TOKunittest)
+					id = Lexer.idPool(Token.toChars(TOK.TOKunittest));
+				else
+					error("identifier or integer expected, not %s", token.toChars());
+			} else {
+				error("identifier or integer expected, not %s", token.toChars());
+}
+			}
+			nextToken();
+			check(TOK.TOKrparen);
+		}
+		else
+		   error("(condition) expected following version");
+
+		c = new VersionCondition(mod, level, id);
+
+		return c;
+	}
+
+	/***********************************************
+	 *	static if (expression)
+	 *	    body
+	 *	else
+	 *	    body
+	 */
+    Condition parseStaticIfCondition()
+	{
+		Expression exp;
+		Condition condition;
+		Array aif;
+		Array aelse;
+		Loc loc = this.loc;
+
+		nextToken();
+		if (token.value == TOKlparen)
+		{
+			nextToken();
+			exp = parseAssignExp();
+			check(TOKrparen);
+		}
+		else
+		{   
+			error("(expression) expected following static if");
+			exp = null;
+		}
+		condition = new StaticIfCondition(loc, exp);
+		return condition;
+	}
+	
+	/*****************************************
+	 * Parse a constructor definition:
+	 *	this(parameters) { body }
+	 * or postblit:
+	 *	this(this) { body }
+	 * or constructor template:
+	 *	this(templateparameters)(parameters) { body }
+	 * Current token is 'this'.
+	 */
+	
+    Dsymbol parseCtor()
+	{
+		Loc loc = this.loc;
+
+		nextToken();
+		if (token.value == TOK.TOKlparen && peek(&token).value == TOK.TOKthis)
+		{	// this(this) { ... }
+			nextToken();
+			nextToken();
+			check(TOK.TOKrparen);
+			PostBlitDeclaration f = new PostBlitDeclaration(loc, Loc(0));
+			parseContracts(f);
+			return f;
+		}
+
+		/* Look ahead to see if:
+		 *   this(...)(...)
+		 * which is a constructor template
+		 */
+		TemplateParameters tpl = null;
+		if (token.value == TOK.TOKlparen && peekPastParen(&token).value == TOK.TOKlparen)
+		{	tpl = parseTemplateParameterList();
+
+			int varargs;
+			Arguments arguments = parseParameters(&varargs);
+
+			Expression constraint = null;
+			if (tpl)
+				constraint = parseConstraint();
+
+			CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs);
+			parseContracts(f);
+
+			// Wrap a template around it
+			Array decldefs = new Array();
+			decldefs.push(cast(void*)f);
+			TemplateDeclaration tempdecl =
+				new TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
+			return tempdecl;
+		}
+
+		/* Just a regular constructor
+		 */
+		int varargs;
+		Arguments arguments = parseParameters(&varargs);
+		CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs);
+		parseContracts(f);
+		return f;
+	}
+	
+    PostBlitDeclaration parsePostBlit()
+	{
+		assert(false);
+	}
+	
+	/*****************************************
+	 * Parse a destructor definition:
+	 *	~this() { body }
+	 * Current token is '~'.
+	 */
+    DtorDeclaration parseDtor()
+	{
+		DtorDeclaration f;
+		Loc loc = this.loc;
+
+		nextToken();
+		check(TOKthis);
+		check(TOKlparen);
+		check(TOKrparen);
+
+		f = new DtorDeclaration(loc, Loc(0));
+		parseContracts(f);
+		return f;
+	}
+	
+	/*****************************************
+	 * Parse a static constructor definition:
+	 *	static this() { body }
+	 * Current token is 'this'.
+	 */
+    StaticCtorDeclaration parseStaticCtor()
+	{
+		StaticCtorDeclaration f;
+		Loc loc = this.loc;
+
+		nextToken();
+		check(TOKlparen);
+		check(TOKrparen);
+
+		f = new StaticCtorDeclaration(loc, Loc(0));
+		parseContracts(f);
+		return f;
+	}
+	
+	/*****************************************
+	 * Parse a static destructor definition:
+	 *	static ~this() { body }
+	 * Current token is '~'.
+	 */
+    StaticDtorDeclaration parseStaticDtor()
+	{
+		StaticDtorDeclaration f;
+		Loc loc = this.loc;
+
+		nextToken();
+		check(TOKthis);
+		check(TOKlparen);
+		check(TOKrparen);
+
+		f = new StaticDtorDeclaration(loc, Loc(0));
+		parseContracts(f);
+		return f;
+	}
+	
+	/*****************************************
+	 * Parse an invariant definition:
+	 *	invariant() { body }
+	 * Current token is 'invariant'.
+	 */
+    InvariantDeclaration parseInvariant()
+	{
+		InvariantDeclaration f;
+		Loc loc = this.loc;
+
+		nextToken();
+		if (token.value == TOKlparen)	// optional ()
+		{
+			nextToken();
+			check(TOKrparen);
+		}
+
+		f = new InvariantDeclaration(loc, Loc(0));
+		f.fbody = parseStatement(ParseStatementFlags.PScurly);
+		return f;
+	}
+	
+	/*****************************************
+	 * Parse a unittest definition:
+	 *	unittest { body }
+	 * Current token is 'unittest'.
+	 */
+    UnitTestDeclaration parseUnitTest()
+	{
+		Loc loc = this.loc;
+
+		nextToken();
+
+		UnitTestDeclaration f = new UnitTestDeclaration(loc, this.loc);
+		f.fbody = parseStatement(ParseStatementFlags.PScurly);
+
+		return f;
+	}
+	
+    NewDeclaration parseNew()
+	{
+		assert(false);
+	}
+	
+    DeleteDeclaration parseDelete()
+	{
+		assert(false);
+	}
+	
+    Arguments parseParameters(int* pvarargs)
+	{
+		Arguments arguments = new Arguments();
+		int varargs = 0;
+		int hasdefault = 0;
+
+		check(TOK.TOKlparen);
+		while (1)
+		{   Type *tb;
+		Identifier ai = null;
+		Type at;
+		Argument a;
+		STC storageClass = STC.STCundefined;
+		STC stc;
+		Expression ae;
+
+		for ( ;1; nextToken())
+		{
+			switch (token.value)
+			{
+			case TOK.TOKrparen:
+				break;
+
+			case TOK.TOKdotdotdot:
+				varargs = 1;
+				nextToken();
+				break;
+
+			case TOK.TOKconst:
+				if (peek(&token).value == TOK.TOKlparen)
+				goto Ldefault;
+				stc = STC.STCconst;
+				goto L2;
+
+			case TOK.TOKinvariant:
+			case TOK.TOKimmutable:
+				if (peek(&token).value == TOK.TOKlparen)
+				goto Ldefault;
+				stc = STC.STCimmutable;
+				goto L2;
+
+			case TOK.TOKshared:
+				if (peek(&token).value == TOK.TOKlparen)
+				goto Ldefault;
+				stc = STC.STCshared;
+				goto L2;
+
+			case TOK.TOKin:	   stc = STC.STCin;		goto L2;
+			case TOK.TOKout:	   stc = STC.STCout;	goto L2;
+			case TOK.TOKinout:
+			case TOK.TOKref:	   stc = STC.STCref;	goto L2;
+			case TOK.TOKlazy:	   stc = STC.STClazy;	goto L2;
+			case TOK.TOKscope:	   stc = STC.STCscope;	goto L2;
+			case TOK.TOKfinal:	   stc = STC.STCfinal;	goto L2;
+			L2:
+				if (storageClass & stc ||
+				(storageClass & STC.STCin && stc & (STC.STCconst | STC.STCscope)) ||
+				(stc & STC.STCin && storageClass & (STC.STCconst | STC.STCscope))
+				   )
+				error("redundant storage class %s", Token.toChars(token.value));
+				storageClass |= stc;
+				composeStorageClass(storageClass);
+				continue;
+
+static if (false) {
+			case TOK.TOKstatic:	   stc = STC.STCstatic;		goto L2;
+			case TOK.TOKauto:   storageClass = STC.STCauto;		goto L4;
+			case TOK.TOKalias:  storageClass = STC.STCalias;	goto L4;
+			L4:
+				nextToken();
+				if (token.value == TOK.TOKidentifier)
+				{	ai = token.ident;
+				nextToken();
+				}
+				else
+				ai = null;
+				at = null;		// no type
+				ae = null;		// no default argument
+				if (token.value == TOK.TOKassign)	// = defaultArg
+				{   nextToken();
+				ae = parseDefaultInitExp();
+				hasdefault = 1;
+				}
+				else
+				{   if (hasdefault)
+					error("default argument expected for alias %s",
+						ai ? ai.toChars() : "");
+				}
+				goto L3;
+}
+
+			default:
+			Ldefault:
+				stc = (storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy));
+				if (stc & (stc - 1))	// if stc is not a power of 2
+				error("incompatible parameter storage classes");
+				if ((storageClass & (STC.STCconst | STC.STCout)) == (STC.STCconst | STC.STCout))
+				error("out cannot be const");
+				if ((storageClass & (STC.STCimmutable | STC.STCout)) == (STC.STCimmutable | STC.STCout))
+				error("out cannot be immutable");
+				if ((storageClass & STC.STCscope) &&
+				(storageClass & (STC.STCref | STC.STCout)))
+				error("scope cannot be ref or out");
+				at = parseType(&ai);
+				ae = null;
+				if (token.value == TOK.TOKassign)	// = defaultArg
+				{   nextToken();
+				ae = parseDefaultInitExp();
+				hasdefault = 1;
+				}
+				else
+				{   if (hasdefault)
+					error("default argument expected for %s",
+						ai ? ai.toChars() : at.toChars());
+				}
+				if (token.value == TOK.TOKdotdotdot)
+				{   /* This is:
+				 *	at ai ...
+				 */
+
+				if (storageClass & (STC.STCout | STC.STCref))
+					error("variadic argument cannot be out or ref");
+				varargs = 2;
+				a = new Argument(storageClass, at, ai, ae);
+				arguments.push(cast(void*)a);
+				nextToken();
+				break;
+				}
+			L3:
+				a = new Argument(storageClass, at, ai, ae);
+				arguments.push(cast(void*)a);
+				if (token.value == TOK.TOKcomma)
+				{   nextToken();
+				goto L1;
+				}
+				break;
+			}
+			break;
+		}
+		break;
+
+		L1:	;
+		}
+		check(TOK.TOKrparen);
+		*pvarargs = varargs;
+		return arguments;
+	}
+	
+    EnumDeclaration parseEnum()
+	{
+		EnumDeclaration e;
+		Identifier id;
+		Type memtype;
+		Loc loc = this.loc;
+
+		//printf("Parser.parseEnum()\n");
+		nextToken();
+		if (token.value == TOK.TOKidentifier)
+		{
+			id = token.ident;
+			nextToken();
+		}
+		else
+			id = null;
+
+		if (token.value == TOK.TOKcolon)
+		{
+			nextToken();
+			memtype = parseBasicType();
+			memtype = parseDeclarator(memtype, null, null);
+		}
+		else
+			memtype = null;
+
+		e = new EnumDeclaration(loc, id, memtype);
+		if (token.value == TOK.TOKsemicolon && id)
+			nextToken();
+		else if (token.value == TOK.TOKlcurly)
+		{
+			//printf("enum definition\n");
+			e.members = new Array();
+			nextToken();
+			ubyte* comment = token.blockComment;
+			while (token.value != TOK.TOKrcurly)
+			{
+				/* Can take the following forms:
+				 *	1. ident
+				 *	2. ident = value
+				 *	3. type ident = value
+				 */
+
+				loc = this.loc;
+
+				Type type = null;
+				Identifier ident;
+				Token* tp = peek(&token);
+				if (token.value == TOK.TOKidentifier &&
+					(tp.value == TOK.TOKassign || tp.value == TOK.TOKcomma || tp.value == TOK.TOKrcurly))
+				{
+					ident = token.ident;
+					type = null;
+					nextToken();
+				}
+				else
+				{
+					type = parseType(&ident, null);
+					if (id || memtype)
+						error("type only allowed if anonymous enum and no enum type");
+				}
+
+				Expression value;
+				if (token.value == TOK.TOKassign)
+				{
+					nextToken();
+					value = parseAssignExp();
+				}
+				else
+				{	
+					value = null;
+					if (type)
+						error("if type, there must be an initializer");
+				}
+
+				EnumMember em = new EnumMember(loc, ident, value, type);
+				e.members.push(cast(void*)em);
+
+				if (token.value == TOK.TOKrcurly) {
+					;
+				} else {
+					addComment(em, comment);
+					comment = null;
+					check(TOK.TOKcomma);
+				}
+				addComment(em, comment);
+				comment = token.blockComment;
+			}
+			nextToken();
+		}
+		else
+			error("enum declaration is invalid");
+
+		//printf("-parseEnum() %s\n", e.toChars());
+		return e;
+	}
+	
+    Dsymbol parseAggregate()
+	{
+		AggregateDeclaration a = null;
+		int anon = 0;
+		TOK tok;
+		Identifier id;
+		TemplateParameters tpl = null;
+		Expression constraint = null;
+
+		//printf("Parser.parseAggregate()\n");
+		tok = token.value;
+		nextToken();
+		if (token.value != TOK.TOKidentifier)
+		{
+			id = null;
+		}
+		else
+		{
+			id = token.ident;
+			nextToken();
+
+			if (token.value == TOK.TOKlparen)
+			{   
+				// Class template declaration.
+
+				// Gather template parameter list
+				tpl = parseTemplateParameterList();
+				constraint = parseConstraint();
+			}
+		}
+
+		Loc loc = this.loc;
+		switch (tok)
+		{	case TOK.TOKclass:
+		case TOK.TOKinterface:
+		{
+			if (!id)
+			error("anonymous classes not allowed");
+
+			// Collect base class(es)
+			BaseClasses baseclasses = null;
+			if (token.value == TOK.TOKcolon)
+			{
+				nextToken();
+				baseclasses = parseBaseClasses();
+
+				if (token.value != TOK.TOKlcurly)
+					error("members expected");
+			}
+
+			if (tok == TOK.TOKclass)
+				a = new ClassDeclaration(loc, id, baseclasses);
+			else
+				a = new InterfaceDeclaration(loc, id, baseclasses);
+			break;
+		}
+
+		case TOK.TOKstruct:
+			if (id)
+			a = new StructDeclaration(loc, id);
+			else
+			anon = 1;
+			break;
+
+		case TOK.TOKunion:
+			if (id)
+			a = new UnionDeclaration(loc, id);
+			else
+			anon = 2;
+			break;
+
+		default:
+			assert(0);
+			break;
+		}
+		if (a && token.value == TOK.TOKsemicolon)
+		{ 	nextToken();
+		}
+		else if (token.value == TOK.TOKlcurly)
+		{
+		//printf("aggregate definition\n");
+		nextToken();
+		Array decl = parseDeclDefs(0);
+		if (token.value != TOK.TOKrcurly)
+			error("} expected following member declarations in aggregate");
+		nextToken();
+		if (anon)
+		{
+			/* Anonymous structs/unions are more like attributes.
+			 */
+			return new AnonDeclaration(loc, anon - 1, decl);
+		}
+		else
+			a.members = decl;
+		}
+		else
+		{
+		error("{ } expected following aggregate declaration");
+		a = new StructDeclaration(loc, null);
+		}
+
+		if (tpl)
+		{	// Wrap a template around the aggregate declaration
+
+		Array decldefs = new Array();
+		decldefs.push(cast(void*)a);
+		TemplateDeclaration tempdecl =
+			new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
+		return tempdecl;
+		}
+
+		return a;
+	}
+	
+    BaseClasses parseBaseClasses()
+	{
+		BaseClasses baseclasses = new BaseClasses();
+
+		for (; 1; nextToken())
+		{
+			PROT protection = PROT.PROTpublic;
+			switch (token.value)
+			{
+				case TOK.TOKprivate:
+					protection = PROT.PROTprivate;
+					nextToken();
+					break;
+				case TOK.TOKpackage:
+					protection = PROT.PROTpackage;
+					nextToken();
+					break;
+				case TOK.TOKprotected:
+					protection = PROT.PROTprotected;
+					nextToken();
+					break;
+				case TOK.TOKpublic:
+					protection = PROT.PROTpublic;
+					nextToken();
+					break;
+				default:
+					break;	///
+			}
+			if (token.value == TOK.TOKidentifier)
+			{
+				BaseClass b = new BaseClass(parseBasicType(), protection);
+				baseclasses.push(cast(void*)b);
+				if (token.value != TOK.TOKcomma)
+					break;
+			}
+			else
+			{
+				error("base classes expected instead of %s", token.toChars());
+				return null;
+			}
+		}
+		return baseclasses;
+	}
+	
+    Import parseImport(Array decldefs, int isstatic)
+	{
+		Import s;
+		Identifier id;
+		Identifier aliasid = null;
+		Array a;
+		Loc loc;
+
+		//printf("Parser.parseImport()\n");
+		do
+		{
+		 L1:
+			nextToken();
+			if (token.value != TOK.TOKidentifier)
+			{   
+				error("Identifier expected following import");
+				break;
+			}
+
+			loc = this.loc;
+			a = null;
+			id = token.ident;
+			nextToken();
+			if (!aliasid && token.value == TOK.TOKassign)
+			{
+				aliasid = id;
+				goto L1;
+			}
+			while (token.value == TOK.TOKdot)
+			{
+				if (!a)
+					a = new Array();
+				a.push(cast(void*)id);
+				nextToken();
+				if (token.value != TOK.TOKidentifier)
+				{   
+					error("identifier expected following package");
+					break;
+				}
+				id = token.ident;
+				nextToken();
+			}
+
+			s = new Import(loc, a, id, aliasid, isstatic);
+			decldefs.push(cast(void*)s);
+
+			/* Look for
+			 *	: alias=name, alias=name;
+			 * syntax.
+			 */
+			if (token.value == TOK.TOKcolon)
+			{
+				do
+				{	
+					Identifier name;
+
+					nextToken();
+					if (token.value != TOK.TOKidentifier)
+					{   
+						error("Identifier expected following :");
+						break;
+					}
+					Identifier alias_ = token.ident;
+					nextToken();
+					if (token.value == TOK.TOKassign)
+					{
+						nextToken();
+						if (token.value != TOK.TOKidentifier)
+						{   
+							error("Identifier expected following %s=", alias_.toChars());
+							break;
+						}
+						name = token.ident;
+						nextToken();
+					}
+					else
+					{   
+						name = alias_;
+						alias_ = null;
+					}
+					s.addAlias(name, alias_);
+				} while (token.value == TOK.TOKcomma);
+
+				break;	// no comma-separated imports of this form
+			}
+
+			aliasid = null;
+
+		} while (token.value == TOK.TOKcomma);
+
+		if (token.value == TOK.TOKsemicolon)
+			nextToken();
+		else
+		{
+			error("';' expected");
+			nextToken();
+		}
+
+		return null;
+	}
+	
+    Type parseType(Identifier* pident = null, TemplateParameters* tpl = null)
+	{
+		Type t;
+
+		/* Take care of the storage class prefixes that
+		 * serve as type attributes:
+		 *  const shared, shared const, const, invariant, shared
+		 */
+		if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() != TOK.TOKlparen ||
+			token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() != TOK.TOKlparen)
+		{
+			nextToken();
+			nextToken();
+			/* shared const type
+			 */
+			t = parseType(pident, tpl);
+			t = t.makeSharedConst();
+			return t;
+		}
+		else if (token.value == TOK.TOKconst && peekNext() != TOK.TOKlparen)
+		{
+			nextToken();
+			/* const type
+			 */
+			t = parseType(pident, tpl);
+			t = t.makeConst();
+			return t;
+		}
+		else if ((token.value == TOK.TOKinvariant || token.value == TOK.TOKimmutable) &&
+				 peekNext() != TOK.TOKlparen)
+		{
+			nextToken();
+			/* invariant type
+			 */
+			t = parseType(pident, tpl);
+			t = t.makeInvariant();
+			return t;
+		}
+		else if (token.value == TOK.TOKshared && peekNext() != TOK.TOKlparen)
+		{
+			nextToken();
+			/* shared type
+			 */
+			t = parseType(pident, tpl);
+			t = t.makeShared();
+			return t;
+		}
+		else
+			t = parseBasicType();	
+		t = parseDeclarator(t, pident, tpl);
+		return t;
+	}
+	
+    Type parseBasicType()
+	{
+		Type t;
+		Identifier id;
+		TypeQualified tid;
+
+		//printf("parseBasicType()\n");
+		switch (token.value)
+		{
+			case TOK.TOKvoid:	 t = Type.tvoid;  goto LabelX;
+			case TOK.TOKint8:	 t = Type.tint8;  goto LabelX;
+			case TOK.TOKuns8:	 t = Type.tuns8;  goto LabelX;
+			case TOK.TOKint16:	 t = Type.tint16; goto LabelX;
+			case TOK.TOKuns16:	 t = Type.tuns16; goto LabelX;
+			case TOK.TOKint32:	 t = Type.tint32; goto LabelX;
+			case TOK.TOKuns32:	 t = Type.tuns32; goto LabelX;
+			case TOK.TOKint64:	 t = Type.tint64; goto LabelX;
+			case TOK.TOKuns64:	 t = Type.tuns64; goto LabelX;
+			case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX;
+			case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX;
+			case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX;
+			case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX;
+			case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX;
+			case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX;
+			case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX;
+			case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX;
+			case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX;
+			case TOK.TOKbit:	 t = Type.tbit;     goto LabelX;
+			case TOK.TOKbool:	 t = Type.tbool;    goto LabelX;
+			case TOK.TOKchar:	 t = Type.tchar;    goto LabelX;
+			case TOK.TOKwchar:	 t = Type.twchar; goto LabelX;
+			case TOK.TOKdchar:	 t = Type.tdchar; goto LabelX;
+			LabelX:
+				nextToken();
+				break;
+
+		case TOK.TOKidentifier:
+			id = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKnot)
+			{	// ident!(template_arguments)
+			TemplateInstance tempinst = new TemplateInstance(loc, id);
+			nextToken();
+			if (token.value == TOK.TOKlparen)
+				// ident!(template_arguments)
+				tempinst.tiargs = parseTemplateArgumentList();
+			else
+				// ident!template_argument
+				tempinst.tiargs = parseTemplateArgument();
+			tid = new TypeInstance(loc, tempinst);
+			goto Lident2;
+			}
+		Lident:
+			tid = new TypeIdentifier(loc, id);
+		Lident2:
+			while (token.value == TOK.TOKdot)
+			{	nextToken();
+			if (token.value != TOK.TOKidentifier)
+			{   error("identifier expected following '.' instead of '%s'", token.toChars());
+				break;
+			}
+			id = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKnot)
+			{
+				TemplateInstance tempinst = new TemplateInstance(loc, id);
+				nextToken();
+				if (token.value == TOK.TOKlparen)
+				// ident!(template_arguments)
+				tempinst.tiargs = parseTemplateArgumentList();
+				else
+				// ident!template_argument
+				tempinst.tiargs = parseTemplateArgument();
+				tid.addIdent(cast(Identifier)tempinst);
+			}
+			else
+				tid.addIdent(id);
+			}
+			t = tid;
+			break;
+
+		case TOK.TOKdot:
+			// Leading . as in .foo
+			id = Id.empty;
+			goto Lident;
+
+		case TOK.TOKtypeof:
+			// typeof(expression)
+			tid = parseTypeof();
+			goto Lident2;
+
+		case TOK.TOKconst:
+			// const(type)
+			nextToken();
+			check(TOK.TOKlparen);
+			t = parseType();
+			check(TOK.TOKrparen);
+			if (t.isShared())
+			t = t.makeSharedConst();
+			else
+			t = t.makeConst();
+			break;
+
+		case TOK.TOKinvariant:
+		case TOK.TOKimmutable:
+			// invariant(type)
+			nextToken();
+			check(TOK.TOKlparen);
+			t = parseType();
+			check(TOK.TOKrparen);
+			t = t.makeInvariant();
+			break;
+
+		case TOK.TOKshared:
+			// shared(type)
+			nextToken();
+			check(TOK.TOKlparen);
+			t = parseType();
+			check(TOK.TOKrparen);
+			if (t.isConst())
+			t = t.makeSharedConst();
+			else
+			t = t.makeShared();
+			break;
+
+		default:
+			error("basic type expected, not %s", token.toChars());
+			t = Type.tint32;
+			break;
+		}
+		return t;
+	}
+	
+    Type parseBasicType2(Type t)
+	{
+		//printf("parseBasicType2()\n");
+		while (1)
+		{
+		switch (token.value)
+		{
+			case TOK.TOKmul:
+			t = new TypePointer(t);
+			nextToken();
+			continue;
+
+			case TOK.TOKlbracket:
+			// Handle []. Make sure things like
+			//     int[3][1] a;
+			// is (array[1] of array[3] of int)
+			nextToken();
+			if (token.value == TOK.TOKrbracket)
+			{
+				t = new TypeDArray(t);			// []
+				nextToken();
+			}
+			else if (isDeclaration(&token, 0, TOK.TOKrbracket, null))
+			{   // It's an associative array declaration
+
+				//printf("it's an associative array\n");
+				Type index = parseType();		// [ type ]
+				t = new TypeAArray(t, index);
+				check(TOK.TOKrbracket);
+			}
+			else
+			{
+				//printf("it's type[expression]\n");
+				inBrackets++;
+				Expression e = parseExpression();		// [ expression ]
+				if (token.value == TOK.TOKslice)
+				{
+				nextToken();
+				Expression e2 = parseExpression();	// [ exp .. exp ]
+				t = new TypeSlice(t, e, e2);
+				}
+				else
+				t = new TypeSArray(t,e);
+				inBrackets--;
+				check(TOK.TOKrbracket);
+			}
+			continue;
+
+			case TOK.TOKdelegate:
+			case TOK.TOKfunction:
+			{	// Handle delegate declaration:
+			//	t delegate(parameter list) nothrow pure
+			//	t function(parameter list) nothrow pure
+			Arguments arguments;
+			int varargs;
+			bool ispure = false;
+			bool isnothrow = false;
+			TOK save = token.value;
+
+			nextToken();
+			arguments = parseParameters(&varargs);
+			while (1)
+			{   // Postfixes
+				if (token.value == TOK.TOKpure)
+				ispure = true;
+				else if (token.value == TOK.TOKnothrow)
+				isnothrow = true;
+				else
+				break;
+				nextToken();
+			}
+			TypeFunction tf = new TypeFunction(arguments, t, varargs, linkage);
+			tf.ispure = ispure;
+			tf.isnothrow = isnothrow;
+			if (save == TOK.TOKdelegate)
+				t = new TypeDelegate(tf);
+			else
+				t = new TypePointer(tf);	// pointer to function
+			continue;
+			}
+
+			default:
+			return t;
+		}
+		assert(0);
+		}
+		assert(0);
+		return null;
+	}
+	
+    Type parseDeclarator(Type t, Identifier* pident, TemplateParameters* tpl = null)
+	{
+		Type ts;
+
+		//printf("parseDeclarator(tpl = %p)\n", tpl);
+		t = parseBasicType2(t);
+
+		switch (token.value)
+		{
+
+		case TOK.TOKidentifier:
+			if (pident)
+			*pident = token.ident;
+			else
+			error("unexpected identifer '%s' in declarator", token.ident.toChars());
+			ts = t;
+			nextToken();
+			break;
+
+		case TOK.TOKlparen:
+			/* Parse things with parentheses around the identifier, like:
+			 *	int (*ident[3])[]
+			 * although the D style would be:
+			 *	int[]*[3] ident
+			 */
+			nextToken();
+			ts = parseDeclarator(t, pident);
+			check(TOK.TOKrparen);
+			break;
+
+		default:
+			ts = t;
+			break;
+		}
+
+		// parse DeclaratorSuffixes
+		while (1)
+		{
+		switch (token.value)
+		{
+version (CARRAYDECL) {
+			/* Support C style array syntax:
+			 *   int ident[]
+			 * as opposed to D-style:
+			 *   int[] ident
+			 */
+			case TOK.TOKlbracket:
+			{	// This is the old C-style post [] syntax.
+			TypeNext ta;
+			nextToken();
+			if (token.value == TOK.TOKrbracket)
+			{   // It's a dynamic array
+				ta = new TypeDArray(t);		// []
+				nextToken();
+			}
+			else if (isDeclaration(&token, 0, TOK.TOKrbracket, null))
+			{   // It's an associative array
+
+				//printf("it's an associative array\n");
+				Type index = parseType();		// [ type ]
+				check(TOK.TOKrbracket);
+				ta = new TypeAArray(t, index);
+			}
+			else
+			{
+				//printf("It's a static array\n");
+				Expression e = parseExpression();	// [ expression ]
+				ta = new TypeSArray(t, e);
+				check(TOK.TOKrbracket);
+			}
+
+			/* Insert ta into
+			 *   ts . ... . t
+			 * so that
+			 *   ts . ... . ta . t
+			 */
+			Type* pt;
+			for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) {
+				;
+			}
+			*pt = ta;
+			continue;
+			}
+}
+			case TOK.TOKlparen:
+			{
+			if (tpl)
+			{
+				/* Look ahead to see if this is (...)(...),
+				 * i.e. a function template declaration
+				 */
+				if (peekPastParen(&token).value == TOK.TOKlparen)
+				{
+				//printf("function template declaration\n");
+
+				// Gather template parameter list
+				*tpl = parseTemplateParameterList();
+				}
+			}
+
+			int varargs;
+			Arguments arguments = parseParameters(&varargs);
+			Type tf = new TypeFunction(arguments, t, varargs, linkage);
+
+			/* Parse const/invariant/nothrow/pure postfix
+			 */
+			while (1)
+			{
+				switch (token.value)
+				{
+					case TOK.TOKconst:
+						if (tf.isShared())
+						tf = tf.makeSharedConst();
+						else
+						tf = tf.makeConst();
+						nextToken();
+						continue;
+
+					case TOK.TOKinvariant:
+					case TOK.TOKimmutable:
+						tf = tf.makeInvariant();
+						nextToken();
+						continue;
+
+					case TOK.TOKshared:
+						if (tf.isConst())
+						tf = tf.makeSharedConst();
+						else
+						tf = tf.makeShared();
+						nextToken();
+						continue;
+
+					case TOK.TOKnothrow:
+						(cast(TypeFunction)tf).isnothrow = 1;
+						nextToken();
+						continue;
+
+					case TOK.TOKpure:
+						(cast(TypeFunction)tf).ispure = 1;
+						nextToken();
+						continue;
+
+					case TOK.TOKat:
+						nextToken();
+						if (token.value != TOK.TOKidentifier)
+						{   error("attribute identifier expected");
+						nextToken();
+						continue;
+						}
+						Identifier id = token.ident;
+						if (id is Id.property)
+						(cast(TypeFunction)tf).ispure = 1;
+						else
+						error("valid attribute identifiers are property, not %s", id.toChars());
+						nextToken();
+						continue;
+					default:
+						break;	///
+				}
+				break;
+			}
+
+			/* Insert tf into
+			 *   ts . ... . t
+			 * so that
+			 *   ts . ... . tf . t
+			 */
+			Type* pt;
+			for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) {
+				;
+			}
+			*pt = tf;
+			break;
+			}
+			
+			default:
+				break;	///
+		}
+		break;
+		}
+
+		return ts;
+	}
+	
+    Array parseDeclarations(STC storage_class)
+	{
+		STC stc;
+		Type ts;
+		Type t;
+		Type tfirst;
+		Identifier ident;
+		Array a;
+		TOK tok = TOK.TOKreserved;
+		ubyte* comment = token.blockComment;
+		LINK link = linkage;
+
+		//printf("parseDeclarations() %s\n", token.toChars());
+		if (storage_class)
+		{	ts = null;		// infer type
+		goto L2;
+		}
+
+		switch (token.value)
+		{
+			case TOK.TOKalias:
+				/* Look for:
+				 *   alias identifier this;
+				 */
+				tok = token.value;
+				nextToken();
+				if (token.value == TOK.TOKidentifier && peek(&token).value == TOK.TOKthis)
+				{
+				AliasThis s = new AliasThis(this.loc, token.ident);
+				nextToken();
+				check(TOK.TOKthis);
+				check(TOK.TOKsemicolon);
+				a = new Array();
+				a.push(cast(void*)s);
+				addComment(s, comment);
+				return a;
+				}
+				break;
+			case TOK.TOKtypedef:
+				tok = token.value;
+				nextToken();
+				break;
+			default:
+				break;
+		}
+
+		storage_class = STC.STCundefined;
+		while (1)
+		{
+		switch (token.value)
+		{
+			case TOK.TOKconst:
+			if (peek(&token).value == TOK.TOKlparen)
+				break;		// const as type constructor
+			stc = STC.STCconst;		// const as storage class
+			goto L1;
+
+			case TOK.TOKinvariant:
+			case TOK.TOKimmutable:
+			if (peek(&token).value == TOK.TOKlparen)
+				break;
+			stc = STC.STCimmutable;
+			goto L1;
+
+			case TOK.TOKshared:
+			if (peek(&token).value == TOK.TOKlparen)
+				break;
+			stc = STC.STCshared;
+			goto L1;
+
+			case TOK.TOKstatic:	stc = STC.STCstatic;	 goto L1;
+			case TOK.TOKfinal:	stc = STC.STCfinal;		 goto L1;
+			case TOK.TOKauto:	stc = STC.STCauto;		 goto L1;
+			case TOK.TOKscope:	stc = STC.STCscope;		 goto L1;
+			case TOK.TOKoverride:	stc = STC.STCoverride;	 goto L1;
+			case TOK.TOKabstract:	stc = STC.STCabstract;	 goto L1;
+			case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto L1;
+			case TOK.TOKdeprecated: stc = STC.STCdeprecated;	 goto L1;
+version (DMDV2) {
+			case TOK.TOKnothrow:    stc = STC.STCnothrow;	 goto L1;
+			case TOK.TOKpure:       stc = STC.STCpure;		 goto L1;
+			case TOK.TOKref:        stc = STC.STCref;            goto L1;
+			case TOK.TOKtls:        stc = STC.STCtls;		 goto L1;
+			case TOK.TOKgshared:    stc = STC.STCgshared;	 goto L1;
+			case TOK.TOKenum:	stc = STC.STCmanifest;	 goto L1;
+}
+			L1:
+			if (storage_class & stc)
+				error("redundant storage class '%s'", token.toChars());
+			storage_class = (storage_class | stc);
+			composeStorageClass(storage_class);
+			nextToken();
+			continue;
+
+			case TOK.TOKextern:
+			if (peek(&token).value != TOK.TOKlparen)
+			{   stc = STC.STCextern;
+				goto L1;
+			}
+
+			link = parseLinkage();
+			continue;
+
+			default:
+			break;
+		}
+		break;
+		}
+
+		/* Look for auto initializers:
+		 *	storage_class identifier = initializer;
+		 */
+		if (storage_class &&
+		token.value == TOK.TOKidentifier &&
+		peek(&token).value == TOK.TOKassign)
+		{
+		return parseAutoDeclarations(storage_class, comment);
+		}
+
+		if (token.value == TOK.TOKclass)
+		{
+		AggregateDeclaration s = cast(AggregateDeclaration)parseAggregate();
+		s.storage_class |= storage_class;
+		a = new Array();
+		a.push(cast(void*)s);
+		addComment(s, comment);
+		return a;
+		}
+
+		/* Look for return type inference for template functions.
+		 */
+		{
+		Token *tk;
+		if (storage_class &&
+		token.value == TOK.TOKidentifier &&
+		(tk = peek(&token)).value == TOK.TOKlparen &&
+		skipParens(tk, &tk) &&
+		peek(tk).value == TOK.TOKlparen)
+		{
+		ts = null;
+		}
+		else
+		{
+		ts = parseBasicType();
+		ts = parseBasicType2(ts);
+		}
+		}
+
+	L2:
+		tfirst = null;
+		a = new Array();
+
+		while (1)
+		{
+		Loc loc = this.loc;
+		TemplateParameters tpl = null;
+
+		ident = null;
+		t = parseDeclarator(ts, &ident, &tpl);
+		assert(t);
+		if (!tfirst)
+			tfirst = t;
+		else if (t != tfirst)
+			error("multiple declarations must have the same type, not %s and %s",
+			tfirst.toChars(), t.toChars());
+		if (!ident)
+			error("no identifier for declarator %s", t.toChars());
+
+		if (tok == TOK.TOKtypedef || tok == TOK.TOKalias)
+		{   Declaration v;
+			Initializer init = null;
+
+			if (token.value == TOK.TOKassign)
+			{
+			nextToken();
+			init = parseInitializer();
+			}
+			if (tok == TOK.TOKtypedef)
+			v = new TypedefDeclaration(loc, ident, t, init);
+			else
+			{	if (init)
+				error("alias cannot have initializer");
+			v = new AliasDeclaration(loc, ident, t);
+			}
+			v.storage_class = storage_class;
+			if (link == linkage)
+			a.push(cast(void*)v);
+			else
+			{
+			Array ax = new Array();
+			ax.push(cast(void*)v);
+			Dsymbol s = new LinkDeclaration(link, ax);
+			a.push(cast(void*)s);
+			}
+			switch (token.value)
+			{   case TOK.TOKsemicolon:
+				nextToken();
+				addComment(v, comment);
+				break;
+
+			case TOK.TOKcomma:
+				nextToken();
+				addComment(v, comment);
+				continue;
+
+			default:
+				error("semicolon expected to close %s declaration", Token.toChars(tok));
+				break;
+			}
+		}
+		else if (t.ty == TY.Tfunction)
+		{
+			TypeFunction tf = cast(TypeFunction)t;
+			Expression constraint = null;
+static if (false) {
+			if (Argument.isTPL(tf.parameters))
+			{
+			if (!tpl)
+				tpl = new TemplateParameters();
+			}
+}
+			FuncDeclaration f =
+			new FuncDeclaration(loc, Loc(0), ident, storage_class, t);
+			addComment(f, comment);
+			if (tpl)
+			constraint = parseConstraint();
+			parseContracts(f);
+			addComment(f, null);
+			Dsymbol s;
+			if (link == linkage)
+			{
+			s = f;
+			}
+			else
+			{
+			Array ax = new Array();
+			ax.push(cast(void*)f);
+			s = new LinkDeclaration(link, ax);
+			}
+			/* A template parameter list means it's a function template
+			 */
+			if (tpl)
+			{
+			// Wrap a template around the function declaration
+			Array decldefs = new Array();
+			decldefs.push(cast(void*)s);
+			TemplateDeclaration tempdecl =
+				new TemplateDeclaration(loc, s.ident, tpl, constraint, decldefs);
+			s = tempdecl;
+			}
+			addComment(s, comment);
+			a.push(cast(void*)s);
+		}
+		else
+		{
+			Initializer init = null;
+			if (token.value == TOK.TOKassign)
+			{
+			nextToken();
+			init = parseInitializer();
+			}
+
+			VarDeclaration v = new VarDeclaration(loc, t, ident, init);
+			v.storage_class = storage_class;
+			if (link == linkage)
+			a.push(cast(void*)v);
+			else
+			{
+			Array ax = new Array();
+			ax.push(cast(void*)v);
+			Dsymbol s = new LinkDeclaration(link, ax);
+			a.push(cast(void*)s);
+			}
+			switch (token.value)
+			{   case TOK.TOKsemicolon:
+				nextToken();
+				addComment(v, comment);
+				break;
+
+			case TOK.TOKcomma:
+				nextToken();
+				addComment(v, comment);
+				continue;
+
+			default:
+				error("semicolon expected, not '%s'", token.toChars());
+				break;
+			}
+		}
+		break;
+		}
+		return a;
+	}
+	
+    void parseContracts(FuncDeclaration f)
+	{
+		Type tb;
+		LINK linksave = linkage;
+
+		// The following is irrelevant, as it is overridden by sc.linkage in
+		// TypeFunction.semantic
+		linkage = LINK.LINKd;		// nested functions have D linkage
+	L1:
+		switch (token.value)
+		{
+		case TOK.TOKlcurly:
+			if (f.frequire || f.fensure)
+			error("missing body { ... } after in or out");
+			f.fbody = parseStatement(ParseStatementFlags.PSsemi);
+			f.endloc = endloc;
+			break;
+
+		case TOK.TOKbody:
+			nextToken();
+			f.fbody = parseStatement(ParseStatementFlags.PScurly);
+			f.endloc = endloc;
+			break;
+
+		case TOK.TOKsemicolon:
+			if (f.frequire || f.fensure)
+			error("missing body { ... } after in or out");
+			nextToken();
+			break;
+
+static if (false) {	// Do we want this for function declarations, so we can do:
+		// int x, y, foo(), z;
+		case TOK.TOKcomma:
+			nextToken();
+			continue;
+}
+
+static if (false) { // Dumped feature
+		case TOK.TOKthrow:
+			if (!f.fthrows)
+			f.fthrows = new Array();
+			nextToken();
+			check(TOK.TOKlparen);
+			while (1)
+			{
+			tb = parseBasicType();
+			f.fthrows.push(tb);
+			if (token.value == TOK.TOKcomma)
+			{   nextToken();
+				continue;
+			}
+			break;
+			}
+			check(TOK.TOKrparen);
+			goto L1;
+}
+
+		case TOK.TOKin:
+			nextToken();
+			if (f.frequire)
+			error("redundant 'in' statement");
+			f.frequire = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope);
+			goto L1;
+
+		case TOK.TOKout:
+			// parse: out (identifier) { statement }
+			nextToken();
+			if (token.value != TOK.TOKlcurly)
+			{
+			check(TOK.TOKlparen);
+			if (token.value != TOK.TOKidentifier)	   
+				error("(identifier) following 'out' expected, not %s", token.toChars());
+			f.outId = token.ident;
+			nextToken();
+			check(TOK.TOKrparen);
+			}
+			if (f.fensure)
+			error("redundant 'out' statement");
+			f.fensure = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope);
+			goto L1;
+
+		default:
+			error("semicolon expected following function declaration");
+			break;
+		}
+		linkage = linksave;
+	}
+	
+    Statement parseStatement(ParseStatementFlags flags)
+	{
+		Statement s;
+		Token* t;
+		Condition condition;
+		Statement ifbody;
+		Statement elsebody;
+		bool isfinal;
+		Loc loc = this.loc;
+
+		//printf("parseStatement()\n");
+
+		if (flags & ParseStatementFlags.PScurly && token.value != TOK.TOKlcurly)
+			error("statement expected to be { }, not %s", token.toChars());
+
+		switch (token.value)
+		{
+		case TOK.TOKidentifier:
+			/* A leading identifier can be a declaration, label, or expression.
+			 * The easiest case to check first is label:
+			 */
+			t = peek(&token);
+			if (t.value == TOK.TOKcolon)
+			{	// It's a label
+
+			Identifier ident = token.ident;
+			nextToken();
+			nextToken();
+			s = parseStatement(ParseStatementFlags.PSsemi);
+			s = new LabelStatement(loc, ident, s);
+			break;
+			}
+			// fallthrough to TOK.TOKdot
+		case TOK.TOKdot:
+		case TOK.TOKtypeof:
+			if (isDeclaration(&token, 2, TOK.TOKreserved, null))
+			goto Ldeclaration;
+			else
+			goto Lexp;
+			break;
+
+		case TOK.TOKassert:
+		case TOK.TOKthis:
+		case TOK.TOKsuper:
+		case TOK.TOKint32v:
+		case TOK.TOKuns32v:
+		case TOK.TOKint64v:
+		case TOK.TOKuns64v:
+		case TOK.TOKfloat32v:
+		case TOK.TOKfloat64v:
+		case TOK.TOKfloat80v:
+		case TOK.TOKimaginary32v:
+		case TOK.TOKimaginary64v:
+		case TOK.TOKimaginary80v:
+		case TOK.TOKcharv:
+		case TOK.TOKwcharv:
+		case TOK.TOKdcharv:
+		case TOK.TOKnull:
+		case TOK.TOKtrue:
+		case TOK.TOKfalse:
+		case TOK.TOKstring:
+		case TOK.TOKlparen:
+		case TOK.TOKcast:
+		case TOK.TOKmul:
+		case TOK.TOKmin:
+		case TOK.TOKadd:
+		case TOK.TOKplusplus:
+		case TOK.TOKminusminus:
+		case TOK.TOKnew:
+		case TOK.TOKdelete:
+		case TOK.TOKdelegate:
+		case TOK.TOKfunction:
+		case TOK.TOKtypeid:
+		case TOK.TOKis:
+		case TOK.TOKlbracket:
+version (DMDV2) {
+		case TOK.TOKtraits:
+		case TOK.TOKfile:
+		case TOK.TOKline:
+}
+		Lexp:
+		{   Expression exp;
+
+			exp = parseExpression();
+			check(TOK.TOKsemicolon, "statement");
+			s = new ExpStatement(loc, exp);
+			break;
+		}
+
+		case TOK.TOKstatic:
+		{   // Look ahead to see if it's static assert() or static if()
+			Token *tt;
+
+			tt = peek(&token);
+			if (tt.value == TOK.TOKassert)
+			{
+				nextToken();
+				s = new StaticAssertStatement(parseStaticAssert());
+				break;
+			}
+			if (tt.value == TOK.TOKif)
+			{
+				nextToken();
+				condition = parseStaticIfCondition();
+				goto Lcondition;
+			}
+			goto Ldeclaration;
+		}
+
+		case TOK.TOKfinal:
+			if (peekNext() == TOK.TOKswitch)
+			{
+			nextToken();
+			isfinal = true;
+			goto Lswitch;
+			}
+			goto Ldeclaration;
+
+		case TOK.TOKwchar: case TOK.TOKdchar:
+		case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
+		case TOK.TOKint8: case TOK.TOKuns8:
+		case TOK.TOKint16: case TOK.TOKuns16:
+		case TOK.TOKint32: case TOK.TOKuns32:
+		case TOK.TOKint64: case TOK.TOKuns64:
+		case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
+		case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
+		case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
+		case TOK.TOKvoid:
+		case TOK.TOKtypedef:
+		case TOK.TOKalias:
+		case TOK.TOKconst:
+		case TOK.TOKauto:
+		case TOK.TOKextern:
+		case TOK.TOKinvariant:
+version (DMDV2) {
+		case TOK.TOKimmutable:
+		case TOK.TOKshared:
+		case TOK.TOKnothrow:
+		case TOK.TOKpure:
+		case TOK.TOKtls:
+		case TOK.TOKgshared:
+}
+	//	case TOK.TOKtypeof:
+		Ldeclaration:
+		{   Array a;
+
+			a = parseDeclarations(STC.STCundefined);
+			if (a.dim > 1)
+			{
+			Statements as = new Statements();
+			as.reserve(a.dim);
+			for (int i = 0; i < a.dim; i++)
+			{
+				Dsymbol d = cast(Dsymbol)a.data[i];
+				s = new DeclarationStatement(loc, d);
+				as.push(cast(void*)s);
+			}
+			s = new CompoundDeclarationStatement(loc, as);
+			}
+			else if (a.dim == 1)
+			{
+				Dsymbol d = cast(Dsymbol)a.data[0];
+			s = new DeclarationStatement(loc, d);
+			}
+			else
+			assert(0);
+			if (flags & ParseStatementFlags.PSscope)
+			s = new ScopeStatement(loc, s);
+			break;
+		}
+
+		case TOK.TOKstruct:
+		case TOK.TOKunion:
+		case TOK.TOKclass:
+		case TOK.TOKinterface:
+		{   Dsymbol d;
+
+			d = parseAggregate();
+			s = new DeclarationStatement(loc, d);
+			break;
+		}
+
+		case TOK.TOKenum:
+		{   /* Determine if this is a manifest constant declaration,
+			 * or a conventional enum.
+			 */
+			Dsymbol d;
+			Token* tt = peek(&token);
+			if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon)
+			d = parseEnum();
+			else if (tt.value != TOK.TOKidentifier)
+			goto Ldeclaration;
+			else
+			{
+			tt = peek(tt);
+			if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon ||
+				tt.value == TOK.TOKsemicolon)
+				d = parseEnum();
+			else
+				goto Ldeclaration;
+			}
+			s = new DeclarationStatement(loc, d);
+			break;
+		}
+
+		case TOK.TOKmixin:
+		{   t = peek(&token);
+			if (t.value == TOK.TOKlparen)
+			{	// mixin(string)
+			nextToken();
+			check(TOK.TOKlparen, "mixin");
+			Expression e = parseAssignExp();
+			check(TOK.TOKrparen);
+			check(TOK.TOKsemicolon);
+			s = new CompileStatement(loc, e);
+			break;
+			}
+			Dsymbol d = parseMixin();
+			s = new DeclarationStatement(loc, d);
+			break;
+		}
+
+		case TOK.TOKlcurly:
+		{   Statements statements;
+
+			nextToken();
+			statements = new Statements();
+			while (token.value != TOK.TOKrcurly)
+			{
+			statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
+			}
+			endloc = this.loc;
+			s = new CompoundStatement(loc, statements);
+			if (flags & (ParseStatementFlags.PSscope | ParseStatementFlags.PScurlyscope))
+			s = new ScopeStatement(loc, s);
+			nextToken();
+			break;
+		}
+
+		case TOK.TOKwhile:
+		{   Expression condition2;
+			Statement body_;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			condition2 = parseExpression();
+			check(TOK.TOKrparen);
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			s = new WhileStatement(loc, condition2, body_);
+			break;
+		}
+
+		case TOK.TOKsemicolon:
+			if (!(flags & ParseStatementFlags.PSsemi))
+			error("use '{ }' for an empty statement, not a ';'");
+			nextToken();
+			s = new ExpStatement(loc, null);
+			break;
+
+		case TOK.TOKdo:
+		{   Statement body_;
+			Expression condition2;
+
+			nextToken();
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			check(TOK.TOKwhile);
+			check(TOK.TOKlparen);
+			condition2 = parseExpression();
+			check(TOK.TOKrparen);
+			s = new DoStatement(loc, body_, condition2);
+			break;
+		}
+
+		case TOK.TOKfor:
+		{
+			Statement init;
+			Expression condition2;
+			Expression increment;
+			Statement body_;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			if (token.value == TOK.TOKsemicolon)
+			{	init = null;
+			nextToken();
+			}
+			else
+			{	init = parseStatement(cast(ParseStatementFlags)0);
+			}
+			if (token.value == TOK.TOKsemicolon)
+			{
+			condition2 = null;
+			nextToken();
+			}
+			else
+			{
+			condition2 = parseExpression();
+			check(TOK.TOKsemicolon, "for condition");
+			}
+			if (token.value == TOK.TOKrparen)
+			{	increment = null;
+			nextToken();
+			}
+			else
+			{	increment = parseExpression();
+			check(TOK.TOKrparen);
+			}
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			s = new ForStatement(loc, init, condition2, increment, body_);
+			if (init)
+			s = new ScopeStatement(loc, s);
+			break;
+		}
+
+		case TOK.TOKforeach:
+		case TOK.TOKforeach_reverse:
+		{
+			TOK op = token.value;
+			Arguments arguments;
+
+			Statement d;
+			Statement body_;
+			Expression aggr;
+
+			nextToken();
+			check(TOK.TOKlparen);
+
+			arguments = new Arguments();
+
+			while (1)
+			{
+			Type tb;
+			Identifier ai = null;
+			Type at;
+			STC storageClass = STC.STCundefined;
+			Argument a;
+
+			if (token.value == TOK.TOKinout || token.value == TOK.TOKref)
+			{   storageClass = STC.STCref;
+				nextToken();
+			}
+			if (token.value == TOK.TOKidentifier)
+			{
+				Token *tt = peek(&token);
+				if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon)
+				{	ai = token.ident;
+				at = null;		// infer argument type
+				nextToken();
+				goto Larg;
+				}
+			}
+			at = parseType(&ai);
+			if (!ai)
+				error("no identifier for declarator %s", at.toChars());
+			  Larg:
+			a = new Argument(storageClass, at, ai, null);
+			arguments.push(cast(void*)a);
+			if (token.value == TOK.TOKcomma)
+			{   nextToken();
+				continue;
+			}
+			break;
+			}
+			check(TOK.TOKsemicolon);
+
+			aggr = parseExpression();
+			if (token.value == TOK.TOKslice && arguments.dim == 1)
+			{
+			Argument a = cast(Argument)arguments.data[0];
+			delete arguments;
+			nextToken();
+			Expression upr = parseExpression();
+			check(TOK.TOKrparen);
+			body_ = parseStatement(cast(ParseStatementFlags)0);
+			s = new ForeachRangeStatement(loc, op, a, aggr, upr, body_);
+			}
+			else
+			{
+			check(TOK.TOKrparen);
+			body_ = parseStatement(cast(ParseStatementFlags)0);
+			s = new ForeachStatement(loc, op, arguments, aggr, body_);
+			}
+			break;
+		}
+
+		case TOK.TOKif:
+		{   Argument arg = null;
+			Expression condition2;
+			Statement ifbody2;
+			Statement elsebody2;
+
+			nextToken();
+			check(TOK.TOKlparen);
+
+			if (token.value == TOK.TOKauto)
+			{
+			nextToken();
+			if (token.value == TOK.TOKidentifier)
+			{
+				Token *tt = peek(&token);
+				if (tt.value == TOK.TOKassign)
+				{
+					arg = new Argument(STC.STCundefined, null, token.ident, null);
+					nextToken();
+					nextToken();
+				}
+				else
+				{   error("= expected following auto identifier");
+				goto Lerror;
+				}
+			}
+			else
+			{   error("identifier expected following auto");
+				goto Lerror;
+			}
+			}
+			else if (isDeclaration(&token, 2, TOK.TOKassign, null))
+			{
+			Type at;
+			Identifier ai;
+
+			at = parseType(&ai);
+			check(TOK.TOKassign);
+			arg = new Argument(STC.STCundefined, at, ai, null);
+			}
+
+			// Check for " ident;"
+			else if (token.value == TOK.TOKidentifier)
+			{
+			Token *tt = peek(&token);
+			if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon)
+			{
+				arg = new Argument(STC.STCundefined, null, token.ident, null);
+				nextToken();
+				nextToken();
+				if (1 || !global.params.useDeprecated)
+				error("if (v; e) is deprecated, use if (auto v = e)");
+			}
+			}
+
+			condition2 = parseExpression();
+			check(TOK.TOKrparen);
+			ifbody2 = parseStatement(ParseStatementFlags.PSscope);
+			if (token.value == TOK.TOKelse)
+			{
+			nextToken();
+			elsebody2 = parseStatement(ParseStatementFlags.PSscope);
+			}
+			else
+			elsebody2 = null;
+			s = new IfStatement(loc, arg, condition2, ifbody2, elsebody2);
+			break;
+		}
+
+		case TOK.TOKscope:
+			if (peek(&token).value != TOK.TOKlparen)
+			goto Ldeclaration;		// scope used as storage class
+			nextToken();
+			check(TOK.TOKlparen);
+			if (token.value != TOK.TOKidentifier)
+			{	error("scope identifier expected");
+			goto Lerror;
+			}
+			else
+			{	TOK tt = TOK.TOKon_scope_exit;
+			Identifier id = token.ident;
+
+			if (id == Id.exit)
+				tt = TOK.TOKon_scope_exit;
+			else if (id == Id.failure)
+				tt = TOK.TOKon_scope_failure;
+			else if (id == Id.success)
+				tt = TOK.TOKon_scope_success;
+			else
+				error("valid scope identifiers are exit, failure, or success, not %s", id.toChars());
+			nextToken();
+			check(TOK.TOKrparen);
+			Statement st = parseStatement(ParseStatementFlags.PScurlyscope);
+			s = new OnScopeStatement(loc, tt, st);
+			break;
+			}
+
+		case TOK.TOKdebug:
+			nextToken();
+			condition = parseDebugCondition();
+			goto Lcondition;
+
+		case TOK.TOKversion:
+			nextToken();
+			condition = parseVersionCondition();
+			goto Lcondition;
+
+		Lcondition:
+			ifbody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/);
+			elsebody = null;
+			if (token.value == TOK.TOKelse)
+			{
+			nextToken();
+			elsebody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/);
+			}
+			s = new ConditionalStatement(loc, condition, ifbody, elsebody);
+			break;
+
+		case TOK.TOKpragma:
+		{   Identifier ident;
+			Expressions args = null;
+			Statement body_;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			if (token.value != TOK.TOKidentifier)
+			{   error("pragma(identifier expected");
+			goto Lerror;
+			}
+			ident = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen)
+			args = parseArguments();	// pragma(identifier, args...);
+			else
+			check(TOK.TOKrparen);		// pragma(identifier);
+			if (token.value == TOK.TOKsemicolon)
+			{	nextToken();
+			body_ = null;
+			}
+			else
+			body_ = parseStatement(ParseStatementFlags.PSsemi);
+			s = new PragmaStatement(loc, ident, args, body_);
+			break;
+		}
+
+		case TOK.TOKswitch:
+			isfinal = false;
+			goto Lswitch;
+
+		Lswitch:
+		{
+			nextToken();
+			check(TOK.TOKlparen);
+			Expression condition2 = parseExpression();
+			check(TOK.TOKrparen);
+			Statement body_ = parseStatement(ParseStatementFlags.PSscope);
+			s = new SwitchStatement(loc, condition2, body_, isfinal);
+			break;
+		}
+
+		case TOK.TOKcase:
+		{   Expression exp;
+			Statements statements;
+			scope Array cases = new Array();	// array of Expression's
+			Expression last = null;
+
+			while (1)
+			{
+			nextToken();
+			exp = parseAssignExp();
+			cases.push(cast(void*)exp);
+			if (token.value != TOK.TOKcomma)
+				break;
+			}
+			check(TOK.TOKcolon);
+
+version (DMDV2) {
+			/* case exp: .. case last:
+			 */
+			if (token.value == TOK.TOKslice)
+			{
+			if (cases.dim > 1)
+				error("only one case allowed for start of case range");
+			nextToken();
+			check(TOK.TOKcase);
+			last = parseAssignExp();
+			check(TOK.TOKcolon);
+			}
+}
+
+			statements = new Statements();
+			while (token.value != TOK.TOKcase &&
+			   token.value != TOK.TOKdefault &&
+			   token.value != TOK.TOKrcurly)
+			{
+			statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
+			}
+			s = new CompoundStatement(loc, statements);
+			s = new ScopeStatement(loc, s);
+
+///version (DMDV2) {
+			if (last)
+			{
+				s = new CaseRangeStatement(loc, exp, last, s);
+			}
+			else
+///}
+			{
+				// Keep cases in order by building the case statements backwards
+				for (int i = cases.dim; i; i--)
+				{
+					exp = cast(Expression)cases.data[i - 1];
+					s = new CaseStatement(loc, exp, s);
+				}
+			}
+			break;
+		}
+
+		case TOK.TOKdefault:
+		{
+			Statements statements;
+
+			nextToken();
+			check(TOK.TOKcolon);
+
+			statements = new Statements();
+			while (token.value != TOK.TOKcase &&
+			   token.value != TOK.TOKdefault &&
+			   token.value != TOK.TOKrcurly)
+			{
+			statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
+			}
+			s = new CompoundStatement(loc, statements);
+			s = new ScopeStatement(loc, s);
+			s = new DefaultStatement(loc, s);
+			break;
+		}
+
+		case TOK.TOKreturn:
+		{   Expression exp;
+
+			nextToken();
+			if (token.value == TOK.TOKsemicolon)
+			exp = null;
+			else
+			exp = parseExpression();
+			check(TOK.TOKsemicolon, "return statement");
+			s = new ReturnStatement(loc, exp);
+			break;
+		}
+
+		case TOK.TOKbreak:
+		{   Identifier ident;
+
+			nextToken();
+			if (token.value == TOK.TOKidentifier)
+			{	ident = token.ident;
+			nextToken();
+			}
+			else
+			ident = null;
+			check(TOK.TOKsemicolon, "break statement");
+			s = new BreakStatement(loc, ident);
+			break;
+		}
+
+		case TOK.TOKcontinue:
+		{   Identifier ident;
+
+			nextToken();
+			if (token.value == TOK.TOKidentifier)
+			{	ident = token.ident;
+			nextToken();
+			}
+			else
+			ident = null;
+			check(TOK.TOKsemicolon, "continue statement");
+			s = new ContinueStatement(loc, ident);
+			break;
+		}
+
+		case TOK.TOKgoto:
+		{   Identifier ident;
+
+			nextToken();
+			if (token.value == TOK.TOKdefault)
+			{
+			nextToken();
+			s = new GotoDefaultStatement(loc);
+			}
+			else if (token.value == TOK.TOKcase)
+			{
+			Expression exp = null;
+
+			nextToken();
+			if (token.value != TOK.TOKsemicolon)
+				exp = parseExpression();
+			s = new GotoCaseStatement(loc, exp);
+			}
+			else
+			{
+			if (token.value != TOK.TOKidentifier)
+			{   error("Identifier expected following goto");
+				ident = null;
+			}
+			else
+			{   ident = token.ident;
+				nextToken();
+			}
+			s = new GotoStatement(loc, ident);
+			}
+			check(TOK.TOKsemicolon, "goto statement");
+			break;
+		}
+
+		case TOK.TOKsynchronized:
+		{   Expression exp;
+			Statement body_;
+
+			nextToken();
+			if (token.value == TOK.TOKlparen)
+			{
+			nextToken();
+			exp = parseExpression();
+			check(TOK.TOKrparen);
+			}
+			else
+			exp = null;
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			s = new SynchronizedStatement(loc, exp, body_);
+			break;
+		}
+
+		case TOK.TOKwith:
+		{   Expression exp;
+			Statement body_;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			exp = parseExpression();
+			check(TOK.TOKrparen);
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			s = new WithStatement(loc, exp, body_);
+			break;
+		}
+
+		case TOK.TOKtry:
+		{   Statement body_;
+			Array catches = null;
+			Statement finalbody = null;
+
+			nextToken();
+			body_ = parseStatement(ParseStatementFlags.PSscope);
+			while (token.value == TOK.TOKcatch)
+			{
+				Statement handler;
+				Catch c;
+				Type tt;
+				Identifier id;
+				Loc loc2 = this.loc;
+
+				nextToken();
+				if (token.value == TOK.TOKlcurly)
+				{
+					tt = null;
+					id = null;
+				}
+				else
+				{
+					check(TOK.TOKlparen);
+					id = null;
+					tt = parseType(&id);
+					check(TOK.TOKrparen);
+				}
+				handler = parseStatement(cast(ParseStatementFlags)0);
+				c = new Catch(loc2, tt, id, handler);
+				if (!catches)
+					catches = new Array();
+				catches.push(cast(void*)c);
+			}
+
+			if (token.value == TOK.TOKfinally)
+			{	nextToken();
+			finalbody = parseStatement(cast(ParseStatementFlags)0);
+			}
+
+			s = body_;
+			if (!catches && !finalbody)
+			error("catch or finally expected following try");
+			else
+			{	if (catches)
+				s = new TryCatchStatement(loc, body_, catches);
+			if (finalbody)
+				s = new TryFinallyStatement(loc, s, finalbody);
+			}
+			break;
+		}
+
+		case TOK.TOKthrow:
+		{   Expression exp;
+
+			nextToken();
+			exp = parseExpression();
+			check(TOK.TOKsemicolon, "throw statement");
+			s = new ThrowStatement(loc, exp);
+			break;
+		}
+
+		case TOK.TOKvolatile:
+			nextToken();
+			s = parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope);
+version (DMDV2) {
+			if (!global.params.useDeprecated)
+				error("volatile statements deprecated; used synchronized statements instead");
+}
+			s = new VolatileStatement(loc, s);
+			break;
+
+		case TOK.TOKasm:
+		{   Statements statements;
+			Identifier label;
+			Loc labelloc;
+			Token* toklist;
+			Token** ptoklist;
+
+			// Parse the asm block into a sequence of AsmStatements,
+			// each AsmStatement is one instruction.
+			// Separate out labels.
+			// Defer parsing of AsmStatements until semantic processing.
+
+			nextToken();
+			check(TOK.TOKlcurly);
+			toklist = null;
+			ptoklist = &toklist;
+			label = null;
+			statements = new Statements();
+			while (1)
+			{
+			switch (token.value)
+			{
+				case TOK.TOKidentifier:
+				if (!toklist)
+				{
+					// Look ahead to see if it is a label
+					t = peek(&token);
+					if (t.value == TOK.TOKcolon)
+					{   // It's a label
+					label = token.ident;
+					labelloc = this.loc;
+					nextToken();
+					nextToken();
+					continue;
+					}
+				}
+				goto Ldefault;
+
+				case TOK.TOKrcurly:
+				if (toklist || label)
+				{
+					error("asm statements must end in ';'");
+				}
+				break;
+
+				case TOK.TOKsemicolon:
+				s = null;
+				if (toklist || label)
+				{   // Create AsmStatement from list of tokens we've saved
+					s = new AsmStatement(this.loc, toklist);
+					toklist = null;
+					ptoklist = &toklist;
+					if (label)
+					{   
+						s = new LabelStatement(labelloc, label, s);
+						label = null;
+					}
+					statements.push(cast(void*)s);
+				}
+				nextToken();
+				continue;
+
+				case TOK.TOKeof:
+				/* { */
+				error("matching '}' expected, not end of file");
+				break;
+
+				default:
+				Ldefault:
+				*ptoklist = new Token();
+				memcpy(*ptoklist, &token, Token.sizeof);
+				ptoklist = &(*ptoklist).next;
+				*ptoklist = null;
+
+				nextToken();
+				continue;
+			}
+			break;
+			}
+			s = new CompoundStatement(loc, statements);
+			nextToken();
+			break;
+		}
+
+		default:
+			error("found '%s' instead of statement", token.toChars());
+			goto Lerror;
+
+		Lerror:
+			while (token.value != TOK.TOKrcurly &&
+			   token.value != TOK.TOKsemicolon &&
+			   token.value != TOK.TOKeof)
+			nextToken();
+			if (token.value == TOK.TOKsemicolon)
+			nextToken();
+			s = null;
+			break;
+		}
+
+		return s;
+	}
+	
+	/*****************************************
+	 * Parse initializer for variable declaration.
+	 */
+    Initializer parseInitializer()
+	{
+		StructInitializer is_;
+		ArrayInitializer ia;
+		ExpInitializer ie;
+		Expression e;
+		Identifier id;
+		Initializer value;
+		int comma;
+		Loc loc = this.loc;
+		Token* t;
+		int braces;
+		int brackets;
+
+		switch (token.value)
+		{
+			case TOK.TOKlcurly:
+				/* Scan ahead to see if it is a struct initializer or
+				 * a function literal.
+				 * If it contains a ';', it is a function literal.
+				 * Treat { } as a struct initializer.
+				 */
+				braces = 1;
+				for (t = peek(&token); 1; t = peek(t))
+				{
+					switch (t.value)
+					{
+						case TOK.TOKsemicolon:
+						case TOK.TOKreturn:
+							goto Lexpression;
+
+						case TOK.TOKlcurly:
+							braces++;
+							continue;
+
+						case TOK.TOKrcurly:
+							if (--braces == 0)
+								break;
+							continue;
+
+						case TOK.TOKeof:
+							break;
+
+						default:
+							continue;
+					}
+					break;
+				}
+
+				is_ = new StructInitializer(loc);
+				nextToken();
+				comma = 0;
+				while (1)
+				{
+					switch (token.value)
+					{
+						case TOK.TOKidentifier:
+							if (comma == 1)
+								error("comma expected separating field initializers");
+							t = peek(&token);
+							if (t.value == TOK.TOKcolon)
+							{
+								id = token.ident;
+								nextToken();
+								nextToken();	// skip over ':'
+							}
+							else
+							{   
+								id = null;
+							}
+							value = parseInitializer();
+							is_.addInit(id, value);
+							comma = 1;
+							continue;
+
+						case TOK.TOKcomma:
+							nextToken();
+							comma = 2;
+							continue;
+
+						case TOK.TOKrcurly:		// allow trailing comma's
+							nextToken();
+							break;
+
+						case TOK.TOKeof:
+							error("found EOF instead of initializer");
+							break;
+
+						default:
+							value = parseInitializer();
+							is_.addInit(null, value);
+							comma = 1;
+							continue;
+							//error("found '%s' instead of field initializer", token.toChars());
+							//break;
+					}
+					break;
+				}
+				return is_;
+
+			case TOK.TOKlbracket:
+				/* Scan ahead to see if it is an array initializer or
+				 * an expression.
+				 * If it ends with a ';' ',' or '}', it is an array initializer.
+				 */
+				brackets = 1;
+				for (t = peek(&token); 1; t = peek(t))
+				{
+					switch (t.value)
+					{
+						case TOK.TOKlbracket:
+							brackets++;
+							continue;
+
+						case TOK.TOKrbracket:
+							if (--brackets == 0)
+							{   
+								t = peek(t);
+								if (t.value != TOK.TOKsemicolon &&
+									t.value != TOK.TOKcomma &&
+								t.value != TOK.TOKrcurly)
+								goto Lexpression;
+								break;
+							}
+							continue;
+
+						case TOK.TOKeof:
+							break;
+
+						default:
+							continue;
+					}
+					break;
+				}
+
+				ia = new ArrayInitializer(loc);
+				nextToken();
+				comma = 0;
+				while (true)
+				{
+					switch (token.value)
+					{
+						default:
+							if (comma == 1)
+							{   
+								error("comma expected separating array initializers, not %s", token.toChars());
+								nextToken();
+								break;
+							}
+							e = parseAssignExp();
+							if (!e)
+								break;
+							if (token.value == TOK.TOKcolon)
+							{
+								nextToken();
+								value = parseInitializer();
+							}
+							else
+							{   value = new ExpInitializer(e.loc, e);
+								e = null;
+							}
+							ia.addInit(e, value);
+							comma = 1;
+							continue;
+
+						case TOK.TOKlcurly:
+						case TOK.TOKlbracket:
+							if (comma == 1)
+								error("comma expected separating array initializers, not %s", token.toChars());
+							value = parseInitializer();
+							ia.addInit(null, value);
+							comma = 1;
+							continue;
+
+						case TOK.TOKcomma:
+							nextToken();
+							comma = 2;
+							continue;
+
+						case TOK.TOKrbracket:		// allow trailing comma's
+							nextToken();
+							break;
+
+						case TOK.TOKeof:
+							error("found '%s' instead of array initializer", token.toChars());
+							break;
+					}
+					break;
+				}
+				return ia;
+
+			case TOK.TOKvoid:
+				t = peek(&token);
+				if (t.value == TOK.TOKsemicolon || t.value == TOK.TOKcomma)
+				{
+					nextToken();
+					return new VoidInitializer(loc);
+				}
+				goto Lexpression;
+
+			default:
+			Lexpression:
+				e = parseAssignExp();
+				ie = new ExpInitializer(loc, e);
+				return ie;
+		}
+	}
+	
+	/*****************************************
+	 * Parses default argument initializer expression that is an assign expression,
+	 * with special handling for __FILE__ and __LINE__.
+	 */
+version (DMDV2) {
+    Expression parseDefaultInitExp()
+	{
+		if (token.value == TOK.TOKfile ||
+			token.value == TOK.TOKline)
+		{
+			Token* t = peek(&token);
+			if (t.value == TOK.TOKcomma || t.value == TOK.TOKrparen)
+			{   
+				Expression e;
+
+				if (token.value == TOK.TOKfile)
+					e = new FileInitExp(loc);
+				else
+					e = new LineInitExp(loc);
+				nextToken();
+				return e;
+			}
+		}
+
+		Expression e = parseAssignExp();
+		return e;
+	}
+}
+    void check(Loc loc, TOK value)
+	{
+		if (token.value != value)
+			error(loc, "found '%s' when expecting '%s'", token.toChars(), Token.toChars(value));
+		nextToken();
+	}
+	
+    void check(TOK value)
+	{
+		check(loc, value);
+	}
+	
+    void check(TOK value, string string_)
+	{
+		if (token.value != value) {
+			error("found '%s' when expecting '%s' following '%s'", token.toChars(), Token.toChars(value), string_);
+		}
+		nextToken();
+	}
+	
+	/************************************
+	 * Determine if the scanner is sitting on the start of a declaration.
+	 * Input:
+	 *	needId	0	no identifier
+	 *		1	identifier optional
+	 *		2	must have identifier
+	 * Output:
+	 *	if *pt is not null, it is set to the ending token, which would be endtok
+	 */
+
+    bool isDeclaration(Token* t, int needId, TOK endtok, Token** pt)
+	{
+		//printf("isDeclaration(needId = %d)\n", needId);
+		int haveId = 0;
+
+version (DMDV2) {
+		if ((t.value == TOK.TOKconst ||
+			t.value == TOK.TOKinvariant ||
+			t.value == TOK.TOKimmutable ||
+			t.value == TOK.TOKshared) &&
+			peek(t).value != TOK.TOKlparen)
+		{
+			/* const type
+			* immutable type
+			* shared type
+			*/
+			t = peek(t);
+		}
+}
+
+		if (!isBasicType(&t))
+		{
+			goto Lisnot;
+		}
+		if (!isDeclarator(&t, &haveId, endtok))
+			goto Lisnot;
+		if ( needId == 1 ||
+			(needId == 0 && !haveId) ||
+			(needId == 2 &&  haveId))
+		{	
+			if (pt)
+				*pt = t;
+			goto Lis;
+		}
+		else
+			goto Lisnot;
+
+	Lis:
+		//printf("\tis declaration, t = %s\n", t.toChars());
+		return true;
+
+	Lisnot:
+		//printf("\tis not declaration\n");
+		return false;
+	}
+	
+    bool isBasicType(Token** pt)
+	{
+		// This code parallels parseBasicType()
+		Token* t = *pt;
+		Token* t2;
+		int parens;
+		int haveId = 0;
+
+		switch (t.value)
+		{
+		case TOKwchar:
+		case TOKdchar:
+		case TOKbit:
+		case TOKbool:
+		case TOKchar:
+		case TOKint8:
+		case TOKuns8:
+		case TOKint16:
+		case TOKuns16:
+		case TOKint32:
+		case TOKuns32:
+		case TOKint64:
+		case TOKuns64:
+		case TOKfloat32:
+		case TOKfloat64:
+		case TOKfloat80:
+		case TOKimaginary32:
+		case TOKimaginary64:
+		case TOKimaginary80:
+		case TOKcomplex32:
+		case TOKcomplex64:
+		case TOKcomplex80:
+		case TOKvoid:
+			t = peek(t);
+			break;
+
+		case TOK.TOKidentifier:
+		L5:
+			t = peek(t);
+			if (t.value == TOK.TOKnot)
+			{
+			goto L4;
+			}
+			goto L3;
+			while (1)
+			{
+		L2:
+			t = peek(t);
+		L3:
+			if (t.value == TOK.TOKdot)
+			{
+		Ldot:
+				t = peek(t);
+				if (t.value != TOK.TOKidentifier)
+				goto Lfalse;
+				t = peek(t);
+				if (t.value != TOK.TOKnot)
+				goto L3;
+		L4:
+				/* Seen a !
+				 * Look for:
+				 * !( args ), !identifier, etc.
+				 */
+				t = peek(t);
+				switch (t.value)
+				{	case TOK.TOKidentifier:
+					goto L5;
+				case TOK.TOKlparen:
+					if (!skipParens(t, &t))
+					goto Lfalse;
+					break;
+				case TOK.TOKwchar: case TOK.TOKdchar:
+				case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
+				case TOK.TOKint8: case TOK.TOKuns8:
+				case TOK.TOKint16: case TOK.TOKuns16:
+				case TOK.TOKint32: case TOK.TOKuns32:
+				case TOK.TOKint64: case TOK.TOKuns64:
+				case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
+				case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
+				case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
+				case TOK.TOKvoid:
+				case TOK.TOKint32v:
+				case TOK.TOKuns32v:
+				case TOK.TOKint64v:
+				case TOK.TOKuns64v:
+				case TOK.TOKfloat32v:
+				case TOK.TOKfloat64v:
+				case TOK.TOKfloat80v:
+				case TOK.TOKimaginary32v:
+				case TOK.TOKimaginary64v:
+				case TOK.TOKimaginary80v:
+				case TOK.TOKnull:
+				case TOK.TOKtrue:
+				case TOK.TOKfalse:
+				case TOK.TOKcharv:
+				case TOK.TOKwcharv:
+				case TOK.TOKdcharv:
+				case TOK.TOKstring:
+				case TOK.TOKfile:
+				case TOK.TOKline:
+					goto L2;
+				default:
+					goto Lfalse;
+				}
+			}
+			else
+				break;
+			}
+			break;
+
+		case TOK.TOKdot:
+			goto Ldot;
+
+		case TOK.TOKtypeof:
+			/* typeof(exp).identifier...
+			 */
+			t = peek(t);
+			if (t.value != TOK.TOKlparen)
+			goto Lfalse;
+			if (!skipParens(t, &t))
+			goto Lfalse;
+			goto L2;
+
+		case TOK.TOKconst:
+		case TOK.TOKinvariant:
+		case TOK.TOKimmutable:
+		case TOK.TOKshared:
+			// const(type)  or  immutable(type)  or  shared(type)
+			t = peek(t);
+			if (t.value != TOK.TOKlparen)
+			goto Lfalse;
+			t = peek(t);
+			if (!isDeclaration(t, 0, TOK.TOKrparen, &t))
+			{
+			goto Lfalse;
+			}
+			t = peek(t);
+			break;
+
+		default:
+			goto Lfalse;
+		}
+		*pt = t;
+		//printf("is\n");
+		return true;
+
+	Lfalse:
+		//printf("is not\n");
+		return false;
+	}
+	
+    bool isDeclarator(Token** pt, int* haveId, TOK endtok)
+	{
+		// This code parallels parseDeclarator()
+		Token* t = *pt;
+		bool parens;
+
+		//printf("Parser.isDeclarator()\n");
+		//t.print();
+		if (t.value == TOK.TOKassign)
+			return false;
+
+		while (true)
+		{
+			parens = false;
+			switch (t.value)
+			{
+				case TOK.TOKmul:
+				//case TOKand:
+					t = peek(t);
+					continue;
+
+				case TOK.TOKlbracket:
+					t = peek(t);
+					if (t.value == TOK.TOKrbracket)
+					{
+						t = peek(t);
+					}
+					else if (isDeclaration(t, 0, TOK.TOKrbracket, &t))
+					{   
+						// It's an associative array declaration
+						t = peek(t);
+					}
+					else
+					{
+						// [ expression ]
+						// [ expression .. expression ]
+						if (!isExpression(&t))
+							return false;
+						if (t.value == TOK.TOKslice)
+						{	
+							t = peek(t);
+							if (!isExpression(&t))
+								return false;
+						}
+						if (t.value != TOK.TOKrbracket)
+							return false;
+						t = peek(t);
+					}
+					continue;
+
+				case TOK.TOKidentifier:
+					if (*haveId)
+						return false;
+					*haveId = true;
+					t = peek(t);
+					break;
+
+				case TOK.TOKlparen:
+					t = peek(t);
+
+					if (t.value == TOK.TOKrparen)
+						return false;		// () is not a declarator
+
+					/* Regard ( identifier ) as not a declarator
+					 * BUG: what about ( *identifier ) in
+					 *	f(*p)(x);
+					 * where f is a class instance with overloaded () ?
+					 * Should we just disallow C-style function pointer declarations?
+					 */
+					if (t.value == TOK.TOKidentifier)
+					{   
+						Token *t2 = peek(t);
+						if (t2.value == TOK.TOKrparen)
+							return false;
+					}
+
+					if (!isDeclarator(&t, haveId, TOK.TOKrparen))
+						return false;
+					t = peek(t);
+					parens = true;
+					break;
+
+				case TOK.TOKdelegate:
+				case TOK.TOKfunction:
+					t = peek(t);
+					if (!isParameters(&t))
+						return false;
+					continue;
+				default:
+					break;	///
+			}
+			break;
+		}
+
+		while (1)
+		{
+			switch (t.value)
+			{
+version (CARRAYDECL) {
+				case TOK.TOKlbracket:
+					parens = false;
+					t = peek(t);
+					if (t.value == TOK.TOKrbracket)
+					{
+						t = peek(t);
+					}
+					else if (isDeclaration(t, 0, TOKrbracket, &t))
+					{   
+						// It's an associative array declaration
+						t = peek(t);
+					}
+					else
+					{
+						// [ expression ]
+						if (!isExpression(&t))
+							return false;
+						if (t.value != TOK.TOKrbracket)
+							return false;
+						t = peek(t);
+					}
+					continue;
+}
+
+				case TOK.TOKlparen:
+					parens = false;
+					if (!isParameters(&t))
+						return false;
+version (DMDV2) {
+					while (true)
+					{
+						switch (t.value)
+						{
+							case TOK.TOKconst:
+							case TOK.TOKinvariant:
+							case TOK.TOKimmutable:
+							case TOK.TOKshared:
+							case TOK.TOKpure:
+							case TOK.TOKnothrow:
+								t = peek(t);
+								continue;
+							case TOK.TOKat:
+								t = peek(t);	// skip '@'
+								t = peek(t);	// skip identifier
+								continue;
+							default:
+								break;
+						}
+						break;
+					}
+}
+					continue;
+
+				// Valid tokens that follow a declaration
+				case TOK.TOKrparen:
+				case TOK.TOKrbracket:
+				case TOK.TOKassign:
+				case TOK.TOKcomma:
+				case TOK.TOKsemicolon:
+				case TOK.TOKlcurly:
+				case TOK.TOKin:
+					// The !parens is to disallow unnecessary parentheses
+					if (!parens && (endtok == TOK.TOKreserved || endtok == t.value))
+					{   
+						*pt = t;
+						return true;
+					}
+					return false;
+
+				default:
+					return false;
+			}
+		}
+	}
+	
+    bool isParameters(Token** pt)
+	{
+		// This code parallels parseParameters()
+		Token* t = *pt;
+
+		//printf("isParameters()\n");
+		if (t.value != TOKlparen)
+			return false;
+
+		t = peek(t);
+		for (;1; t = peek(t))
+		{
+			 L1:
+			switch (t.value)
+			{
+				case TOKrparen:
+					break;
+
+				case TOKdotdotdot:
+					t = peek(t);
+					break;
+
+				case TOKin:
+				case TOKout:
+				case TOKinout:
+				case TOKref:
+				case TOKlazy:
+				case TOKfinal:
+					continue;
+
+				case TOKconst:
+				case TOKinvariant:
+				case TOKimmutable:
+				case TOKshared:
+					t = peek(t);
+					if (t.value == TOKlparen)
+					{
+						t = peek(t);
+						if (!isDeclaration(t, 0, TOKrparen, &t))
+						return false;
+						t = peek(t);	// skip past closing ')'
+						goto L2;
+					}
+					goto L1;
+
+		static if (false) {
+				case TOKstatic:
+					continue;
+				case TOKauto:
+				case TOKalias:
+					t = peek(t);
+					if (t.value == TOKidentifier)
+						t = peek(t);
+					if (t.value == TOKassign)
+					{   t = peek(t);
+						if (!isExpression(&t))
+						return false;
+					}
+					goto L3;
+		}
+
+				default:
+				{	
+					if (!isBasicType(&t))
+						return false;
+					L2:
+					int tmp = false;
+					if (t.value != TOKdotdotdot &&
+						!isDeclarator(&t, &tmp, TOKreserved))
+						return false;
+					if (t.value == TOKassign)
+					{
+						t = peek(t);
+						if (!isExpression(&t))
+							return false;
+					}
+					if (t.value == TOKdotdotdot)
+					{
+						t = peek(t);
+						break;
+					}
+				}
+				L3:
+				if (t.value == TOKcomma)
+				{
+					continue;
+				}
+				break;
+			}
+			break;
+		}
+
+		if (t.value != TOKrparen)
+			return false;
+
+		t = peek(t);
+		*pt = t;
+		return true;
+	}
+	
+    bool isExpression(Token** pt)
+	{
+		// This is supposed to determine if something is an expression.
+		// What it actually does is scan until a closing right bracket
+		// is found.
+
+		Token* t = *pt;
+		int brnest = 0;
+		int panest = 0;
+		int curlynest = 0;
+
+		for (;; t = peek(t))
+		{
+			switch (t.value)
+			{
+				case TOKlbracket:
+					brnest++;
+					continue;
+
+				case TOKrbracket:
+					if (--brnest >= 0)
+						continue;
+					break;
+
+				case TOKlparen:
+					panest++;
+					continue;
+
+				case TOKcomma:
+					if (brnest || panest)
+						continue;
+					break;
+
+				case TOKrparen:
+					if (--panest >= 0)
+						continue;
+					break;
+
+				case TOKlcurly:
+					curlynest++;
+					continue;
+
+				case TOKrcurly:
+					if (--curlynest >= 0)
+						continue;
+					return false;
+
+				case TOKslice:
+					if (brnest)
+						continue;
+					break;
+
+				case TOKsemicolon:
+					if (curlynest)
+						continue;
+					return false;
+
+				case TOKeof:
+					return false;
+
+				default:
+					continue;
+			}
+			break;
+		}
+
+		*pt = t;
+		return true;
+	}
+	
+    int isTemplateInstance(Token t, Token* pt)
+	{
+		assert(false);
+	}
+	
+	/*******************************************
+	 * Skip parens, brackets.
+	 * Input:
+	 *	t is on opening (
+	 * Output:
+	 *	*pt is set to closing token, which is ')' on success
+	 * Returns:
+	 *	!=0	successful
+	 *	0	some parsing error
+	 */
+    bool skipParens(Token* t, Token** pt)
+	{
+		int parens = 0;
+
+		while (1)
+		{
+			switch (t.value)
+			{
+				case TOKlparen:
+					parens++;
+					break;
+
+				case TOKrparen:
+					parens--;
+					if (parens < 0)
+						goto Lfalse;
+					if (parens == 0)
+						goto Ldone;
+					break;
+
+				case TOKeof:
+				case TOKsemicolon:
+					goto Lfalse;
+
+				default:
+					break;
+			}
+			t = peek(t);
+		}
+
+	  Ldone:
+		if (*pt)
+			*pt = t;
+		return true;
+
+	  Lfalse:
+		return false;
+	}
+
+    Expression parseExpression()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		//printf("Parser.parseExpression() loc = %d\n", loc.linnum);
+		e = parseAssignExp();
+		while (token.value == TOK.TOKcomma)
+		{
+			nextToken();
+			e2 = parseAssignExp();
+			e = new CommaExp(loc, e, e2);
+			loc = this.loc;
+		}
+		return e;
+	}
+	
+    Expression parsePrimaryExp()
+	{
+		Expression e;
+		Type t;
+		Identifier id;
+		TOK save;
+		Loc loc = this.loc;
+
+		//printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+		switch (token.value)
+		{
+		case TOK.TOKidentifier:
+			id = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis)
+			{	// identifier!(template-argument-list)
+			TemplateInstance tempinst;
+
+			tempinst = new TemplateInstance(loc, id);
+			nextToken();
+			if (token.value == TOK.TOKlparen)
+				// ident!(template_arguments)
+				tempinst.tiargs = parseTemplateArgumentList();
+			else
+				// ident!template_argument
+				tempinst.tiargs = parseTemplateArgument();
+			e = new ScopeExp(loc, tempinst);
+			}
+			else
+			e = new IdentifierExp(loc, id);
+			break;
+
+		case TOK.TOKdollar:
+			if (!inBrackets)
+			error("'$' is valid only inside [] of index or slice");
+			e = new DollarExp(loc);
+			nextToken();
+			break;
+
+		case TOK.TOKdot:
+			// Signal global scope '.' operator with "" identifier
+			e = new IdentifierExp(loc, Id.empty);
+			break;
+
+		case TOK.TOKthis:
+			e = new ThisExp(loc);
+			nextToken();
+			break;
+
+		case TOK.TOKsuper:
+			e = new SuperExp(loc);
+			nextToken();
+			break;
+
+		case TOK.TOKint32v:
+			e = new IntegerExp(loc, token.int32value, Type.tint32);
+			nextToken();
+			break;
+
+		case TOK.TOKuns32v:
+			e = new IntegerExp(loc, token.uns32value, Type.tuns32);
+			nextToken();
+			break;
+
+		case TOK.TOKint64v:
+			e = new IntegerExp(loc, token.int64value, Type.tint64);
+			nextToken();
+			break;
+
+		case TOK.TOKuns64v:
+			e = new IntegerExp(loc, token.uns64value, Type.tuns64);
+			nextToken();
+			break;
+
+		case TOK.TOKfloat32v:
+			e = new RealExp(loc, token.float80value, Type.tfloat32);
+			nextToken();
+			break;
+
+		case TOK.TOKfloat64v:
+			e = new RealExp(loc, token.float80value, Type.tfloat64);
+			nextToken();
+			break;
+
+		case TOK.TOKfloat80v:
+			e = new RealExp(loc, token.float80value, Type.tfloat80);
+			nextToken();
+			break;
+
+		case TOK.TOKimaginary32v:
+			e = new RealExp(loc, token.float80value, Type.timaginary32);
+			nextToken();
+			break;
+
+		case TOK.TOKimaginary64v:
+			e = new RealExp(loc, token.float80value, Type.timaginary64);
+			nextToken();
+			break;
+
+		case TOK.TOKimaginary80v:
+			e = new RealExp(loc, token.float80value, Type.timaginary80);
+			nextToken();
+			break;
+
+		case TOK.TOKnull:
+			e = new NullExp(loc);
+			nextToken();
+			break;
+
+version (DMDV2) {
+		case TOK.TOKfile:
+		{
+			string s = loc.filename ? loc.filename : mod.ident.toChars();
+			e = new StringExp(loc, s, 0);
+			nextToken();
+			break;
+		}
+
+		case TOK.TOKline:
+			e = new IntegerExp(loc, loc.linnum, Type.tint32);
+			nextToken();
+			break;
+}
+
+		case TOK.TOKtrue:
+			e = new IntegerExp(loc, 1, Type.tbool);
+			nextToken();
+			break;
+
+		case TOK.TOKfalse:
+			e = new IntegerExp(loc, 0, Type.tbool);
+			nextToken();
+			break;
+
+		case TOK.TOKcharv:
+			e = new IntegerExp(loc, token.uns32value, Type.tchar);
+			nextToken();
+			break;
+
+		case TOK.TOKwcharv:
+			e = new IntegerExp(loc, token.uns32value, Type.twchar);
+			nextToken();
+			break;
+
+		case TOK.TOKdcharv:
+			e = new IntegerExp(loc, token.uns32value, Type.tdchar);
+			nextToken();
+			break;
+
+		case TOK.TOKstring:
+		{  
+			const(char)* s;
+			uint len;
+			ubyte postfix;
+
+			// cat adjacent strings
+			s = token.ustring;
+			len = token.len;
+			postfix = token.postfix;
+			while (1)
+			{
+				nextToken();
+				if (token.value == TOK.TOKstring)
+				{   uint len1;
+					uint len2;
+					char* s2;
+
+					if (token.postfix)
+					{	if (token.postfix != postfix)
+						error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+					postfix = token.postfix;
+					}
+
+					len1 = len;
+					len2 = token.len;
+					len = len1 + len2;
+					s2 = cast(char*)malloc((len + 1) * ubyte.sizeof);
+					memcpy(s2, s, len1 * ubyte.sizeof);
+					memcpy(s2 + len1, token.ustring, (len2 + 1) * ubyte.sizeof);
+					s = s2;
+				}
+				else
+					break;
+			}
+			e = new StringExp(loc, assumeUnique(s[0..len]), postfix);
+			break;
+		}
+
+		case TOK.TOKvoid:	 t = Type.tvoid;  goto LabelX;
+		case TOK.TOKint8:	 t = Type.tint8;  goto LabelX;
+		case TOK.TOKuns8:	 t = Type.tuns8;  goto LabelX;
+		case TOK.TOKint16:	 t = Type.tint16; goto LabelX;
+		case TOK.TOKuns16:	 t = Type.tuns16; goto LabelX;
+		case TOK.TOKint32:	 t = Type.tint32; goto LabelX;
+		case TOK.TOKuns32:	 t = Type.tuns32; goto LabelX;
+		case TOK.TOKint64:	 t = Type.tint64; goto LabelX;
+		case TOK.TOKuns64:	 t = Type.tuns64; goto LabelX;
+		case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX;
+		case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX;
+		case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX;
+		case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX;
+		case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX;
+		case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX;
+		case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX;
+		case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX;
+		case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX;
+		case TOK.TOKbit:	 t = Type.tbit;     goto LabelX;
+		case TOK.TOKbool:	 t = Type.tbool;    goto LabelX;
+		case TOK.TOKchar:	 t = Type.tchar;    goto LabelX;
+		case TOK.TOKwchar:	 t = Type.twchar; goto LabelX;
+		case TOK.TOKdchar:	 t = Type.tdchar; goto LabelX;
+		LabelX:
+			nextToken();
+		L1:
+			check(TOK.TOKdot, t.toChars());
+			if (token.value != TOK.TOKidentifier)
+			{   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t.toChars());
+			goto Lerr;
+			}
+			e = typeDotIdExp(loc, t, token.ident);
+			nextToken();
+			break;
+
+		case TOK.TOKtypeof:
+		{
+			t = parseTypeof();
+			e = new TypeExp(loc, t);
+			break;
+		}
+
+		case TOK.TOKtypeid:
+		{   Type tt;
+
+			nextToken();
+			check(TOK.TOKlparen, "typeid");
+			tt = parseType();		// ( type )
+			check(TOK.TOKrparen);
+			e = new TypeidExp(loc, tt);
+			break;
+		}
+
+version (DMDV2) {
+		case TOK.TOKtraits:
+		{   /* __traits(identifier, args...)
+			 */
+			Identifier ident;
+			Objects args = null;
+
+			nextToken();
+			check(TOK.TOKlparen);
+			if (token.value != TOK.TOKidentifier)
+			{   error("__traits(identifier, args...) expected");
+			goto Lerr;
+			}
+			ident = token.ident;
+			nextToken();
+			if (token.value == TOK.TOKcomma)
+			args = parseTemplateArgumentList2();	// __traits(identifier, args...)
+			else
+			check(TOK.TOKrparen);		// __traits(identifier)
+
+			e = new TraitsExp(loc, ident, args);
+			break;
+		}
+}
+
+		case TOK.TOKis:
+		{   Type targ;
+			Identifier ident = null;
+			Type tspec = null;
+			TOK tok = TOK.TOKreserved;
+			TOK tok2 = TOK.TOKreserved;
+			TemplateParameters tpl = null;
+			Loc loc2 = this.loc;
+
+			nextToken();
+			if (token.value == TOK.TOKlparen)
+			{
+				nextToken();
+				targ = parseType(&ident);
+				if (token.value == TOK.TOKcolon || token.value == TOK.TOKequal)
+				{
+					tok = token.value;
+					nextToken();
+					if (tok == TOK.TOKequal &&
+					(token.value == TOK.TOKtypedef ||
+					 token.value == TOK.TOKstruct ||
+					 token.value == TOK.TOKunion ||
+					 token.value == TOK.TOKclass ||
+					 token.value == TOK.TOKsuper ||
+					 token.value == TOK.TOKenum ||
+					 token.value == TOK.TOKinterface ||
+	///version (DMDV2) {
+					 token.value == TOK.TOKconst && peek(&token).value == TOK.TOKrparen ||
+					 token.value == TOK.TOKinvariant && peek(&token).value == TOK.TOKrparen ||
+					 token.value == TOK.TOKimmutable && peek(&token).value == TOK.TOKrparen ||
+					 token.value == TOK.TOKshared && peek(&token).value == TOK.TOKrparen ||
+	///}
+					 token.value == TOK.TOKfunction ||
+					 token.value == TOK.TOKdelegate ||
+					 token.value == TOK.TOKreturn))
+					{
+					tok2 = token.value;
+					nextToken();
+					}
+					else
+					{
+					tspec = parseType();
+					}
+				}
+				if (ident && tspec)
+				{
+					if (token.value == TOK.TOKcomma)
+					tpl = parseTemplateParameterList(1);
+					else
+					{	tpl = new TemplateParameters();
+					check(TOK.TOKrparen);
+					}
+					TemplateParameter tp = new TemplateTypeParameter(loc2, ident, null, null);
+					tpl.insert(0, cast(void*)tp);
+				}
+				else
+					check(TOK.TOKrparen);
+			}
+			else
+			{   error("(type identifier : specialization) expected following is");
+			goto Lerr;
+			}
+			e = new IsExp(loc2, targ, ident, tok, tspec, tok2, tpl);
+			break;
+		}
+
+		case TOK.TOKassert:
+		{   
+			Expression msg = null;
+
+			nextToken();
+			check(TOK.TOKlparen, "assert");
+			e = parseAssignExp();
+			if (token.value == TOK.TOKcomma)
+			{	nextToken();
+			msg = parseAssignExp();
+			}
+			check(TOK.TOKrparen);
+			e = new AssertExp(loc, e, msg);
+			break;
+		}
+
+		case TOK.TOKmixin:
+		{
+			nextToken();
+			check(TOK.TOKlparen, "mixin");
+			e = parseAssignExp();
+			check(TOK.TOKrparen);
+			e = new CompileExp(loc, e);
+			break;
+		}
+
+		case TOK.TOKimport:
+		{
+			nextToken();
+			check(TOK.TOKlparen, "import");
+			e = parseAssignExp();
+			check(TOK.TOKrparen);
+			e = new FileExp(loc, e);
+			break;
+		}
+
+		case TOK.TOKlparen:
+			if (peekPastParen(&token).value == TOK.TOKlcurly)
+			{	// (arguments) { statements... }
+			save = TOK.TOKdelegate;
+			goto case_delegate;
+			}
+			// ( expression )
+			nextToken();
+			e = parseExpression();
+			check(loc, TOK.TOKrparen);
+			break;
+
+		case TOK.TOKlbracket:
+		{   /* Parse array literals and associative array literals:
+			 *	[ value, value, value ... ]
+			 *	[ key:value, key:value, key:value ... ]
+			 */
+			Expressions values = new Expressions();
+			Expressions keys = null;
+
+			nextToken();
+			if (token.value != TOK.TOKrbracket)
+			{
+			while (token.value != TOK.TOKeof)
+			{
+				Expression e2 = parseAssignExp();
+				if (token.value == TOK.TOKcolon && (keys || values.dim == 0))
+				{	
+					nextToken();
+					if (!keys)
+						keys = new Expressions();
+					keys.push(cast(void*)e2);
+					e2 = parseAssignExp();
+				}
+				else if (keys)
+				{	
+					error("'key:value' expected for associative array literal");
+					delete keys;
+					keys = null;
+				}
+				values.push(cast(void*)e2);
+				if (token.value == TOK.TOKrbracket)
+					break;
+				check(TOK.TOKcomma);
+			}
+			}
+			check(TOK.TOKrbracket);
+
+			if (keys)
+				e = new AssocArrayLiteralExp(loc, keys, values);
+			else
+				e = new ArrayLiteralExp(loc, values);
+			break;
+		}
+
+		case TOK.TOKlcurly:
+			// { statements... }
+			save = TOK.TOKdelegate;
+			goto case_delegate;
+
+		case TOK.TOKfunction:
+		case TOK.TOKdelegate:
+			save = token.value;
+			nextToken();
+		case_delegate:
+		{
+			/* function type(parameters) { body } pure nothrow
+			 * delegate type(parameters) { body } pure nothrow
+			 * (parameters) { body }
+			 * { body }
+			 */
+			Arguments arguments;
+			int varargs;
+			FuncLiteralDeclaration fd;
+			Type tt;
+			bool isnothrow = false;
+			bool ispure = false;
+
+			if (token.value == TOK.TOKlcurly)
+			{
+			tt = null;
+			varargs = 0;
+			arguments = new Arguments();
+			}
+			else
+			{
+			if (token.value == TOK.TOKlparen)
+				tt = null;
+			else
+			{
+				tt = parseBasicType();
+				tt = parseBasicType2(tt);	// function return type
+			}
+			arguments = parseParameters(&varargs);
+			while (1)
+			{
+				if (token.value == TOK.TOKpure)
+				ispure = true;
+				else if (token.value == TOK.TOKnothrow)
+				isnothrow = true;
+				else
+				break;
+				nextToken();
+			}
+			}
+
+			TypeFunction tf = new TypeFunction(arguments, tt, varargs, linkage);
+			tf.ispure = ispure;
+			tf.isnothrow = isnothrow;
+			fd = new FuncLiteralDeclaration(loc, Loc(0), tf, save, null);
+			parseContracts(fd);
+			e = new FuncExp(loc, fd);
+			break;
+		}
+
+		default:
+			error("expression expected, not '%s'", token.toChars());
+		Lerr:
+			// Anything for e, as long as it's not null
+			e = new IntegerExp(loc, 0, Type.tint32);
+			nextToken();
+			break;
+		}
+		return e;
+	}
+	
+    Expression parseUnaryExp()
+	{
+		Expression e;
+		Loc loc = this.loc;
+
+		switch (token.value)
+		{
+		case TOK.TOKand:
+			nextToken();
+			e = parseUnaryExp();
+			e = new AddrExp(loc, e);
+			break;
+
+		case TOK.TOKplusplus:
+			nextToken();
+			e = parseUnaryExp();
+			e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32));
+			break;
+
+		case TOK.TOKminusminus:
+			nextToken();
+			e = parseUnaryExp();
+			e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32));
+			break;
+
+		case TOK.TOKmul:
+			nextToken();
+			e = parseUnaryExp();
+			e = new PtrExp(loc, e);
+			break;
+
+		case TOK.TOKmin:
+			nextToken();
+			e = parseUnaryExp();
+			e = new NegExp(loc, e);
+			break;
+
+		case TOK.TOKadd:
+			nextToken();
+			e = parseUnaryExp();
+			e = new UAddExp(loc, e);
+			break;
+
+		case TOK.TOKnot:
+			nextToken();
+			e = parseUnaryExp();
+			e = new NotExp(loc, e);
+			break;
+
+		case TOK.TOKtilde:
+			nextToken();
+			e = parseUnaryExp();
+			e = new ComExp(loc, e);
+			break;
+
+		case TOK.TOKdelete:
+			nextToken();
+			e = parseUnaryExp();
+			e = new DeleteExp(loc, e);
+			break;
+
+		case TOK.TOKnew:
+			e = parseNewExp(null);
+			break;
+
+		case TOK.TOKcast:				// cast(type) expression
+		{
+			nextToken();
+			check(TOK.TOKlparen);
+			/* Look for cast(), cast(const), cast(immutable),
+			 * cast(shared), cast(shared const)
+			 */
+			MOD m;
+			if (token.value == TOK.TOKrparen)
+			{
+			m = MOD.MODundefined;
+			goto Lmod1;
+			}
+			else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKrparen)
+			{
+			m = MOD.MODconst;
+			goto Lmod2;
+			}
+			else if ((token.value == TOK.TOKimmutable || token.value == TOK.TOKinvariant) && peekNext() == TOK.TOKrparen)
+			{
+			m = MOD.MODinvariant;
+			goto Lmod2;
+			}
+			else if (token.value == TOK.TOKshared && peekNext() == TOK.TOKrparen)
+			{
+			m = MOD.MODshared;
+			goto Lmod2;
+			}
+			else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() == TOK.TOKrparen ||
+				 token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() == TOK.TOKrparen)
+			{
+			m = MOD.MODshared | MOD.MODconst;
+			nextToken();
+			  Lmod2:
+			nextToken();
+			  Lmod1:
+			nextToken();
+			e = parseUnaryExp();
+			e = new CastExp(loc, e, m);
+			}
+			else
+			{
+			Type t = parseType();		// ( type )
+			check(TOK.TOKrparen);
+			e = parseUnaryExp();
+			e = new CastExp(loc, e, t);
+			}
+			break;
+		}
+
+		case TOK.TOKlparen:
+		{   Token *tk;
+
+			tk = peek(&token);
+version (CCASTSYNTAX) {
+			// If cast
+			if (isDeclaration(tk, 0, TOK.TOKrparen, &tk))
+			{
+				tk = peek(tk);		// skip over right parenthesis
+				switch (tk.value)
+				{
+					case TOK.TOKnot:
+						tk = peek(tk);
+						if (tk.value == TOK.TOKis)	// !is
+							break;
+					case TOK.TOKdot:
+					case TOK.TOKplusplus:
+					case TOK.TOKminusminus:
+					case TOK.TOKdelete:
+					case TOK.TOKnew:
+					case TOK.TOKlparen:
+					case TOK.TOKidentifier:
+					case TOK.TOKthis:
+					case TOK.TOKsuper:
+					case TOK.TOKint32v:
+					case TOK.TOKuns32v:
+					case TOK.TOKint64v:
+					case TOK.TOKuns64v:
+					case TOK.TOKfloat32v:
+					case TOK.TOKfloat64v:
+					case TOK.TOKfloat80v:
+					case TOK.TOKimaginary32v:
+					case TOK.TOKimaginary64v:
+					case TOK.TOKimaginary80v:
+					case TOK.TOKnull:
+					case TOK.TOKtrue:
+					case TOK.TOKfalse:
+					case TOK.TOKcharv:
+					case TOK.TOKwcharv:
+					case TOK.TOKdcharv:
+					case TOK.TOKstring:
+static if (false) {
+					case TOK.TOKtilde:
+					case TOK.TOKand:
+					case TOK.TOKmul:
+					case TOK.TOKmin:
+					case TOK.TOKadd:
+}
+					case TOK.TOKfunction:
+					case TOK.TOKdelegate:
+					case TOK.TOKtypeof:
+version (DMDV2) {
+					case TOK.TOKfile:
+					case TOK.TOKline:
+}
+					case TOK.TOKwchar: case TOK.TOKdchar:
+					case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
+					case TOK.TOKint8: case TOK.TOKuns8:
+					case TOK.TOKint16: case TOK.TOKuns16:
+					case TOK.TOKint32: case TOK.TOKuns32:
+					case TOK.TOKint64: case TOK.TOKuns64:
+					case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
+					case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
+					case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
+					case TOK.TOKvoid:		// (type)int.size
+					{	
+						// (type) una_exp
+						nextToken();
+						Type t = parseType();
+						check(TOK.TOKrparen);
+
+						// if .identifier
+						if (token.value == TOK.TOKdot)
+						{
+							nextToken();
+							if (token.value != TOK.TOKidentifier)
+							{   
+								error("Identifier expected following (type).");
+								return null;
+							}
+							e = typeDotIdExp(loc, t, token.ident);
+							nextToken();
+							e = parsePostExp(e);
+						}
+						else
+						{
+							e = parseUnaryExp();
+							e = new CastExp(loc, e, t);
+							error("C style cast illegal, use %s", e.toChars());
+						}
+						return e;
+					}
+					
+					default:
+						break;	///
+				}
+			}
+}
+			e = parsePrimaryExp();
+			e = parsePostExp(e);
+			break;
+		}
+		default:
+			e = parsePrimaryExp();
+			e = parsePostExp(e);
+			break;
+		}
+		assert(e);
+		return e;
+	}
+	
+    Expression parsePostExp(Expression e)
+	{
+		Loc loc;
+
+		while (1)
+		{
+		loc = this.loc;
+		switch (token.value)
+		{
+			case TOK.TOKdot:
+			nextToken();
+			if (token.value == TOK.TOKidentifier)
+			{   Identifier id = token.ident;
+
+				nextToken();
+				if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis)
+				{   // identifier!(template-argument-list)
+				TemplateInstance tempinst = new TemplateInstance(loc, id);
+				nextToken();
+				if (token.value == TOK.TOKlparen)
+					// ident!(template_arguments)
+					tempinst.tiargs = parseTemplateArgumentList();
+				else
+					// ident!template_argument
+					tempinst.tiargs = parseTemplateArgument();
+				e = new DotTemplateInstanceExp(loc, e, tempinst);
+				}
+				else
+				e = new DotIdExp(loc, e, id);
+				continue;
+			}
+			else if (token.value == TOK.TOKnew)
+			{
+				e = parseNewExp(e);
+				continue;
+			}
+			else
+				error("identifier expected following '.', not '%s'", token.toChars());
+			break;
+
+			case TOK.TOKplusplus:
+			e = new PostExp(TOK.TOKplusplus, loc, e);
+			break;
+
+			case TOK.TOKminusminus:
+			e = new PostExp(TOK.TOKminusminus, loc, e);
+			break;
+
+			case TOK.TOKlparen:
+			e = new CallExp(loc, e, parseArguments());
+			continue;
+
+			case TOK.TOKlbracket:
+			{	// array dereferences:
+			//	array[index]
+			//	array[]
+			//	array[lwr .. upr]
+			Expression index;
+			Expression upr;
+
+			inBrackets++;
+			nextToken();
+			if (token.value == TOK.TOKrbracket)
+			{   // array[]
+				e = new SliceExp(loc, e, null, null);
+				nextToken();
+			}
+			else
+			{
+				index = parseAssignExp();
+				if (token.value == TOK.TOKslice)
+				{	// array[lwr .. upr]
+				nextToken();
+				upr = parseAssignExp();
+				e = new SliceExp(loc, e, index, upr);
+				}
+				else
+				{	// array[index, i2, i3, i4, ...]
+				Expressions arguments = new Expressions();
+				arguments.push(cast(void*)index);
+				if (token.value == TOK.TOKcomma)
+				{
+					nextToken();
+					while (1)
+					{   Expression arg;
+
+					arg = parseAssignExp();
+					arguments.push(cast(void*)arg);
+					if (token.value == TOK.TOKrbracket)
+						break;
+					check(TOK.TOKcomma);
+					}
+				}
+				e = new ArrayExp(loc, e, arguments);
+				}
+				check(TOK.TOKrbracket);
+				inBrackets--;
+			}
+			continue;
+			}
+
+			default:
+			return e;
+		}
+		nextToken();
+		}
+		
+		assert(false);
+	}
+	
+    Expression parseMulExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseUnaryExp();
+		while (1)
+		{
+			switch (token.value)
+			{
+				case TOK.TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
+				case TOK.TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
+				case TOK.TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
+
+				default:
+				break;
+			}
+			break;
+		}
+		return e;
+	}
+	
+    Expression parseShiftExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseAddExp();
+		while (1)
+		{
+			switch (token.value)
+			{
+				case TOK.TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
+				case TOK.TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
+				case TOK.TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
+
+				default:
+				break;
+			}
+			break;
+		}
+		return e;
+	}
+	
+    Expression parseAddExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseMulExp();
+		while (1)
+		{
+			switch (token.value)
+			{
+				case TOK.TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
+				case TOK.TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
+				case TOK.TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
+
+				default:
+				break;
+			}
+			break;
+		}
+		return e;
+	}
+	
+    Expression parseRelExp()
+	{
+		assert(false);
+	}
+	
+    Expression parseEqualExp()
+	{
+		assert(false);
+	}
+	
+    Expression parseCmpExp()
+	{
+		Expression e;
+		Expression e2;
+		Token* t;
+		Loc loc = this.loc;
+
+		e = parseShiftExp();
+		TOK op = token.value;
+
+		switch (op)
+		{
+		case TOK.TOKequal:
+		case TOK.TOKnotequal:
+			nextToken();
+			e2 = parseShiftExp();
+			e = new EqualExp(op, loc, e, e2);
+			break;
+
+		case TOK.TOKis:
+			op = TOK.TOKidentity;
+			goto L1;
+
+		case TOK.TOKnot:
+			// Attempt to identify '!is'
+			t = peek(&token);
+			if (t.value != TOK.TOKis)
+			break;
+			nextToken();
+			op = TOK.TOKnotidentity;
+			goto L1;
+
+		L1:
+			nextToken();
+			e2 = parseShiftExp();
+			e = new IdentityExp(op, loc, e, e2);
+			break;
+
+		case TOK.TOKlt:
+		case TOK.TOKle:
+		case TOK.TOKgt:
+		case TOK.TOKge:
+		case TOK.TOKunord:
+		case TOK.TOKlg:
+		case TOK.TOKleg:
+		case TOK.TOKule:
+		case TOK.TOKul:
+		case TOK.TOKuge:
+		case TOK.TOKug:
+		case TOK.TOKue:
+			nextToken();
+			e2 = parseShiftExp();
+			e = new CmpExp(op, loc, e, e2);
+			break;
+
+		case TOK.TOKin:
+			nextToken();
+			e2 = parseShiftExp();
+			e = new InExp(loc, e, e2);
+			break;
+
+		default:
+			break;
+		}
+		return e;
+	}
+	
+    Expression parseAndExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		if (global.params.Dversion == 1)
+		{
+			e = parseEqualExp();
+			while (token.value == TOK.TOKand)
+			{
+				nextToken();
+				e2 = parseEqualExp();
+				e = new AndExp(loc,e,e2);
+				loc = this.loc;
+			}
+		}
+		else
+		{
+			e = parseCmpExp();
+			while (token.value == TOK.TOKand)
+			{
+				nextToken();
+				e2 = parseCmpExp();
+				e = new AndExp(loc,e,e2);
+				loc = this.loc;
+			}
+		}
+		return e;
+	}
+	
+    Expression parseXorExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseAndExp();
+		while (token.value == TOK.TOKxor)
+		{
+			nextToken();
+			e2 = parseAndExp();
+			e = new XorExp(loc, e, e2);
+		}
+
+		return e;
+	}
+
+    Expression parseOrExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseXorExp();
+		while (token.value == TOK.TOKor)
+		{
+			nextToken();
+			e2 = parseXorExp();
+			e = new OrExp(loc, e, e2);
+		}
+		return e;
+	}
+	
+    Expression parseAndAndExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseOrExp();
+		while (token.value == TOK.TOKandand)
+		{
+			nextToken();
+			e2 = parseOrExp();
+			e = new AndAndExp(loc, e, e2);
+		}
+		return e;
+	}
+	
+    Expression parseOrOrExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseAndAndExp();
+		while (token.value == TOK.TOKoror)
+		{
+			nextToken();
+			e2 = parseAndAndExp();
+			e = new OrOrExp(loc, e, e2);
+		}
+
+		return e;
+	}
+	
+    Expression parseCondExp()
+	{
+		Expression e;
+		Expression e1;
+		Expression e2;
+		Loc loc = this.loc;
+
+		e = parseOrOrExp();
+		if (token.value == TOK.TOKquestion)
+		{
+			nextToken();
+			e1 = parseExpression();
+			check(TOK.TOKcolon);
+			e2 = parseCondExp();
+			e = new CondExp(loc, e, e1, e2);
+		}
+		return e;
+	}
+	
+    Expression parseAssignExp()
+	{
+		Expression e;
+		Expression e2;
+		Loc loc;
+
+		e = parseCondExp();
+		while (1)
+		{
+			loc = this.loc;
+			switch (token.value)
+			{
+				case TOK.TOKassign:  nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
+				case TOK.TOKaddass:  nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
+				case TOK.TOKminass:  nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
+				case TOK.TOKmulass:  nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
+				case TOK.TOKdivass:  nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
+				case TOK.TOKmodass:  nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
+				case TOK.TOKandass:  nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
+				case TOK.TOKorass:   nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
+				case TOK.TOKxorass:  nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
+				case TOK.TOKshlass:  nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
+				case TOK.TOKshrass:  nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
+				case TOK.TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
+				case TOK.TOKcatass:  nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
+				
+				default:
+					break;
+			}
+			break;
+		}
+
+		return e;
+	}
+	
+	/*************************
+	 * Collect argument list.
+	 * Assume current token is ',', '(' or '['.
+	 */
+    Expressions parseArguments()
+	{
+		// function call
+		Expressions arguments = new Expressions();
+		Expression arg;
+		TOK endtok;
+		
+		if (token.value == TOK.TOKlbracket)
+			endtok = TOK.TOKrbracket;
+		else
+			endtok = TOK.TOKrparen;
+
+		{
+			nextToken();
+			if (token.value != endtok)
+			{
+				while (1)
+				{
+					arg = parseAssignExp();
+					arguments.push(cast(void*)arg);
+					if (token.value == endtok)
+						break;
+					check(TOK.TOKcomma);
+				}
+			}
+			check(endtok);
+		}
+		return arguments;
+	}
+
+    Expression parseNewExp(Expression thisexp)
+	{
+		Type t;
+		Expressions newargs;
+		Expressions arguments = null;
+		Expression e;
+		Loc loc = this.loc;
+
+		nextToken();
+		newargs = null;
+		if (token.value == TOKlparen)
+		{
+			newargs = parseArguments();
+		}
+
+		// An anonymous nested class starts with "class"
+		if (token.value == TOKclass)
+		{
+			nextToken();
+			if (token.value == TOKlparen)
+				arguments = parseArguments();
+
+			BaseClasses baseclasses = null;
+			if (token.value != TOKlcurly)
+				baseclasses = parseBaseClasses();
+
+			Identifier id = null;
+			ClassDeclaration cd = new ClassDeclaration(loc, id, baseclasses);
+
+			if (token.value != TOKlcurly)
+			{   
+				error("{ members } expected for anonymous class");
+				cd.members = null;
+			}
+			else
+			{
+				nextToken();
+				Array decl = parseDeclDefs(0);
+				if (token.value != TOKrcurly)
+					error("class member expected");
+				nextToken();
+				cd.members = decl;
+			}
+
+			e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+
+			return e;
+		}
+
+		t = parseBasicType();
+		t = parseBasicType2(t);
+		if (t.ty == Taarray)
+		{	
+			TypeAArray taa = cast(TypeAArray)t;
+			Type index = taa.index;
+
+			Expression e2 = index.toExpression();
+			if (e2)
+			{   
+				arguments = new Expressions();
+				arguments.push(cast(void*)e2);
+				t = new TypeDArray(taa.next);
+			}
+			else
+			{
+				error("need size of rightmost array, not type %s", index.toChars());
+				return new NullExp(loc);
+			}
+		}
+		else if (t.ty == Tsarray)
+		{
+			TypeSArray tsa = cast(TypeSArray)t;
+			Expression ee = tsa.dim;
+
+			arguments = new Expressions();
+			arguments.push(cast(void*)ee);
+			t = new TypeDArray(tsa.next);
+		}
+		else if (token.value == TOKlparen)
+		{
+			arguments = parseArguments();
+		}
+
+		e = new NewExp(loc, thisexp, newargs, t, arguments);
+		return e;
+	}
+	
+    void addComment(Dsymbol s, ubyte* blockComment)
+	{
+		s.addComment(combineComments(blockComment, token.lineComment));
+		token.lineComment = null;
+	}
+}
\ No newline at end of file