GenHTML uint = 1 << iota;  // generate HTML
        RawFormat;  // do not use a tabwriter; if set, UseSpaces is ignored
        UseSpaces;  // use spaces instead of tabs for indentation and alignment
-       OptCommas;  // print optional commas
-       OptSemis;  // print optional semicolons
-       Reverse;  // print top-level declarations in reverse order without forward-declarations
 )
 
 
 // ----------------------------------------------------------------------------
 // Printing of common AST nodes.
 
-func (p *printer) optSemis() bool {
-       return p.mode & OptSemis != 0;
-}
-
-
 // TODO(gri) The code for printing lead and line comments
 //           should be eliminated in favor of reusing the
 //           comment intersperse mechanism above somehow.
 
 
 func (p *printer) identList(list []*ast.Ident) {
+       // convert into an expression list
+       xlist := make([]ast.Expr, len(list));
        for i, x := range list {
-               if i > 0 {
-                       p.print(token.COMMA, blank);
-               }
-               p.expr(x);
+               xlist[i] = x;
+       }
+       p.exprList(xlist, commaSep);
+}
+
+
+func (p *printer) stringList(list []*ast.StringLit) {
+       // convert into an expression list
+       xlist := make([]ast.Expr, len(list));
+       for i, x := range list {
+               xlist[i] = x;
        }
+       p.exprList(xlist, 0);
 }
 
 
-func (p *printer) exprList(list []ast.Expr) {
+type exprListMode uint;
+const (
+       blankStart exprListMode = 1 << iota;  // print a blank before the list
+       commaSep;  // elements are separated by commas
+       commaTerm;  // elements are terminated by comma
+)
+
+
+// Print a list of expressions. If the list spans multiple
+// source lines, the original line breaks are respected.
+func (p *printer) exprList(list []ast.Expr, mode exprListMode) {
+       if len(list) == 0 {
+               return;
+       }
+
+       n := len(list)-1;  // TODO 6g compiler bug - need temporary variable n
+       if list[0].Pos().Line == list[n].Pos().Line {
+               // all list entries on a single line
+               if mode & blankStart != 0 {
+                       p.print(blank);
+               }
+               for i, x := range list {
+                       if i > 0 {
+                               if mode & commaSep != 0 {
+                                       p.print(token.COMMA);
+                               }
+                               p.print(blank);
+                       }
+                       p.expr(x);
+               }
+               return;
+       }
+
+       // list entries span multiple lines;
+       // use source code positions to guide line breaks
+       p.print(+1, formfeed);
+       line := list[0].Pos().Line;
        for i, x := range list {
+               prev := line;
+               line = x.Pos().Line;
                if i > 0 {
-                       p.print(token.COMMA, blank);
+                       if mode & commaSep != 0 {
+                               p.print(token.COMMA);
+                       }
+                       if prev < line {
+                               p.print(newline);
+                       } else {
+                               p.print(blank);
+                       }
                }
                p.expr(x);
        }
+       if mode & commaTerm != 0 {
+               p.print(token.COMMA);
+       }
+       p.print(-1, formfeed);
 }
 
 
 func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isInterface bool) bool {
        if list == nil {
                // forward declaration
+               // TODO(gri) remove this logic once godoc doesn't produce field
+               //           lists that resemble forward declarations anymore
                return false;  // no {}'s
        }
 
        if len(list) == 0 {
-               p.print(blank, lbrace, token.LBRACE, rbrace, token.RBRACE);
+               // no blank between keyword and {} in this case
+               p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
                return true;  // empty list with {}'s
        }
 
                lastComment = f.Comment;
        }
 
-       if p.optSemis() {
-               p.print(token.SEMICOLON);
-       }
+       p.print(token.SEMICOLON);
        p.lineComment(lastComment);
-
-       p.print(-1, newline, rbrace, token.RBRACE);
+       p.print(-1, formfeed, rbrace, token.RBRACE);
 
        return true;  // field list with {}'s
 }
 
        case *ast.KeyValueExpr:
                p.expr(x.Key);
