Index: libcfa/configure
===================================================================
--- libcfa/configure	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ libcfa/configure	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -1959,4 +1959,5 @@
 
 
+
 am__api_version='1.15'
 
Index: src/CodeTools/ResolvProtoDump.cc
===================================================================
--- src/CodeTools/ResolvProtoDump.cc	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
+++ src/CodeTools/ResolvProtoDump.cc	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -0,0 +1,586 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolvProtoDump.cc -- Translates CFA resolver instances into resolv-proto instances
+//
+// Author           : Aaron Moss
+// Created On       : Tue Sep 11 09:04:00 2018
+// Last Modified By : Aaron Moss
+// Last Modified On : Tue Sep 11 09:04:00 2018
+// Update Count     : 1
+//
+
+#include <algorithm>
+#include <cctype>
+#include <iostream>
+#include <memory>
+#include <list>
+#include <set>
+#include <sstream>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "Common/PassVisitor.h"
+#include "CodeGen/OperatorTable.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Statement.h"
+#include "SynTree/Type.h"
+
+namespace CodeTools {
+
+	/// Visitor for dumping resolver prototype output
+	class ProtoDump : public WithShortCircuiting, public WithVisitorRef<ProtoDump> {
+		std::set<std::string> decls;               ///< Declarations in this scope
+		std::set<std::string> exprs;               ///< Expressions in this scope
+		std::vector<PassVisitor<ProtoDump>> subs;  ///< Sub-scopes
+		const ProtoDump* parent;                   ///< Outer lexical scope
+
+	public:
+		/// Default constructor for root ProtoDump
+		ProtoDump() : decls(), exprs(), subs(), parent(nullptr) {}
+
+		/// Child constructor
+		ProtoDump(const ProtoDump& p) : decls(), exprs(), subs(), parent(&p) {}
+
+	private:
+		/// checks if this declaration is contained in the scope or one of its parents
+		bool hasDecl( const std::string& s ) const {
+			if ( decls.count( s ) ) return true;
+			if ( parent ) return parent->hasDecl( s );
+			return false;
+		}
+
+		/// adds a new declaration to this scope, providing it does not already exist
+		void addDecl( const std::string& s ) {
+			if ( ! hasDecl( s ) ) decls.insert( s );
+		}
+
+		/// adds a new expression to this scope
+		void addExpr( const std::string& s ) {
+			if ( ! s.empty() ) { exprs.insert( s ); }
+		}
+
+		/// adds a new subscope to this scope, returning a reference
+		PassVisitor<ProtoDump>& addSub() {
+			subs.emplace_back( *this );
+			return subs.back();
+		}
+	
+		/// Whether lists should be separated, terminated, or preceded by their separator
+		enum septype { separated, terminated, preceded };
+
+		/// builds space-separated list of types
+		template<typename V>
+		static void build( V& visitor, const std::list< Type* >& tys, std::stringstream& ss, 
+				septype mode = separated ) {
+			if ( tys.empty() ) return;
+
+			if ( mode == preceded ) { ss << ' '; }
+
+			auto it = tys.begin();
+			(*it)->accept( visitor );
+
+			while ( ++it != tys.end() ) {
+				ss << ' ';
+				(*it)->accept( visitor );
+			}
+
+			if ( mode == terminated ) { ss << ' '; }
+		}
+
+		/// builds list of types wrapped as tuple type
+		template<typename V>
+		static void buildAsTuple( V& visitor, const std::list< Type* >& tys, 
+				std::stringstream& ss ) {
+			switch ( tys.size() ) {
+				case 0: ss << "#void"; break;
+				case 1: tys.front()->accept( visitor ); break;
+				default:
+					ss << "#$" << tys.size() << '<';
+					build( visitor, tys, ss );
+					ss << '>';
+					break;
+			}
+		}
+
+		/// gets types from DWT list
+		static std::list< Type* > from_decls( const std::list< DeclarationWithType* >& decls ) {
+			std::list< Type* > tys;
+			for ( auto decl : decls ) { tys.emplace_back( decl->get_type() ); }
+			return tys;
+		}
+
+		/// gets types from TypeExpr list
+		static std::list< Type* > from_exprs( const std::list< Expression* >& exprs ) {
+			std::list< Type* > tys;
+			for ( auto expr : exprs ) {
+				if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(expr) ) {
+					tys.emplace_back( tyExpr->type );
+				}
+			}
+			return tys;
+		}
+
+		/// builds prefixes for rp_name
+		static std::string new_prefix( const std::string& old, const char* added ) {
+			if ( old.empty() ) return std::string{"$"} + added;
+			return old + added;
+		}
+
+		/// shortens operator names
+		static void op_name( const std::string& name, std::stringstream& ss ) {
+			if ( name.compare( 0, 10, "_operator_" ) == 0 ) {
+				ss << name.substr(10);
+			} else if ( name.compare( "_constructor" ) == 0 
+					|| name.compare( "_destructor" ) == 0 ) {
+				ss << name.substr(1);
+			} else if ( name.compare( 0, 11, "__operator_" ) == 0 ) {
+				ss << name.substr(11);
+			} else {
+				ss << name;
+			}
+		}
+
+		/// replaces operators with resolv-proto names
+		static void rp_name( const std::string& name, std::stringstream& ss, 
+				std::string&& pre = "" ) {
+			// safety check for anonymous names
+			if ( name.empty() ) {
+				ss << new_prefix(pre, "anon");
+				return;
+			}
+
+			// replace operator names
+			CodeGen::OperatorInfo info;
+			if ( CodeGen::operatorLookup( name, info ) ) {
+				ss << new_prefix(pre, "");
+				op_name( info.outputName, ss );
+				return;
+			} 
+			
+			// replace retval names
+			if ( name.compare( 0, 8, "_retval_" ) == 0 ) {
+				ss << new_prefix(pre, "rtn_");
+				op_name( name.substr(8), ss );
+				return;
+			}
+			
+			// default to just name
+			ss << pre << name;
+		}
+
+		/// ensures type inst names are uppercase
+		static void ti_name( const std::string& name, std::stringstream& ss ) {
+			ss << (char)std::toupper( static_cast<unsigned char>(name[0]) )
+			   << (name.c_str() + 1);
+		}
+
+		/// Visitor for printing types
+		struct TypePrinter : public WithShortCircuiting, WithVisitorRef<TypePrinter>, WithGuards {
+			std::stringstream& ss;  ///< Output to print to
+			unsigned depth;         ///< Depth of nesting from root type
+
+			TypePrinter( std::stringstream& ss ) : ss(ss), depth(0) {}
+
+			// basic type represented as integer type
+			// TODO maybe hard-code conversion graph and make named type
+			void previsit( BasicType* bt ) { ss << (int)bt->get_kind(); }
+
+			// pointers represented as generic type
+			// TODO except pointer to function
+			void previsit( PointerType* ) { ss << "#$ptr<"; ++depth; }
+			void postvisit( PointerType* ) { --depth; ss << '>'; }
+
+			// arrays represented as generic type
+			void previsit( ArrayType* ) { ss << "#$arr<"; ++depth; }
+			void postvisit( ArrayType* ) { --depth; ss << '>'; }
+
+			// ignore top-level reference types, they're mostly transparent to resolution
+			void previsit( ReferenceType* ) {
+				if ( depth > 0 ) { ss << "#$ref<"; }
+				++depth;
+			}
+			void postvisit( ReferenceType* ) {
+				--depth;
+				if ( depth > 0 ) { ss << '>'; }
+			}
+
+			// encode function type as a 2-param generic type
+			// TODO handle forall functions
+			void previsit( FunctionType* ft ) {
+				ss << "#$fn<";
+				++depth;
+				buildAsTuple( *visitor, from_decls( ft->returnVals ), ss );
+				ss << ' ';
+				buildAsTuple( *visitor, from_decls( ft->parameters ), ss );
+				--depth;
+				ss << '>';
+				visit_children = false;
+			}
+
+		private:
+			// prints aggregate type name as NamedType with optional paramters
+			void handleAggregate( ReferenceToType* at ) {
+				ss << '#' << at->name;
+				if ( ! at->parameters.empty() ) {
+					ss << '<';
+					++depth;
+					build( *visitor, from_exprs( at->parameters ), ss );
+					--depth;
+					ss << '>';
+				}
+				visit_children = false;
+			}
+
+		public:
+			// handle aggregate types using NamedType
+			void previsit( StructInstType* st ) { handleAggregate( st ); }
+			void previsit( UnionInstType* ut ) { handleAggregate( ut ); }
+
+			// replace enums with int
+			void previsit( EnumInstType* ) { ss << (int)BasicType::SignedInt; }
+
+			// make sure first letter of TypeInstType is capitalized
+			void previsit( TypeInstType* vt ) {
+				ti_name( vt->name, ss );
+			}
+
+			// flattens empty and singleton tuples
+			void previsit( TupleType* tt ) {
+				++depth;
+				buildAsTuple( *visitor, tt->types, ss );
+				--depth;
+				visit_children = false;
+			}
+
+			// TODO support VarArgsType
+
+			// replace 0 and 1 with int
+			// TODO support 0 and 1 with their proper type names and conversions
+			void previsit( ZeroType* ) { ss << (int)BasicType::SignedInt; }
+			void previsit( OneType* ) { ss << (int)BasicType::SignedInt; }
+
+			// only print void type if not at top level
+			void previsit( VoidType* ) {
+				if ( depth > 0 ) { ss << "#void"; }
+			}
+		};
+	
+		/// builds description of function
+		void build( const std::string& name, FunctionType* fnTy, std::stringstream& ss ) {
+			PassVisitor<TypePrinter> printTy{ ss };
+			build( printTy, from_decls( fnTy->returnVals ), ss, terminated );
+			rp_name( name, ss );
+			build( printTy, from_decls( fnTy->parameters ), ss, preceded );
+			// TODO handle assertions
+		}
+
+		/// builds description of a variable (falls back to function if function type)
+		void build( const std::string& name, Type* ty, std::stringstream& ss ) {
+			// ignore top-level references
+			Type *norefs = ty->stripReferences();
+			
+			// fall back to function declaration if function type
+			if ( PointerType* pTy = dynamic_cast< PointerType* >(norefs) ) {
+				if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(pTy->base) ) {
+					build( name, fnTy, ss );
+					return;
+				}
+			} else if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(norefs) ) {
+				build( name, fnTy, ss );
+				return;
+			}
+
+			// print variable declaration as zero-arg function
+			PassVisitor<TypePrinter> printTy{ ss };
+			norefs->accept( printTy );
+			ss << ' ';
+			rp_name( name, ss );
+		}
+
+		/// builds description of a field access
+		void build( const std::string& name, AggregateDecl* agg, Type* ty, std::stringstream& ss ) {
+			// ignore top-level references
+			Type *norefs = ty->stripReferences();
+
+			// print access as new field name
+			PassVisitor<TypePrinter> printTy{ ss };
+			norefs->accept( printTy );
+			ss << ' ';
+			rp_name( name, ss, "$field_" );
+			ss << " #" << agg->name;
+			// handle type parameters
+			if ( ! agg->parameters.empty() ) {
+				ss << '<';
+				auto it = agg->parameters.begin();
+				while (true) {
+					ti_name( (*it)->name, ss );
+					if ( ++it == agg->parameters.end() ) break;
+					ss << ' ';
+				}
+				ss << '>';
+			}
+		}
+
+		/// Visitor for printing expressions
+		struct ExprPrinter : WithShortCircuiting, WithVisitorRef<ExprPrinter> {
+			// TODO change interface to generate multiple expression candidates
+
+			std::stringstream& ss;  ///< Output to print to
+
+			ExprPrinter( std::stringstream& ss ) : ss(ss) {}
+
+			/// Names handled as nullary function calls
+			void previsit( NameExpr* expr ) {
+				rp_name( expr->name, ss );
+				ss << "()";
+			}
+
+			/// Calls handled as calls
+			void previsit( UntypedExpr* expr ) {
+				// TODO handle name extraction more generally
+				NameExpr* name = dynamic_cast<NameExpr*>(expr->function);
+
+				// fall back on just resolving call to function name
+				// TODO incorporate function type into resolv-proto
+				if ( ! name ) {
+					expr->function->accept( *visitor );
+					visit_children = false;
+					return;
+				}
+
+				rp_name( name->name, ss );
+				if ( expr->args.empty() ) {
+					ss << "()";
+				} else {
+					ss << "( ";
+					auto it = expr->args.begin();
+					while (true) {
+						(*it)->accept( *visitor );
+						if ( ++it == expr->args.end() ) break;
+						ss << ' ';
+					}
+					ss << " )";
+				}
+				visit_children = false;
+			}
+
+			/// Address-of handled as operator
+			void previsit( AddressExpr* expr ) {
+				// TODO global function to implement this
+				ss << "$addr( ";
+				expr->arg->accept( *visitor );
+				ss << " )";
+				visit_children = false;
+			}
+
+			/// Casts replaced with arguments 
+			/// TODO put casts in resolv-proto
+			
+			/// Member access handled as function from aggregate to member
+			void previsit( UntypedMemberExpr* expr ) {
+				// TODO handle name extraction more generally
+				NameExpr* name = dynamic_cast<NameExpr*>(expr->member);
+
+				// fall back on just resolving call to member name
+				// TODO incorporate function type into resolv-proto
+				if ( ! name ) {
+					expr->member->accept( *visitor );
+					visit_children = false;
+					return;
+				}
+
+				rp_name( name->name, ss, "$field_" );
+				ss << "( ";
+				expr->aggregate->accept( *visitor );
+				ss << " )";
+				visit_children = false;
+			}
+
+			/// Constant expression replaced by its type
+			void previsit( ConstantExpr* expr ) {
+				PassVisitor<TypePrinter> tyPrinter{ ss };
+				expr->constant.get_type()->accept( tyPrinter );
+				visit_children = false;
+			}
+
+			/// sizeof( ... ), alignof( ... ), offsetof( ... ) replaced by unsigned long constant
+			/// TODO extra expression to resolve argument
+			void previsit( SizeofExpr* ) {
+				ss << (int)BasicType::LongUnsignedInt;
+				visit_children = false;
+			}
+			void previsit( AlignofExpr* ) {
+				ss << (int)BasicType::LongUnsignedInt;
+				visit_children = false;
+			}
+			void previsit( UntypedOffsetofExpr* ) {
+				ss << (int)BasicType::LongUnsignedInt;
+				visit_children = false;
+			}
+
+			/// Logical expressions represented as operators
+			void previsit( LogicalExpr* expr ) {
+				// TODO global functions for these
+				ss << '$' << ( expr->get_isAnd() ? "and" : "or" ) << "( ";
+				expr->arg1->accept( *visitor );
+				ss << ' ';
+				expr->arg2->accept( *visitor );
+				ss << " )";
+				visit_children = false;
+			}
+
+			/// Conditional expression represented as operator
+			void previsit( ConditionalExpr* expr ) {
+				// TODO global function for this
+				ss << "$if( ";
+				expr->arg1->accept( *visitor );
+				ss << ' ';
+				expr->arg2->accept( *visitor );
+				ss << ' ';
+				expr->arg3->accept( *visitor );
+				ss << " )";
+				visit_children = false;
+			}
+
+			/// Comma expression represented as operator
+			void previsit( CommaExpr* expr ) {
+				// TODO global function for this
+				ss << "$seq( ";
+				expr->arg1->accept( *visitor );
+				ss << ' ';
+				expr->arg2->accept( *visitor );
+				ss << " )";
+				visit_children = false;
+			}
+
+			// TODO handle ignored ImplicitCopyCtorExpr and below
+		};
+
+		/// Adds all named declarations in a list to the local scope
+		void addAll( const std::list<DeclarationWithType*>& decls ) {
+			for ( auto decl : decls ) {
+				// skip anonymous decls
+				if ( decl->name.empty() ) continue;
+
+				// handle objects
+				if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >( decl ) ) {
+					previsit( obj );
+				}
+			}
+		}
+
+		/// encode field access as function
+		void addAggregateFields( AggregateDecl* agg ) {
+			// make field names functions
+			for ( Declaration* member : agg->members ) {
+				if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
+					std::stringstream ss;
+					build( obj->name, agg, obj->type, ss );
+					addDecl( ss.str() );
+				}
+			}
+
+			visit_children = false;
+		}
+
+	public:
+		void previsit( ObjectDecl *obj ) {
+			// add variable as declaration
+			std::stringstream ss;
+			build( obj->name, obj->type, ss );
+			addDecl( ss.str() );
+		}
+
+		void previsit( FunctionDecl *decl ) {
+			// add function as declaration
+			std::stringstream ss;
+			build( decl->name, decl->type, ss );
+			addDecl( ss.str() );
+
+			// add body if available
+			if ( decl->statements ) {
+				PassVisitor<ProtoDump>& body = addSub();
+				
+				// add named parameters and returns to local scope
+				body.pass.addAll( decl->type->returnVals );
+				body.pass.addAll( decl->type->parameters );
+				
+				// TODO add assertions to local scope
+
+				// TODO add set of "closed" types to body so that it can print them as NamedType
+
+				// add contents of function to new scope
+				decl->statements->accept( body );
+			}
+
+			visit_children = false;
+		}
+
+		void previsit( StructDecl* sd ) { addAggregateFields(sd); }
+		void previsit( UnionDecl* ud ) { addAggregateFields(ud); }
+		
+		void previsit( EnumDecl* ed ) {
+			std::unique_ptr<Type> eType = 
+				std::make_unique<BasicType>( Type::Qualifiers{}, BasicType::SignedInt );
+			
+			// add field names directly to enclosing scope
+			for ( Declaration* member : ed->members ) {
+				if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
+					previsit(obj);
+				}
+			}
+
+			visit_children = false;
+		}
+
+		void previsit( Expression* expr ) {
+			std::stringstream ss;
+			PassVisitor<ExprPrinter> exPrinter{ss};
+			expr->accept( exPrinter );
+			addExpr( ss.str() );
+			visit_children = false;
+		}
+
+	public:
+		/// Prints this ProtoDump instance
+		void print(unsigned indent = 0) const {
+			std::string tab( indent, '\t' );
+			// print decls
+			for ( const std::string& d : decls ) {
+				std::cout << tab << d << std::endl;
+			}
+			// print divider
+			std::cout << tab << "%%" << std::endl;
+			// print top-level expressions
+			for ( const std::string& e : exprs ) {
+				std::cout << tab << e << std::endl;
+			}
+			// print child scopes
+			++indent;
+			for ( const PassVisitor<ProtoDump>& s : subs ) {
+				std::cout << tab << '{' << std::endl;
+				s.pass.print( indent );
+				std::cout << tab << '}' << std::endl;
+			}
+		}
+	};
+
+	void dumpAsResolvProto( std::list< Declaration * > &translationUnit ) {
+		PassVisitor<ProtoDump> dump;
+		acceptAll( translationUnit, dump );
+		dump.pass.print();
+	}
+
+}  // namespace CodeTools
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/CodeTools/ResolvProtoDump.h
===================================================================
--- src/CodeTools/ResolvProtoDump.h	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
+++ src/CodeTools/ResolvProtoDump.h	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -0,0 +1,33 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolvProtoDump.h -- Translates CFA resolver instances into resolv-proto instances
+//
+// Author           : Aaron Moss
+// Created On       : Tue Sep 11 09:04:00 2018
+// Last Modified By : Aaron Moss
+// Last Modified On : Tue Sep 11 09:04:00 2018
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <list>
+
+class Declaration;
+
+namespace CodeTools {
+
+	/// Prints a translation unit in the input format of the resolv-proto tool
+	void dumpAsResolvProto( std::list< Declaration * > &translationUnit );
+
+}  // namespace CodeTools
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/CodeTools/module.mk
===================================================================
--- src/CodeTools/module.mk	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ src/CodeTools/module.mk	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -16,3 +16,4 @@
 
 SRC += CodeTools/DeclStats.cc \
