// Semantic analysis
        top_scope *Globals.Scope;
+       undef_types *Globals.List;
        exports *Globals.List;
 }
 
        P.S = S;
        P.Next();
        P.top_scope = Universe.scope;
+       P.undef_types = Globals.NewList();
        P.exports = Globals.NewList();
 }
 
 // ----------------------------------------------------------------------------
 // Types
 
-func (P *Parser) ParseType() *Globals.Type{
+func (P *Parser) ParseType() *Globals.Type {
        P.Trace("Type");
        
        typ := P.TryType();
        P.Trace("TypeName");
        
        if EnableSemanticTests {
+               pos := P.pos;
                obj := P.ParseQualifiedIdent(-1, "");
                typ := obj.typ;
                if obj.kind != Object.TYPE {
-                       P.Error(obj.pos, `"` + obj.ident + `" is not a type`);
+                       P.Error(pos, "qualified identifier does not denote a type");
                        typ = Universe.bad_t;
                }
                P.Ecart();
        P.Trace("PointerType");
        
        P.Expect(Scanner.MUL);
-       typ := Universe.undef_t;
-       if (EnableSemanticTests && P.tok == Scanner.IDENT && P.Lookup(P.val) == nil) {
-               // forward declaration
-               panic "UNIMPLEMENTED *forward_declared_type";
+       typ := Globals.NewType(Type.POINTER);
+       
+       if EnableSemanticTests {
+               if P.tok == Scanner.IDENT {
+                       if P.Lookup(P.val) == nil {
+                               // implicit forward declaration
+                               // TODO very problematic: in which scope should the
+                               // type object be declared? It's different if this
+                               // is inside a struct or say in a var declaration.
+                               // This code is only here for "compatibility" with 6g.
+                               pos := P.pos;
+                               obj := Globals.NewObject(pos, Object.TYPE, P.ParseIdent());
+                               obj.typ = Globals.NewType(Type.UNDEF);
+                               obj.typ.obj = obj;  // primary type object
+                               typ.elt = obj.typ;
+                               // TODO obj should be declared, but scope is not clear
+                       } else {
+                               // type name
+                               // (ParseType() doesn't permit incomplete types,
+                               // so call ParseTypeName() here)
+                               typ.elt = P.ParseTypeName();
+                       }
+               } else {
+                       typ.elt = P.ParseType();
+               }
+       
+               // collect undefined pointer types
+               if typ.elt.form == Type.UNDEF {
+                       P.undef_types.AddTyp(typ);
+               }
+               
        } else {
-               typ = Globals.NewType(Type.POINTER);
                typ.elt = P.ParseType();
        }
 
-       P.Ecart();      
+       P.Ecart();
        return typ;
 }
 
 func (P *Parser) TryType() *Globals.Type {
        P.Trace("Type (try)");
        
+       pos := P.pos;
        var typ *Globals.Type = nil;
        switch P.tok {
        case Scanner.IDENT: typ = P.ParseTypeName();
        case Scanner.MUL: typ = P.ParsePointerType();
        }
 
+       if typ != nil && typ.form == Type.UNDEF {
+               P.Error(pos, "incomplete type");
+       }
+
        P.Ecart();
        return typ;
 }
        typ := P.TryType();
        if typ != nil {
                for p := list.first; p != nil; p = p.next {
-                       p.obj.mark = exported;
+                       p.obj.exported = exported;
                        p.obj.typ = typ;  // TODO should use/have set_type()!
                }
        }
 }
 
 
-func (P *Parser) ParseConstDecl(exported bool) {
-       P.Trace("ConstDecl");
-       
-       P.Expect(Scanner.CONST);
-       if P.tok == Scanner.LPAREN {
-               P.Next();
-               for P.tok == Scanner.IDENT {
-                       P.ParseConstSpec(exported);
-                       if P.tok != Scanner.RPAREN {
-                               P.Expect(Scanner.SEMICOLON);
-                       }
-               }
-               P.Next();
-       } else {
-               P.ParseConstSpec(exported);
-       }
-       
-       P.Ecart();
-}
-
-
 func (P *Parser) ParseTypeSpec(exported bool) {
        P.Trace("TypeSpec");
        
        ident := P.ParseIdent();
        obj := P.top_scope.Lookup(ident);  // only lookup in top scope!
        if obj != nil {
-               // ok if forward declared type
+               // name already declared - ok if forward declared type
                if obj.kind != Object.TYPE || obj.typ.form != Type.UNDEF {
                        // TODO use obj.pos to refer to decl pos in error msg!
                        P.Error(pos, `"` + ident + `" is declared already`);
                }
        } else {
                obj = Globals.NewObject(pos, Object.TYPE, ident);
-               obj.mark = exported;
-               obj.typ = Universe.undef_t;  // TODO fix this
-               P.top_scope.Insert(obj);
+               obj.exported = exported;
+               obj.typ = Globals.NewType(Type.UNDEF);
+               obj.typ.obj = obj;  // primary type object
+               P.Declare(obj);
        }
        
-       typ := P.TryType();  // no type if we have a forward decl
+       typ := P.TryType();  // nil if we have an explicit forward declaration
+
        if typ != nil {
-               // TODO what about the name of incomplete types?
-               obj.typ = typ;  // TODO should use/have set_typ()!
+               obj.typ = typ;
                if typ.obj == nil {
                        typ.obj = obj;  // primary type object
                }
 }
 
 
-func (P *Parser) ParseTypeDecl(exported bool) {
-       P.Trace("TypeDecl");
-       
-       P.Expect(Scanner.TYPE);
-       if P.tok == Scanner.LPAREN {
-               P.Next();
-               for P.tok == Scanner.IDENT {
-                       P.ParseTypeSpec(exported);
-                       if P.tok != Scanner.RPAREN {
-                               P.Expect(Scanner.SEMICOLON);
-                       }
-               }
-               P.Next();
-       } else {
-               P.ParseTypeSpec(exported);
-       }
-       
-       P.Ecart();
-}
-
-
 func (P *Parser) ParseVarSpec(exported bool) {
        P.Trace("VarSpec");
        
 }
 
 
-func (P *Parser) ParseVarDecl(exported bool) {
-       P.Trace("VarDecl");
+// TODO With method variables, we wouldn't need this dispatch function.
+func (P *Parser) ParseSpec(exported bool, keyword int) {
+       switch keyword {
+       case Scanner.CONST: P.ParseConstSpec(exported);
+       case Scanner.TYPE: P.ParseTypeSpec(exported);
+       case Scanner.VAR: P.ParseVarSpec(exported);
+       default: panic "UNREACHABLE";
+       }
+}
+
+
+func (P *Parser) ParseDecl(exported bool, keyword int) {
+       P.Trace("Decl");
        
-       P.Expect(Scanner.VAR);
+       P.Expect(keyword);
        if P.tok == Scanner.LPAREN {
                P.Next();
                for P.tok == Scanner.IDENT {
-                       P.ParseVarSpec(exported);
+                       P.ParseSpec(exported, keyword);
                        if P.tok != Scanner.RPAREN {
                                P.Expect(Scanner.SEMICOLON);
                        }
                }
                P.Next();
        } else {
-               P.ParseVarSpec(exported);
+               P.ParseSpec(exported, keyword);
        }
        
        P.Ecart();
                exported = true;
        }
        switch P.tok {
-       case Scanner.CONST:
-               P.ParseConstDecl(exported);
-       case Scanner.TYPE:
-               P.ParseTypeDecl(exported);
-       case Scanner.VAR:
-               P.ParseVarDecl(exported);
+       case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
+               P.ParseDecl(exported, P.tok);
        case Scanner.FUNC:
                P.ParseFuncDecl(exported);
        case Scanner.EXPORT:
 // ----------------------------------------------------------------------------
 // Program
 
+func (P *Parser) ResolveUndefTypes() {
+       if !EnableSemanticTests {
+               return;
+       }
+       
+       for p := P.undef_types.first; p != nil; p = p.next {
+               typ := p.typ;
+               if typ.form != Type.POINTER {
+                       panic "unresolved types should be pointers only";
+               }
+               if typ.elt.form != Type.UNDEF {
+                       panic "unresolved pointer should point to undefined type";
+               }
+               obj := typ.elt.obj;
+               typ.elt = obj.typ;
+               if typ.elt.form == Type.UNDEF {
+                       P.Error(obj.pos, `"` + obj.ident + `" is not declared`);
+               }
+       }
+}
+
+
 func (P *Parser) MarkExports() {
        if !EnableSemanticTests {
                return;
        for p := P.exports.first; p != nil; p = p.next {
                obj := scope.Lookup(p.str);
                if obj != nil {
-                       obj.mark = true;
+                       obj.exported = true;
                        // For now we export deep
                        // TODO this should change eventually - we need selective export
                        if obj.kind == Object.TYPE {
                                if typ.form == Type.STRUCT || typ.form == Type.INTERFACE {
                                        scope := typ.scope;
                                        for p := scope.entries.first; p != nil; p = p.next {
-                                               p.obj.mark = true;
+                                               p.obj.exported = true;
                                        }
                                }
                        }
                        P.Optional(Scanner.SEMICOLON);
                }
                
+               P.ResolveUndefTypes();
                P.MarkExports();
                P.CloseScope();
        }