Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision fc20514eea90ea2d9e7e72cd6a6a11c02dc1886f)
+++ src/Parser/DeclarationNode.cc	(revision 0fc52b6ec9478db4016cce215b928b588385e1aa)
@@ -254,10 +254,27 @@
 } // DeclarationNode::newFromTypedef
 
+DeclarationNode * DeclarationNode::newFromGlobalScope() {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::GlobalScope );
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newQualifiedType( DeclarationNode * parent, DeclarationNode * child) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Qualified );
+	newnode->type->qualified.parent = parent->type;
+	newnode->type->qualified.child = child->type;
+	parent->type = nullptr;
+	child->type = nullptr;
+	delete parent;
+	delete child;
+	return newnode;
+}
+
 DeclarationNode * DeclarationNode::newAggregate( Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
-	assert( name );
 	DeclarationNode * newnode = new DeclarationNode;
 	newnode->type = new TypeData( TypeData::Aggregate );
 	newnode->type->aggregate.kind = kind;
-	newnode->type->aggregate.name = name;
+	newnode->type->aggregate.name =  name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
 	newnode->type->aggregate.actuals = actuals;
 	newnode->type->aggregate.fields = fields;
@@ -265,14 +282,15 @@
 	newnode->type->aggregate.tagged = false;
 	newnode->type->aggregate.parent = nullptr;
+	newnode->type->aggregate.anon = name == nullptr;
 	return newnode;
 } // DeclarationNode::newAggregate
 
 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body ) {
-	assert( name );
 	DeclarationNode * newnode = new DeclarationNode;
 	newnode->type = new TypeData( TypeData::Enum );
-	newnode->type->enumeration.name = name;
+	newnode->type->enumeration.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
 	newnode->type->enumeration.constants = constants;
 	newnode->type->enumeration.body = body;
+	newnode->type->enumeration.anon = name == nullptr;
 	return newnode;
 } // DeclarationNode::newEnum
@@ -953,10 +971,23 @@
 	for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
 		try {
+			bool extracted = false;
+			bool anon = false;
 			if ( DeclarationNode * extr = cur->extractAggregate() ) {
 				// handle the case where a structure declaration is contained within an object or type declaration
 				Declaration * decl = extr->build();
 				if ( decl ) {
+					// hoist the structure declaration
 					decl->location = cur->location;
 					* out++ = decl;
+
+					// need to remember the cases where a declaration contains an anonymous aggregate definition
+					extracted = true;
+					assert( extr->type );
+					if ( extr->type->kind == TypeData::Aggregate ) {
+						anon = extr->type->aggregate.anon;
+					} else if ( extr->type->kind == TypeData::Enum ) {
+						// xxx - is it useful to have an implicit anonymous enum member?
+						anon = extr->type->enumeration.anon;
+					}
 				} // if
 				delete extr;
@@ -965,6 +996,14 @@
 			Declaration * decl = cur->build();
 			if ( decl ) {
-				decl->location = cur->location;
-				* out++ = decl;
+				// don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.:
+				// struct S {
+				//   struct T { int x; }; // no anonymous member
+				//   struct { int y; };   // anonymous member
+				//   struct T;            // anonymous member
+				// };
+				if ( ! (extracted && decl->name == "" && ! anon) ) {
+					decl->location = cur->location;
+					* out++ = decl;
+				}
 			} // if
 		} catch( SemanticErrorException &e ) {
@@ -978,4 +1017,5 @@
 } // buildList
 
+// currently only builds assertions, function parameters, and return values
 void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > &outputList ) {
 	SemanticErrorException errors;
@@ -985,20 +1025,27 @@
 		try {
 			Declaration * decl = cur->build();
-			if ( decl ) {
-				if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
-					dwt->location = cur->location;
-					* out++ = dwt;
-				} else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
-					StructInstType * inst = new StructInstType( Type::Qualifiers(), agg->get_name() );
-					auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
-					obj->location = cur->location;
-					* out++ = obj;
-					delete agg;
-				} else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
-					UnionInstType * inst = new UnionInstType( Type::Qualifiers(), agg->get_name() );
-					auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
-					obj->location = cur->location;
-					* out++ = obj;
-				} // if
+			assert( decl );
+			if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
+				dwt->location = cur->location;
+				* out++ = dwt;
+			} else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
+				// e.g., int foo(struct S) {}
+				StructInstType * inst = new StructInstType( Type::Qualifiers(), agg->name );
+				auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
+				obj->location = cur->location;
+				* out++ = obj;
+				delete agg;
+			} else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
+				// e.g., int foo(union U) {}
+				UnionInstType * inst = new UnionInstType( Type::Qualifiers(), agg->name );
+				auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
+				obj->location = cur->location;
+				* out++ = obj;
+			} else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
+				// e.g., int foo(enum E) {}
+				EnumInstType * inst = new EnumInstType( Type::Qualifiers(), agg->name );
+				auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
+				obj->location = cur->location;
+				* out++ = obj;
 			} // if
 		} catch( SemanticErrorException &e ) {
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision fc20514eea90ea2d9e7e72cd6a6a11c02dc1886f)
+++ src/Parser/ParseNode.h	(revision 0fc52b6ec9478db4016cce215b928b588385e1aa)
@@ -231,4 +231,6 @@
 	static DeclarationNode * newForall( DeclarationNode * );
 	static DeclarationNode * newFromTypedef( const std::string * );