+	CodeTools/ResolvProtoDump.cc \
 	CodeTools/TrackLoc.cc
Index: src/CompilationState.cc
===================================================================
--- src/CompilationState.cc	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ src/CompilationState.cc	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -30,4 +30,5 @@
 	parsep = false,
 	resolvep = false,
+	resolvprotop = false,
 	symtabp = false,
 	treep = false,
Index: src/CompilationState.h
===================================================================
--- src/CompilationState.h	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ src/CompilationState.h	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -31,4 +31,5 @@
 	parsep,
 	resolvep,
+	resolvprotop,
 	symtabp,
 	treep,
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ src/Makefile.in	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -221,4 +221,5 @@
 	CodeGen/FixNames.$(OBJEXT) CodeGen/FixMain.$(OBJEXT) \
 	CodeGen/OperatorTable.$(OBJEXT) CodeTools/DeclStats.$(OBJEXT) \
+	CodeTools/ResolvProtoDump.$(OBJEXT) \
 	CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \
 	Concurrency/Waitfor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
@@ -520,8 +521,9 @@
 	CodeGen/FixNames.cc CodeGen/FixMain.cc \
 	CodeGen/OperatorTable.cc CodeTools/DeclStats.cc \
-	CodeTools/TrackLoc.cc Concurrency/Keywords.cc \
-	Concurrency/Waitfor.cc Common/SemanticError.cc \
-	Common/UniqueName.cc Common/DebugMalloc.cc Common/Assert.cc \
-	Common/Heap.cc Common/Eval.cc ControlStruct/LabelGenerator.cc \
+	CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \
+	Concurrency/Keywords.cc Concurrency/Waitfor.cc \
+	Common/SemanticError.cc Common/UniqueName.cc \
+	Common/DebugMalloc.cc Common/Assert.cc Common/Heap.cc \
+	Common/Eval.cc ControlStruct/LabelGenerator.cc \
 	ControlStruct/LabelFixer.cc ControlStruct/MLEMutator.cc \
 	ControlStruct/Mutate.cc ControlStruct/ForExprMutator.cc \
