diff options
-rw-r--r-- | AST/StmtDumper.cpp | 562 | ||||
-rw-r--r-- | AST/StmtPrinter.cpp | 9 | ||||
-rw-r--r-- | AST/Type.cpp | 2 | ||||
-rw-r--r-- | Driver/ASTStreamers.cpp | 54 | ||||
-rw-r--r-- | Driver/ASTStreamers.h | 3 | ||||
-rw-r--r-- | Driver/clang.cpp | 6 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 4 | ||||
-rw-r--r-- | include/clang/AST/Stmt.h | 18 |
8 files changed, 638 insertions, 20 deletions
diff --git a/AST/StmtDumper.cpp b/AST/StmtDumper.cpp new file mode 100644 index 0000000000..ebff1541ca --- /dev/null +++ b/AST/StmtDumper.cpp @@ -0,0 +1,562 @@ +//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chris Lattner and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// AST in a form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Lex/IdentifierTable.h" +#include "llvm/Support/Compiler.h" +#include <cstdio> +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtDumper Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor { + FILE *F; + unsigned IndentLevel; + + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump + /// the first few levels of an AST. This keeps track of how many ast levels + /// are left. + unsigned MaxDepth; + public: + StmtDumper(FILE *f, unsigned maxDepth) + : F(f), IndentLevel(0), MaxDepth(maxDepth) {} + + void DumpSubTree(Stmt *S, int SubIndent = 1) { + // Prune the recursion if not using dump all. + if (MaxDepth == 0) return; + + IndentLevel += SubIndent; + if (S) { + S->visit(*this); + } else { + Indent(); + fprintf(F, "<<<NULL>>>\n"); + } + IndentLevel -= SubIndent; + } + + void PrintRawDecl(Decl *D); + + void Indent() const { + for (int i = 0, e = IndentLevel; i < e; ++i) + fprintf(F, " "); + } + + void DumpStmt(const Stmt *Node) const { + Indent(); + fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); + } + + void DumpExpr(Expr *Node) const { + DumpStmt(Node); + // TODO: DUMP TYPE + } + + virtual void VisitStmt(Stmt *Node); +#define STMT(N, CLASS, PARENT) \ + virtual void Visit##CLASS(CLASS *Node); +#include "clang/AST/StmtNodes.def" + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitStmt(Stmt *Node) { + Indent(); + fprintf(F, "<<unknown stmt type>>\n"); +} + +void StmtDumper::PrintRawDecl(Decl *D) { +#if 0 + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { + OS << "typedef " << localType->getUnderlyingType().getAsString(); + OS << " " << localType->getName(); + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: OS << "extern "; break; + case VarDecl::Static: OS << "static "; break; + case VarDecl::Auto: OS << "auto "; break; + case VarDecl::Register: OS << "register "; break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + OS << Name; + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getInit()) { + OS << " = "; + DumpExpr(V->getInit()); + } + } + } else { + // FIXME: "struct x;" + assert(0 && "Unexpected decl"); + } +#endif +} + + +void StmtDumper::VisitNullStmt(NullStmt *Node) { + DumpStmt(Node); + fprintf(F, ")"); +} + +void StmtDumper::VisitDeclStmt(DeclStmt *Node) { + DumpStmt(Node); + // FIXME: implement this better :) + fprintf(F, ")"); +#if 0 + for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + Indent(); + PrintRawDecl(D); + OS << ";\n"; + } +#endif +} + +void StmtDumper::VisitCompoundStmt(CompoundStmt *Node) { + DumpStmt(Node); + if (!Node->body_empty()) fprintf(F, "\n"); + + for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); + I != E; ) { + DumpSubTree(*I); + ++I; + if (I != E) + fprintf(F, "\n"); + } + fprintf(F, ")"); +} + +void StmtDumper::VisitCaseStmt(CaseStmt *Node) { +#if 0 + Indent(-1) << "case "; + DumpExpr(Node->getLHS()); + if (Node->getRHS()) { + OS << " ... "; + DumpExpr(Node->getRHS()); + } + OS << ":\n"; + + DumpSubTree(Node->getSubStmt(), 0); +#endif +} + +void StmtDumper::VisitDefaultStmt(DefaultStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getSubStmt()); + fprintf(F, ")"); +} + +void StmtDumper::VisitLabelStmt(LabelStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s'\n", Node->getName()); + DumpSubTree(Node->getSubStmt()); + fprintf(F, "\n"); +} + +void StmtDumper::VisitIfStmt(IfStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, "\n"); + DumpSubTree(Node->getThen()); + fprintf(F, "\n"); + DumpSubTree(Node->getElse()); + fprintf(F, ")"); +} + +void StmtDumper::VisitSwitchStmt(SwitchStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, "\n"); + DumpSubTree(Node->getBody()); + fprintf(F, ")"); +} + +void StmtDumper::VisitSwitchCase(SwitchCase*) { + assert(0 && "SwitchCase is an abstract class"); +} + +void StmtDumper::VisitWhileStmt(WhileStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, "\n"); + DumpSubTree(Node->getBody()); + fprintf(F, ")"); +} + +void StmtDumper::VisitDoStmt(DoStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getBody()); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, ")"); +} + +void StmtDumper::VisitForStmt(ForStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getInit()); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, "\n"); + DumpSubTree(Node->getInc()); + fprintf(F, "\n"); + DumpSubTree(Node->getBody()); + fprintf(F, ")"); +} + +void StmtDumper::VisitGotoStmt(GotoStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s':%p)", Node->getLabel()->getName(), (void*)Node->getLabel()); +} + +void StmtDumper::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { + DumpStmt(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getTarget()); + fprintf(F, ")"); +} + +void StmtDumper::VisitContinueStmt(ContinueStmt *Node) { + DumpStmt(Node); + fprintf(F, ")"); +} + +void StmtDumper::VisitBreakStmt(BreakStmt *Node) { + DumpStmt(Node); + fprintf(F, ")"); +} + + +void StmtDumper::VisitReturnStmt(ReturnStmt *Node) { + DumpStmt(Node); + if (Expr *RV = Node->getRetValue()) { + fprintf(F, "\n"); + DumpSubTree(RV); + } + fprintf(F, ")"); +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitExpr(Expr *Node) { + DumpExpr(Node); + fprintf(F, ": UNKNOWN EXPR to StmtDumper)"); +} + +void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { + DumpExpr(Node); + fprintf(F, " Decl='%s' %p)", Node->getDecl()->getName(), + (void*)Node->getDecl()); +} + +void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) { + DumpExpr(Node); + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PreDefinedExpr::Func: + fprintf(F, " __func__)"); + break; + case PreDefinedExpr::Function: + fprintf(F, " __FUNCTION__)"); + break; + case PreDefinedExpr::PrettyFunction: + fprintf(F, " __PRETTY_FUNCTION__)"); + break; + } +} + +void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { +#if 0 + // FIXME should print an L for wchar_t constants + unsigned value = Node->getValue(); + switch (value) { + case '\\': + OS << "'\\\\'"; + break; + case '\'': + OS << "'\\''"; + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + OS << "'\\a'"; + break; + case '\b': + OS << "'\\b'"; + break; + // Nonstandard escape sequence. + /*case '\e': + OS << "'\\e'"; + break;*/ + case '\f': + OS << "'\\f'"; + break; + case '\n': + OS << "'\\n'"; + break; + case '\r': + OS << "'\\r'"; + break; + case '\t': + OS << "'\\t'"; + break; + case '\v': + OS << "'\\v'"; + break; + default: + if (isprint(value) && value < 256) { + OS << "'" << (char)value << "'"; + } else if (value < 256) { + OS << "'\\x" << std::hex << value << std::dec << "'"; + } else { + // FIXME what to really do here? + OS << value; + } + } +#endif +} + +void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { + DumpExpr(Node); + + bool isSigned = Node->getType()->isSignedIntegerType(); + fprintf(F, " %s)", Node->getValue().toString(10, isSigned).c_str()); +} +void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { + DumpExpr(Node); + fprintf(F, " %f)", Node->getValue()); +} +void StmtDumper::VisitStringLiteral(StringLiteral *Str) { +#if 0 + if (Str->isWide()) OS << 'L'; + OS << '"'; + + // FIXME: this doesn't print wstrings right. + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (Str->getStrData()[i]) { + default: OS << Str->getStrData()[i]; break; + // Handle some common ones to make dumps prettier. + case '\\': OS << "\\\\"; break; + case '"': OS << "\\\""; break; + case '\n': OS << "\\n"; break; + case '\t': OS << "\\t"; break; + case '\a': OS << "\\a"; break; + case '\b': OS << "\\b"; break; + } + } + OS << '"'; +#endif +} +void StmtDumper::VisitParenExpr(ParenExpr *Node) { + DumpExpr(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getSubExpr()); + fprintf(F, ")"); +} +void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { +#if 0 + if (!Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + DumpExpr(Node->getSubExpr()); + + if (Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + +#endif +} +void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { +#if 0 + OS << (Node->isSizeOf() ? "sizeof(" : "__alignof("); + OS << Node->getArgumentType().getAsString() << ")"; +#endif +} +void StmtDumper::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { + DumpExpr(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getBase()); + fprintf(F, "\n"); + DumpSubTree(Node->getIdx()); + fprintf(F, ")"); +} + +void StmtDumper::VisitCallExpr(CallExpr *Node) { + DumpExpr(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getCallee()); + + for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i) { + fprintf(F, "\n"); + DumpSubTree(Node->getArg(i)); + } + fprintf(F, ")"); +} +void StmtDumper::VisitMemberExpr(MemberExpr *Node) { +#if 0 + DumpExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + + FieldDecl *Field = Node->getMemberDecl(); + assert(Field && "MemberExpr should alway reference a field!"); + OS << Field->getName(); +#endif +} +void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { +#if 0 + DumpExpr(Node->getBase()); + OS << "."; + OS << Node->getAccessor().getName(); +#endif +} +void StmtDumper::VisitCastExpr(CastExpr *Node) { +#if 0 + OS << "(" << Node->getType().getAsString() << ")"; + DumpExpr(Node->getSubExpr()); +#endif +} +void StmtDumper::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { +#if 0 + OS << "(" << Node->getType().getAsString() << ")"; + DumpExpr(Node->getInitializer()); +#endif +} +void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { + DumpExpr(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getSubExpr()); + fprintf(F, ")"); +} +void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { + DumpExpr(Node); + fprintf(F, " '%s'\n", BinaryOperator::getOpcodeStr(Node->getOpcode())); + DumpSubTree(Node->getLHS()); + fprintf(F, "\n"); + DumpSubTree(Node->getRHS()); + fprintf(F, ")"); +} +void StmtDumper::VisitConditionalOperator(ConditionalOperator *Node) { + DumpExpr(Node); + fprintf(F, "\n"); + DumpSubTree(Node->getCond()); + fprintf(F, "\n"); + DumpSubTree(Node->getLHS()); + fprintf(F, "\n"); + DumpSubTree(Node->getRHS()); + fprintf(F, ")"); +} + +// GNU extensions. + +void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { +#if 0 + OS << "&&" << Node->getLabel()->getName(); +#endif +} + +void StmtDumper::VisitStmtExpr(StmtExpr *E) { +#if 0 + OS << "("; + DumpSubTree(E->getSubStmt()); + OS << ")"; +#endif +} + +void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { +#if 0 + OS << "__builtin_types_compatible_p("; + OS << Node->getArgType1().getAsString() << ","; + OS << Node->getArgType2().getAsString() << ")"; +#endif +} + +void StmtDumper::VisitChooseExpr(ChooseExpr *Node) { +#if 0 + OS << "__builtin_choose_expr("; + DumpExpr(Node->getCond()); + OS << ", "; + DumpExpr(Node->getLHS()); + OS << ", "; + DumpExpr(Node->getRHS()); + OS << ")"; +#endif +} + +// C++ + +void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) { +#if 0 + switch (Node->getOpcode()) { + default: + assert(0 && "Not a C++ cast expression"); + abort(); + case CXXCastExpr::ConstCast: OS << "const_cast<"; break; + case CXXCastExpr::DynamicCast: OS << "dynamic_cast<"; break; + case CXXCastExpr::ReinterpretCast: OS << "reinterpret_cast<"; break; + case CXXCastExpr::StaticCast: OS << "static_cast<"; break; + } + + OS << Node->getDestType().getAsString() << ">("; + DumpExpr(Node->getSubExpr()); + OS << ")"; +#endif +} + +void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { +#if 0 + OS << (Node->getValue() ? "true" : "false"); +#endif +} + + +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +/// dump - This does a local dump of the specified AST fragment. It dumps the +/// specified node and a few nodes underneath it, but not the whole subtree. +/// This is useful in a debugger. +void Stmt::dump() const { + StmtDumper P(stderr, 4); + const_cast<Stmt*>(this)->visit(P); +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll() const { + StmtDumper P(stderr, ~0U); + const_cast<Stmt*>(this)->visit(P); +} diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index 41aa6468db..f44e20a0ab 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Stmt::dump/Stmt::print methods. +// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which +// pretty print the AST back out to C code. // //===----------------------------------------------------------------------===// @@ -524,12 +525,12 @@ void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { // Stmt method implementations //===----------------------------------------------------------------------===// -void Stmt::dump() const { +void Stmt::dumpPretty() const { // FIXME: eliminate use of <iostream> - print(std::cerr); + printPretty(std::cerr); } -void Stmt::print(std::ostream &OS) const { +void Stmt::printPretty(std::ostream &OS) const { if (this == 0) { OS << "<NULL>"; return; diff --git a/AST/Type.cpp b/AST/Type.cpp index 27453ca981..dca9404dc9 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -677,7 +677,7 @@ void TypeOfExpr::getAsStringInternal(std::string &InnerString) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. InnerString = ' ' + InnerString; std::ostringstream s; - getUnderlyingExpr()->print(s); + getUnderlyingExpr()->printPretty(s); InnerString = "typeof(" + s.str() + ")" + InnerString; } diff --git a/Driver/ASTStreamers.cpp b/Driver/ASTStreamers.cpp index 19e12bd69e..7f67cd405d 100644 --- a/Driver/ASTStreamers.cpp +++ b/Driver/ASTStreamers.cpp @@ -15,6 +15,7 @@ #include "clang/AST/AST.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ASTStreamer.h" +using namespace clang; void clang::BuildASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) { // collect global stats on Decls/Stmts (until we have a module streamer) @@ -40,7 +41,9 @@ void clang::BuildASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) { ASTStreamer_Terminate(Streamer); } -void clang::PrintFunctionDecl(FunctionDecl *FD) { + + +static void PrintFunctionDeclStart(FunctionDecl *FD) { bool HasBody = FD->getBody(); std::string Proto = FD->getName(); @@ -70,16 +73,12 @@ void clang::PrintFunctionDecl(FunctionDecl *FD) { AFT->getResultType().getAsStringInternal(Proto); fprintf(stderr, "\n%s", Proto.c_str()); - if (FD->getBody()) { - fprintf(stderr, " "); - FD->getBody()->dump(); - fprintf(stderr, "\n"); - } else { + if (!FD->getBody()) fprintf(stderr, ";\n"); - } + // Doesn't print the body. } -void clang::PrintTypeDefDecl(TypedefDecl *TD) { +static void PrintTypeDefDecl(TypedefDecl *TD) { std::string S = TD->getName(); TD->getUnderlyingType().getAsStringInternal(S); fprintf(stderr, "typedef %s;\n", S.c_str()); @@ -91,7 +90,13 @@ void clang::PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) { while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - PrintFunctionDecl(FD); + PrintFunctionDeclStart(FD); + + if (FD->getBody()) { + fprintf(stderr, " "); + FD->getBody()->dumpPretty(); + fprintf(stderr, "\n"); + } } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { PrintTypeDefDecl(TD); } else { @@ -107,3 +112,34 @@ void clang::PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) { ASTStreamer_Terminate(Streamer); } + +void clang::DumpASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) { + ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable()); + ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID); + + while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + PrintFunctionDeclStart(FD); + + if (FD->getBody()) { + fprintf(stderr, "\n"); + FD->getBody()->dumpAll(); + fprintf(stderr, "\n"); + } + } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + PrintTypeDefDecl(TD); + } else { + fprintf(stderr, "Read top-level variable decl: '%s'\n", D->getName()); + } + } + + if (Stats) { + fprintf(stderr, "\nSTATISTICS:\n"); + ASTStreamer_PrintStats(Streamer); + Context.PrintStats(); + } + + ASTStreamer_Terminate(Streamer); +} + + diff --git a/Driver/ASTStreamers.h b/Driver/ASTStreamers.h index 2cce217ce6..93749a46e7 100644 --- a/Driver/ASTStreamers.h +++ b/Driver/ASTStreamers.h @@ -22,8 +22,7 @@ class TypedefDecl; void BuildASTs(Preprocessor &PP, unsigned MainFileID, bool Stats); void PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats); -void PrintFunctionDecl(FunctionDecl *FD); -void PrintTypeDefDecl(TypedefDecl *TD); +void DumpASTs(Preprocessor &PP, unsigned MainFileID, bool Stats); } // end clang namespace diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 7d8a4590f1..2ee8a93a30 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -49,6 +49,7 @@ Stats("stats", llvm::cl::desc("Print performance metrics and statistics")); enum ProgActions { EmitLLVM, // Emit a .ll file. ParseASTPrint, // Parse ASTs and print them. + ParseASTDump, // Parse ASTs and dump them. ParseASTCheck, // Parse ASTs and check diagnostics. ParseAST, // Parse ASTs. ParsePrintCallbacks, // Parse and print each callback. @@ -79,6 +80,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, "Run parser and build ASTs"), clEnumValN(ParseASTPrint, "parse-ast-print", "Run parser, build ASTs, then print ASTs"), + clEnumValN(ParseASTDump, "parse-ast-dump", + "Run parser, build ASTs, then dump them"), clEnumValN(ParseASTCheck, "parse-ast-check", "Run parser, build ASTs, then check diagnostics"), clEnumValN(EmitLLVM, "emit-llvm", @@ -819,6 +822,9 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID, case ParseASTPrint: PrintASTs(PP, MainFileID, Stats); break; + case ParseASTDump: + DumpASTs(PP, MainFileID, Stats); + break; case EmitLLVM: EmitLLVMFromASTs(PP, MainFileID, Stats); break; diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 352b750534..b9f8fe6465 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -118,6 +118,7 @@ DEF2E9320C5FB9FB000C4259 /* ASTStreamers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E9310C5FB9FB000C4259 /* ASTStreamers.h */; }; DEF2E9340C5FBA02000C4259 /* ASTStreamers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2E9330C5FBA02000C4259 /* ASTStreamers.cpp */; }; DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */; }; + DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */; }; F0226FD20C18084500141F42 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */; }; F0226FD30C18084500141F42 /* TextDiagnosticPrinter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */; }; /* End PBXBuildFile section */ @@ -303,6 +304,7 @@ DEF2E9310C5FB9FB000C4259 /* ASTStreamers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTStreamers.h; path = Driver/ASTStreamers.h; sourceTree = "<group>"; }; DEF2E9330C5FBA02000C4259 /* ASTStreamers.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStreamers.cpp; path = Driver/ASTStreamers.cpp; sourceTree = "<group>"; }; DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = "<group>"; }; + DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = AST/StmtDumper.cpp; sourceTree = "<group>"; }; F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = Driver/TextDiagnosticPrinter.cpp; sourceTree = "<group>"; }; F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticPrinter.h; path = Driver/TextDiagnosticPrinter.h; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -491,6 +493,7 @@ DE0FCB330A9C21F100248FD5 /* Expr.cpp */, DE3452400AEF1A2D00DBC861 /* Stmt.cpp */, DE75EDF00B06880E0020CF81 /* Type.cpp */, + DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */, DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */, DE345C560AFC69E800DBC861 /* StmtVisitor.cpp */, ); @@ -675,6 +678,7 @@ DEC82DC40C32D50A00BAC245 /* DiagChecker.cpp in Sources */, DEEBCBE50C33703100A9FE82 /* TextDiagnosticBuffer.cpp in Sources */, DEF2E9340C5FBA02000C4259 /* ASTStreamers.cpp in Sources */, + DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index ef6e739447..f9d0bb3721 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -52,9 +52,19 @@ public: static void addStmtClass(const StmtClass s); static bool CollectingStats(bool enable=false); static void PrintStats(); - + + /// dump - This does a local dump of the specified AST fragment. It dumps the + /// specified node and a few nodes underneath it, but not the whole subtree. + /// This is useful in a debugger. void dump() const; - void print(std::ostream &OS) const; + + /// dumpAll - This does a dump of the specified AST fragment and all subtrees. + void dumpAll() const; + + /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST + /// back to its original source language syntax. + void dumpPretty() const; + void printPretty(std::ostream &OS) const; // Implement visitor support. virtual void visit(StmtVisitor &Visitor); @@ -367,10 +377,10 @@ public: class IndirectGotoStmt : public Stmt { Expr *Target; public: - IndirectGotoStmt(Expr *target) : Stmt(IndirectGotoStmtClass), - Target(target) {} + IndirectGotoStmt(Expr *target) : Stmt(IndirectGotoStmtClass), Target(target){} Expr *getTarget() { return Target; } + const Expr *getTarget() const { return Target; } virtual void visit(StmtVisitor &Visitor); static bool classof(const Stmt *T) { |