+	static DeclarationNode * newFromGlobalScope();
+	static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
 	static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
 	static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision fc20514eea90ea2d9e7e72cd6a6a11c02dc1886f)
+++ src/Parser/TypeData.cc	(revision 0fc52b6ec9478db4016cce215b928b588385e1aa)
@@ -37,4 +37,5 @@
 	  case Reference:
 	  case EnumConstant:
+	  case GlobalScope:
 		// nothing else to initialize
 		break;
@@ -62,4 +63,5 @@
 		enumeration.constants = nullptr;
 		enumeration.body = false;
+		enumeration.anon = false;
 		break;
 	  case Aggregate:
@@ -73,4 +75,5 @@
 		aggregate.tagged = false;
 		aggregate.parent = nullptr;
+		aggregate.anon = false;
 		break;
 	  case AggregateInst:
@@ -98,4 +101,7 @@
 	  case Builtin:
 		// builtin = new Builtin_t;
+		case Qualified:
+		qualified.parent = nullptr;
+		qualified.child = nullptr;
 		break;
 	} // switch
@@ -112,4 +118,5 @@
 	  case Reference:
 	  case EnumConstant:
+	  case GlobalScope:
 		// nothing to destroy
 		break;
@@ -165,4 +172,7 @@
 		// delete builtin;
 		break;
+	  case Qualified:
+		delete qualified.parent;
+		delete qualified.child;
 	} // switch
 } // TypeData::~TypeData
@@ -180,4 +190,5 @@
 	  case Pointer:
 	  case Reference:
+	  case GlobalScope:
 		// nothing else to copy
 		break;
@@ -207,4 +218,5 @@
 		newtype->aggregate.fields = maybeClone( aggregate.fields );
 		newtype->aggregate.body = aggregate.body;
+		newtype->aggregate.anon = aggregate.anon;
 		newtype->aggregate.tagged = aggregate.tagged;
 		newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
@@ -219,4 +231,5 @@
 		newtype->enumeration.constants = maybeClone( enumeration.constants );
 		newtype->enumeration.body = enumeration.body;
+		newtype->enumeration.anon = enumeration.anon;
 		break;
 	  case Symbolic:
@@ -238,4 +251,8 @@
 		newtype->builtintype = builtintype;
 		break;
+		case Qualified:
+		newtype->qualified.parent = maybeClone( qualified.parent );
+		newtype->qualified.child = maybeClone( qualified.child );
+		break;
 	} // switch
 	return newtype;
@@ -406,4 +423,33 @@
 	} // switch
 } // TypeData::print
+
+const std::string * TypeData::leafName() const {
+	switch ( kind ) {
+	  case Unknown:
+	  case Pointer:
+	  case Reference:
+	  case EnumConstant:
+	  case GlobalScope:
+	  case Array:
+	  case Basic:
+	  case Function:
+	  case AggregateInst:
+	  case Tuple:
+	  case Typeof:
+	  case Builtin:
+		assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
+		break;
+	  case Aggregate:
+		return aggregate.name;
+	  case Enum:
+		return enumeration.name;
+	  case Symbolic:
+	  case SymbolicInst:
+		return symbolic.name;
+	  case Qualified:
+		return qualified.child->leafName();
+	} // switch
+	assert(false);
+}
 
 
@@ -465,5 +511,5 @@
 		return new EnumInstType( buildQualifiers( td ), "" );
 	  case TypeData::SymbolicInst:
-		return buildSymbolicInst( td );;
+		return buildSymbolicInst( td );
 	  case TypeData::Tuple:
 		return buildTuple( td );
@@ -480,4 +526,8 @@
 			return new VarArgsType( buildQualifiers( td ) );
 		}
+	  case TypeData::GlobalScope:
+		return new GlobalScopeType();
+		case TypeData::Qualified:
+		return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
 	  case TypeData::Symbolic:
 	  case TypeData::Enum:
@@ -485,4 +535,5 @@
 		assert( false );
 	} // switch
+
 	return nullptr;
 } // typebuild
@@ -893,10 +944,10 @@
 	assert( td->kind == TypeData::Function );
 	FunctionType * ft = new FunctionType( buildQualifiers( td ), ! td->function.params || td->function.params->hasEllipsis );