@@ -999,4 +1001,6 @@
 CodeTools/DeclStats.$(OBJEXT): CodeTools/$(am__dirstamp) \
 	CodeTools/$(DEPDIR)/$(am__dirstamp)
+CodeTools/ResolvProtoDump.$(OBJEXT): CodeTools/$(am__dirstamp) \
+	CodeTools/$(DEPDIR)/$(am__dirstamp)
 CodeTools/TrackLoc.$(OBJEXT): CodeTools/$(am__dirstamp) \
 	CodeTools/$(DEPDIR)/$(am__dirstamp)
@@ -1101,4 +1105,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@CodeGen/$(DEPDIR)/OperatorTable.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@CodeTools/$(DEPDIR)/DeclStats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@CodeTools/$(DEPDIR)/ResolvProtoDump.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@CodeTools/$(DEPDIR)/TrackLoc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Assert.Po@am__quote@
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 67982887d6d6ffea6e1c510c7ded3be0a1acea1f)
+++ src/main.cc	(revision 3b3491b6cedeff816eea57a2ae4762471718ac1f)
@@ -34,4 +34,5 @@
 #include "CodeGen/Generate.h"               // for generate
 #include "CodeTools/DeclStats.h"            // for printDeclStats
+#include "CodeTools/ResolvProtoDump.h"      // for dumpAsResolvProto
 #include "CodeTools/TrackLoc.h"             // for fillLocations
 #include "Common/CompilerError.h"           // for CompilerError