-               p.print(blank, x.Colon, token.COLON, blank);
+               p.print(x.Colon, token.COLON, blank);
                p.expr(x.Value);
 
        case *ast.StarExpr:
                p.print(x.Value);
 
        case *ast.StringList:
-               for i, x := range x.Strings {
-                       if i > 0 {
-                               p.print(blank);
-                       }
-                       p.expr(x);
-               }
+               p.stringList(x.Strings);
 
        case *ast.FuncLit:
                p.expr(x.Type);
        case *ast.CallExpr:
                p.expr1(x.Fun, token.HighestPrec);
                p.print(x.Lparen, token.LPAREN);
-               p.exprList(x.Args);
+               p.exprList(x.Args, commaSep);
                p.print(x.Rparen, token.RPAREN);
 
        case *ast.CompositeLit:
                p.expr1(x.Type, token.HighestPrec);
                p.print(x.Lbrace, token.LBRACE);
-               p.exprList(x.Elts);
-               if p.mode & OptCommas != 0 {
-                       p.print(token.COMMA);
-               }
+               p.exprList(x.Elts, commaSep | commaTerm);
                p.print(x.Rbrace, token.RBRACE);
 
        case *ast.Ellipsis:
                p.expr(x.Elt);
 
        case *ast.StructType:
-               if x.Fields == nil && p.mode & Reverse != 0 && p.level == 0 {
-                       // omit top-level forward declarations in reverse mode
-                       return true;
-               }
                p.print(token.STRUCT);
                optSemi = p.fieldList(x.Lbrace, x.Fields, x.Rbrace, false);
 
                p.signature(x.Params, x.Results);
 
        case *ast.InterfaceType:
-               if x.Methods == nil && p.mode & Reverse != 0 && p.level == 0 {
-                       // omit top-level forward declarations in reverse mode
-                       return true;
-               }
                p.print(token.INTERFACE);
                optSemi = p.fieldList(x.Lbrace, x.Methods, x.Rbrace, true);
 
        case *ast.MapType:
-               p.print(token.MAP, blank, token.LBRACK);
+               p.print(token.MAP, token.LBRACK);
                p.expr(x.Key);
                p.print(token.RBRACK);
                p.expr(x.Value);
                case ast.RECV:
                        p.print(token.ARROW, token.CHAN);
                case ast.SEND:
-                       p.print(token.CHAN, blank, token.ARROW);
+                       p.print(token.CHAN, token.ARROW);
                }
                p.print(blank);
                p.expr(x.Value);
                optSemi := false;
                for i, s := range list {
                        if i > 0 {
-                               if !optSemi || p.optSemis() {
-                                       // semicolon is required
+                               if !optSemi {
                                        p.print(token.SEMICOLON);
                                }
                                p.print(newline);
                        }
                        optSemi = p.stmt(s);
                }
-               if p.optSemis() {
+               if !optSemi {
                        p.print(token.SEMICOLON);
                }
                p.print(-1);
                p.print(s.Tok);
 
        case *ast.AssignStmt:
-               p.exprList(s.Lhs);
-               p.print(blank, s.TokPos, s.Tok, blank);
-               p.exprList(s.Rhs);
+               p.exprList(s.Lhs, commaSep);
+               p.print(blank, s.TokPos, s.Tok);
+               p.exprList(s.Rhs, blankStart | commaSep);
 
        case *ast.GoStmt:
                p.print(token.GO, blank);
        case *ast.ReturnStmt:
                p.print(token.RETURN);
                if s.Results != nil {
-                       p.print(blank);
-                       p.exprList(s.Results);
+                       p.exprList(s.Results, blankStart | commaSep);
                }
 
        case *ast.BranchStmt:
 
        case *ast.CaseClause:
                if s.Values != nil {
-                       p.print(token.CASE, blank);
-                       p.exprList(s.Values);
+                       p.print(token.CASE);
+                       p.exprList(s.Values, blankStart | commaSep);
                } else {
                        p.print(token.DEFAULT);
                }
 
        case *ast.TypeCaseClause:
                if s.Types != nil {
-                       p.print(token.CASE, blank);
-                       p.exprList(s.Types);
+                       p.print(token.CASE);
+                       p.exprList(s.Types, blankStart | commaSep);
                } else {
                        p.print(token.DEFAULT);
                }
                        optSemi = p.expr(s.Type);
                }
                if s.Values != nil {
-                       p.print(tab, token.ASSIGN, blank);
-                       p.exprList(s.Values);
+                       p.print(tab, token.ASSIGN);
+                       p.exprList(s.Values, blankStart | commaSep);
                        optSemi = false;
                }
                comment = s.Comment;
                        // group of parenthesized declarations
                        p.print(d.Lparen, token.LPAREN);
                        if len(d.Specs) > 0 {
-                               p.print(+1, newline);
-                               if p.mode & Reverse != 0 && p.level == 0 {
-                                       for i := len(d.Specs)-1; i >= 0; i-- {
-                                               s := d.Specs[i];
-                                               if i < len(d.Specs)-1 {
-                                                       p.print(token.SEMICOLON);
-                                                       p.lineComment(comment);
-                                                       p.print(newline);
-                                               }
-                                               comment, optSemi = p.spec(s);
-                                       }
-                               } else {
-                                       for i, s := range d.Specs {
-                                               if i > 0 {
-                                                       p.print(token.SEMICOLON);
-                                                       p.lineComment(comment);
-                                                       p.print(newline);
-                                               }
-                                               comment, optSemi = p.spec(s);
+                               p.print(+1, formfeed);
+                               for i, s := range d.Specs {
+                                       if i > 0 {
+                                               p.print(token.SEMICOLON);
+                                               p.lineComment(comment);
+                                               p.print(newline);
                                        }
+                                       comment, optSemi = p.spec(s);
                                }
-                               if p.optSemis() {
-                                       p.print(token.SEMICOLON);
-                               }
+                               p.print(token.SEMICOLON);
                                p.lineComment(comment);
-                               p.print(-1, newline);
+                               p.print(-1, formfeed);
                        }
                        p.print(d.Rparen, token.RPAREN);
                        comment = nil;  // comment was already printed
                }
 
        case *ast.FuncDecl:
-               if d.Body == nil && p.mode & Reverse != 0 {
-                       // omit forward declarations in reverse mode
-                       break;
-               }
                p.leadComment(d.Doc);
                p.print(lineTag(d.Pos()), token.FUNC, blank);
                if recv := d.Recv; recv != nil {
        p.print(src.Pos(), token.PACKAGE, blank);
        p.expr(src.Name);
 
-       if p.mode & Reverse != 0 {
-               for i := len(src.Decls)-1; i >= 0; i-- {
-                       d := src.Decls[i];
-                       p.print(newline, newline);
-                       comment, _ := p.decl(d);
-                       if p.optSemis() {
-                               p.print(token.SEMICOLON);
-                       }
-                       p.lineComment(comment);
-               }
-       } else {
-               for _, d := range src.Decls {
-                       p.print(newline, newline);
-                       comment, _ := p.decl(d);
-                       if p.optSemis() {
-                               p.print(token.SEMICOLON);
-                       }
-                       p.lineComment(comment);
-               }
+       for _, d := range src.Decls {
+               p.print(newline, newline);
+               comment, _ := p.decl(d);
+               p.lineComment(comment);
        }
 
        p.print(newline);
                        comment, _ := p.decl(n);
                        p.lineComment(comment);  // no newline at end
                case *ast.File:
-                       if mode & Reverse == 0 {
-                               // don't print comments in reverse mode
-                               p.comment = n.Comments;
-                       }
+                       p.comment = n.Comments;
                        p.file(n);
                default:
                        p.errors <- os.NewError("unsupported node type");