-	buildList( td->function.params, ft->get_parameters() );
-	buildForall( td->forall, ft->get_forall() );
+	buildList( td->function.params, ft->parameters );
+	buildForall( td->forall, ft->forall );
 	if ( td->base ) {
 		switch ( td->base->kind ) {
 		  case TypeData::Tuple:
-			buildList( td->base->tuple, ft->get_returnVals() );
+			buildList( td->base->tuple, ft->returnVals );
 			break;
 		  default:
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision fc20514eea90ea2d9e7e72cd6a6a11c02dc1886f)
+++ src/Parser/TypeData.h	(revision 0fc52b6ec9478db4016cce215b928b588385e1aa)
@@ -27,5 +27,5 @@
 struct TypeData {
 	enum Kind { Basic, Pointer, Array, Reference, Function, Aggregate, AggregateInst, Enum, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Typeof, Builtin, Unknown };
+				SymbolicInst, Tuple, Typeof, Builtin, GlobalScope, Qualified, Unknown };
 
 	struct Aggregate_t {
@@ -36,4 +36,5 @@
 		DeclarationNode * fields;
 		bool body;
+		bool anon;
 
 		bool tagged;
@@ -57,4 +58,5 @@
 		DeclarationNode * constants;
 		bool body;
+		bool anon;
 	};
 
@@ -75,4 +77,9 @@
 	};
 
+	struct Qualified_t { // qualified type S.T
+		TypeData * parent;
+		TypeData * child;
+	};
+
 	CodeLocation location;
 
@@ -88,12 +95,11 @@
 	DeclarationNode * forall;
 
-	// Basic_t basic;
 	Aggregate_t aggregate;
 	AggInst_t aggInst;
 	Array_t array;
 	Enumeration_t enumeration;
-	// Variable_t variable;
 	Function_t function;
 	Symbolic_t symbolic;
+	Qualified_t qualified;
 	DeclarationNode * tuple;
 	ExpressionNode * typeexpr;
@@ -103,4 +109,6 @@
 	void print( std::ostream &, int indent = 0 ) const;
 	TypeData * clone() const;
+
+	const std::string * leafName() const;
 };
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision fc20514eea90ea2d9e7e72cd6a6a11c02dc1886f)
+++ src/Parser/parser.yy	(revision 0fc52b6ec9478db4016cce215b928b588385e1aa)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 11 11:20:51 2018
-// Update Count     : 3738
+// Last Modified On : Wed Jul 11 11:55:24 2018
+// Update Count     : 3739
 //
 
@@ -1825,12 +1825,12 @@
 		{ $$ = DeclarationNode::newFromTypedef( $1 ); }
 	| '.' TYPEDEFname
-		{ SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), DeclarationNode::newFromTypedef( $2 ) ); }
 	| type_name '.' TYPEDEFname
-		{ SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = DeclarationNode::newQualifiedType( $1, DeclarationNode::newFromTypedef( $3 ) ); }
 	| typegen_name
 	| '.' typegen_name
-		{ SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), $2 ); }
 	| type_name '.' typegen_name
-		{ SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = DeclarationNode::newQualifiedType( $1, $3 ); }
 	;
 
@@ -1863,5 +1863,5 @@
 		{ forall = false; }								// reset
 	  '{' field_declaration_list_opt '}' type_parameters_opt
-		{ $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), $7, $5, true )->addQualifiers( $2 ); }
+		{ $$ = DeclarationNode::newAggregate( $1, nullptr, $7, $5, true )->addQualifiers( $2 ); }
 	| aggregate_key attribute_list_opt no_attr_identifier fred
 		{
@@ -1873,5 +1873,6 @@
 	| aggregate_key attribute_list_opt type_name fred
 		{
-			typedefTable.makeTypedef( *$3->type->symbolic.name, forall | typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
+			// for type_name can be a qualified type name S.T, in which case only the last name in the chain needs a typedef (other names in the chain should already have one)
+			typedefTable.makeTypedef( *$3->type->leafName(), forall | typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
 			forall = false;								// reset
 		}
@@ -1936,10 +1937,8 @@
 		{ distExt( $3 ); $$ = distAttr( $2, $3 ); }		// mark all fields in list
 	| typedef_declaration ';'							// CFA
-		{ SemanticError( yylloc, "Typedef in aggregate is currently unimplemented." ); $$ = nullptr; }
 	| cfa_field_declaring_list ';'						// CFA, new style field declaration
 	| EXTENSION cfa_field_declaring_list ';'			// GCC
 		{ distExt( $2 ); $$ = $2; }						// mark all fields in list
 	| cfa_typedef_declaration ';'						// CFA
-		{ SemanticError( yylloc, "Typedef in aggregate is currently unimplemented." ); $$ = nullptr; }
 	| static_assert										// C11
 	;
@@ -1990,5 +1989,5 @@
 enum_type:												// enum
 	ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
-		{ $$ = DeclarationNode::newEnum( new string( DeclarationNode::anonymous.newName() ), $4, true )->addQualifiers( $2 ); }
+		{ $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); }
 	| ENUM attribute_list_opt no_attr_identifier
 		{ typedefTable.makeTypedef( *$3 ); }