@@ -271,4 +272,9 @@
 		CodeTools::fillLocations( translationUnit );
 
+		if ( resolvprotop ) {
+			CodeTools::dumpAsResolvProto( translationUnit );
+			return 0;
+		}
+
 		PASS( "resolve", ResolvExpr::resolve( translationUnit ) );
 		if ( exprp ) {
@@ -376,5 +382,5 @@
 
 void parse_cmdline( int argc, char * argv[], const char *& filename ) {
-	enum { Ast, Bbox, Bresolver, CtorInitFix, DeclStats, Expr, ExprAlt, Grammar, LibCFA, Linemarks, Nolinemarks, Nopreamble, Parse, PreludeDir, Prototypes, Resolver, Symbol, Tree, TupleExpansion, Validate, };
+	enum { Ast, Bbox, Bresolver, CtorInitFix, DeclStats, Expr, ExprAlt, Grammar, LibCFA, Linemarks, Nolinemarks, Nopreamble, Parse, PreludeDir, Prototypes, Resolver, ResolvProto, Symbol, Tree, TupleExpansion, Validate, };
 
 	static struct option long_opts[] = {
@@ -395,4 +401,5 @@
 		{ "no-prototypes", no_argument, 0, Prototypes },
 		{ "resolver", no_argument, 0, Resolver },
+		{ "resolv-proto", no_argument, 0, ResolvProto },
 		{ "symbol", no_argument, 0, Symbol },
 		{ "tree", no_argument, 0, Tree },
@@ -407,5 +414,5 @@
 	bool Wsuppress = false, Werror = false;
 	int c;
-	while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) {
+	while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) {
 		switch ( c ) {
 		  case Ast:
@@ -479,4 +486,7 @@
 		  case 'r':										// print resolver steps
 			resolvep = true;
+			break;
+			case 'R':										// dump resolv-proto instance
+			resolvprotop = true;
 			break;
 		  case Symbol:
