diff --git a/astprinter.d b/astprinter.d
new file mode 100644
index 0000000..4d4a2fa
--- /dev/null
+++ b/astprinter.d
@@ -0,0 +1,72 @@
+import std.d.lexer;
+import std.d.ast;
+import std.stdio;
+
+class XMLPrinter : ASTVisitor
+{
+	override void visit(Module mod)
+	{
+		output.writeln("<module>");
+		mod.accept(this);
+		output.writeln("</module>");
+	}
+
+	override void visit(ModuleDeclaration modDec)
+	{
+		output.writeln("<moduleDeclaration>");
+		modDec.accept(this);
+		output.writeln("</moduleDeclaration>");
+	}
+
+	override void visit(IdentifierChain chain)
+	{
+		output.writeln("<identifierChain>");
+		foreach (ident; chain.identifiers)
+		{
+			output.writeln("<identifier>", ident.value, "</identifier>");
+		}
+		output.writeln("</identifierChain>");
+	}
+
+	override void visit(ClassDeclaration classDec)
+	{
+		output.writeln("<classDeclaration line=\"", classDec.name.line, "\">");
+		output.writeln("<name>", classDec.name.value, "</name>");
+		output.writeln("</classDeclaration>");
+	}
+
+	override void visit(StructDeclaration structDec)
+	{
+		output.writeln("<structDeclaration line=\"", structDec.name.line, "\">");
+		output.writeln("<name>", structDec.name.value, "</name>");
+		output.writeln("</structDeclaration>");
+	}
+
+	override void visit(FunctionDeclaration functionDec)
+	{
+		output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">");
+		output.writeln("<name>", functionDec.name.value, "</name>");
+		output.writeln("</functionDeclaration>");
+	}
+
+	override void visit(EnumDeclaration enumDec)
+	{
+		output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">");
+		if (enumDec.name.type == TokenType.identifier)
+			output.writeln("<name>", enumDec.name.value, "</name>");
+		enumDec.accept(this);
+		output.writeln("</enumDeclaration>");
+	}
+
+	override void visit(EnumMember enumMem)
+	{
+		output.writeln("<enumMember line=\"", enumMem.name.line, "\">");
+		output.writeln("<name>", enumMem.name.value, "</name>");
+		enumMem.accept(this);
+		output.writeln("</enumMember>");
+	}
+
+	alias ASTVisitor.visit visit;
+
+	File output;
+}
diff --git a/main.d b/main.d
index b431c3c..99a573c 100755
--- a/main.d
+++ b/main.d
@@ -21,6 +21,7 @@ import std.d.parser;
 import highlighter;
 import stats;
 import ctags;
+import astprinter;
 
 int main(string[] args)
 {
@@ -28,19 +29,20 @@ int main(string[] args)
 	bool sloc;
 	bool highlight;
 	bool ctags;
-    bool json;
 	bool recursive;
 	bool format;
 	bool help;
 	bool tokenCount;
 	bool syntaxCheck;
+	bool ast;
 
 	try
 	{
 		getopt(args, "I", &importDirs, "sloc|l", &sloc,
-			"json|j", &json, "highlight", &highlight,
+			"highlight", &highlight,
 			"ctags|c", &ctags, "recursive|r|R", &recursive, "help|h", &help,
-			"tokenCount", &tokenCount, "syntaxCheck|s", &syntaxCheck);
+			"tokenCount", &tokenCount, "syntaxCheck|s", &syntaxCheck,
+			"ast|xml", &ast);
 	}
 	catch (Exception e)
 	{
@@ -53,8 +55,8 @@ int main(string[] args)
 		return 0;
 	}
 
-	auto optionCount = count!"a"([sloc, highlight, ctags, json, tokenCount,
-		syntaxCheck]);
+	auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
+		syntaxCheck, ast]);
 	if (optionCount > 1)
 	{
 		stderr.writeln("Too many options specified");
@@ -104,6 +106,13 @@ int main(string[] args)
 		{
 			parseModule(tokens.array(), args[1]);
 		}
+		else if (ast)
+		{
+			auto mod = parseModule(tokens.array(), args[1]);
+			auto printer = new XMLPrinter;
+			printer.output = stdout;
+			printer.visit(mod);
+		}
 	}
 
 	return 0;
@@ -123,10 +132,6 @@ options:
         count the number of logical lines of code in the given
         source files. If no files are specified, a file is read from stdin.
 
-    --json | -j [sourceFile]
-        Generate a JSON summary of the given source file. If no file is
-        specifed, the file is read from stdin.
-
     --highlight [sourceFile] - Syntax-highlight the given source file. The
         resulting HTML will be written to standard output.
 
@@ -148,6 +153,9 @@ options:
         ctags information requires a filename, so stdin cannot be used in place
         of a filename.
 
+	--ast | --xml sourceFile
+		Generates an XML representation of the source files abstract syntax tree
+
     --recursive | -R | -r directory
         When used with --ctags, dscanner will produce ctags output for all .d
         and .di files contained within the given directory and its
diff --git a/std/d/ast.d b/std/d/ast.d
index b92cf81..881674e 100755
--- a/std/d/ast.d
+++ b/std/d/ast.d
@@ -233,6 +233,14 @@ interface ASTNode
 
 immutable string DEFAULT_ACCEPT = q{void accept(ASTVisitor visitor) {}};
 
+template visitIfNotNull(fields ...)
+{
+	static if (fields.length > 1)
+		immutable visitIfNotNull = visitIfNotNull!(fields[0]) ~ visitIfNotNull!(fields[1..$]);
+	else
+		immutable visitIfNotNull = "if (" ~ fields[0].stringof ~ " !is null) visitor.visit(" ~ fields[0].stringof ~ ");";
+}
+
 abstract class ExpressionNode : ASTNode {}
 
 mixin template BinaryExpressionBody()
@@ -254,7 +262,14 @@ public:
 class AliasDeclaration : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(type, declarator));
+		foreach (initializer; initializers)
+		{
+			if (initializers !is null) visitor.visit(initializer);
+		}
+	}
     /** */ Type type;
     /** */ Declarator declarator;
     /** */ AliasInitializer[] initializers;
@@ -264,7 +279,11 @@ public:
 class AliasInitializer : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		if (type !is null) visitor.visit(type);
+	}
+
     /** */ Token identifier;
     /** */ Type type;
 }
@@ -305,7 +324,14 @@ public:
 class ArgumentList : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		foreach (item; items)
+		{
+			if (item !is null)
+				visitor.visit(item);
+		}
+	}
     /** */ AssignExpression[] items;
 }
 
@@ -313,7 +339,11 @@ public:
 class Arguments : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		if (argumentList !is null)
+			visitor.visit(argumentList);
+	}
     /** */ ArgumentList argumentList;
 }
 
@@ -321,7 +351,13 @@ public:
 class ArrayInitializer : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		foreach(init; arrayMemberInitializations)
+		{
+			if (init !is null) visitor.visit(init);
+		}
+	}
     /** */ ArrayMemberInitialization[] arrayMemberInitializations;
 }
 
@@ -784,30 +820,16 @@ public:
 
     override void accept(ASTVisitor visitor)
     {
-        if (importDeclaration !is null) visitor.visit(importDeclaration);
-        if (functionDeclaration !is null) visitor.visit(functionDeclaration);
-        if (variableDeclaration !is null) visitor.visit(variableDeclaration);
-        if (aliasThisDeclaration !is null) visitor.visit(aliasThisDeclaration);
-        if (structDeclaration !is null) visitor.visit(structDeclaration);
-        if (classDeclaration !is null) visitor.visit(classDeclaration);
-        if (interfaceDeclaration !is null) visitor.visit(interfaceDeclaration);
-        if (unionDeclaration !is null) visitor.visit(unionDeclaration);
-        if (enumDeclaration !is null) visitor.visit(enumDeclaration);
-        if (aliasDeclaration !is null) visitor.visit(aliasDeclaration);
-        if (mixinDeclaration !is null) visitor.visit(mixinDeclaration);
-        if (mixinTemplateDeclaration !is null) visitor.visit(mixinTemplateDeclaration);
-        if (unittest_ !is null) visitor.visit(unittest_);
-        if (staticAssertDeclaration !is null) visitor.visit(staticAssertDeclaration);
-        if (templateDeclaration !is null) visitor.visit(templateDeclaration);
-        if (constructor !is null) visitor.visit(constructor);
-        if (destructor !is null) visitor.visit(destructor);
-        if (staticConstructor !is null) visitor.visit(staticConstructor);
-        if (staticDestructor !is null) visitor.visit(staticDestructor);
-        if (sharedStaticDestructor !is null) visitor.visit(sharedStaticDestructor);
-        if (sharedStaticConstructor !is null) visitor.visit(sharedStaticConstructor);
-        if (conditionalDeclaration !is null) visitor.visit(conditionalDeclaration);
-        if (pragmaDeclaration !is null) visitor.visit(pragmaDeclaration);
-        if (versionSpecification !is null) visitor.visit(versionSpecification);
+
+		mixin(visitIfNotNull!(importDeclaration, functionDeclaration,
+			variableDeclaration, aliasThisDeclaration, structDeclaration,
+			classDeclaration, interfaceDeclaration, unionDeclaration,
+			enumDeclaration, aliasDeclaration, mixinDeclaration,
+			mixinTemplateDeclaration, unittest_, staticAssertDeclaration,
+			templateDeclaration, constructor,
+			destructor, staticConstructor, staticDestructor,
+			sharedStaticDestructor, sharedStaticConstructor,
+			conditionalDeclaration, pragmaDeclaration, versionSpecification));
     }
 
     /** */ Attribute[] attributes;
@@ -873,7 +895,12 @@ public:
 class Declarator : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+
+	override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(initializer));
+	}
+
     /** */ Token name;
     /** */ Initializer initializer;
 }
@@ -931,7 +958,13 @@ public:
 class EnumBody : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		foreach (member; enumMembers)
+		{
+			if (member !is null) visitor.visit(member);
+		}
+	}
     /** */ EnumMember[] enumMembers;
 }
 
@@ -939,7 +972,10 @@ public:
 class EnumDeclaration : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(type, enumBody));
+	}
     /** */ Token name;
     /** */ Type type;
     /** */ EnumBody enumBody;
@@ -949,8 +985,11 @@ public:
 class EnumMember : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
-    /** */ Token identifier;
+    override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(type, assignExpression));
+	}
+    /** */ Token name;
     /** */ Type type;
     /** */ AssignExpression assignExpression;
 }
@@ -1416,7 +1455,10 @@ public:
 class ModuleDeclaration : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		if (moduleName !is null) visitor.visit(moduleName);
+	}
     /** */ IdentifierChain moduleName;
 }
 
@@ -2196,7 +2238,11 @@ public:
 class WhileStatement : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+	override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
+	}
+
     /** */ Expression expression;
     /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
 }
@@ -2205,7 +2251,11 @@ public:
 class WithStatement : ASTNode
 {
 public:
-    mixin(DEFAULT_ACCEPT);
+    override void accept(ASTVisitor visitor)
+	{
+		mixin(visitIfNotNull!(expression, statementNoCaseNoDefault));
+	}
+
     /** */ Expression expression;
     /** */ StatementNoCaseNoDefault statementNoCaseNoDefault;
 }
diff --git a/std/d/parser.d b/std/d/parser.d
index 7d0157c..39b885e 100755
--- a/std/d/parser.d
+++ b/std/d/parser.d
@@ -2002,6 +2002,8 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
         if (expect(TokenType.enum_) is null) return null;
         if (currentIs(TokenType.identifier))
             node.name = advance();
+		else
+			node.name.line = tokens[index - 1].line; // preserve line number if anonymous
         if (currentIs(TokenType.colon))
         {
             advance();
@@ -2026,10 +2028,10 @@ class ClassFour(A, B) if (someTest()) : Super {}}c;
         if (currentIs(TokenType.identifier))
         {
             if (peekIsOneOf(TokenType.comma, TokenType.rBrace))
-                node.identifier = advance();
+                node.name = advance();
             else if (peekIs(TokenType.assign))
             {
-                node.identifier = advance();
+                node.name = advance();
                 goto assign;
             }
             else