func (g *nfa) ToDot(w io.Writer) { tw := tabwriter.NewWriter(w, 4, 8, 1, '\t', 0) w.Write([]byte("digraph {\n")) for i, _ := range g.Nodes { fmt.Fprintf(tw, "\tn%d\t[label=\"%d\"", i, i) if i == g.Start { fmt.Fprintf(tw, ",style=solid,fillcolor=green") } if _, ok := g.Accepting[i]; ok { fmt.Fprintf(tw, ",color=red") } fmt.Fprintf(tw, "];\n") } for i, node := range g.Nodes { for label, to_list := range node.Nodes { for _, to := range to_list { fmt.Fprintf(tw, "\tn%d -> n%d\t[label=%#v];\n", i, to, strconv.Quote(string(byte(label)))) } } for _, to := range node.Epsilons { fmt.Fprintf(tw, "\tn%d -> n%d\t[label=\"eps\"];\n", i, to) } } tw.Flush() fmt.Fprintf(w, "}\n") }
// fprint implements Fprint and takes a nodesSizes map for setting up the printer state. func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (written int, err error) { // redirect output through a trimmer to eliminate trailing whitespace // (Input to a tabwriter must be untrimmed since trailing tabs provide // formatting information. The tabwriter could provide trimming // functionality but no tabwriter is used when RawFormat is set.) output = &trimmer{output: output} // setup tabwriter if needed and redirect output var tw *tabwriter.Writer if cfg.Mode&RawFormat == 0 { minwidth := cfg.Tabwidth padchar := byte('\t') if cfg.Mode&UseSpaces != 0 { padchar = ' ' } twmode := tabwriter.DiscardEmptyColumns if cfg.Mode&TabIndent != 0 { minwidth = 0 twmode |= tabwriter.TabIndent } tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode) output = tw } // setup printer var p printer p.init(output, cfg, fset, nodeSizes) defer func() { written = p.written if e := recover(); e != nil { err = e.(osError).err // re-panics if it's not a local osError } }() // print node switch n := node.(type) { case ast.Expr: p.useNodeComments = true p.expr(n, ignoreMultiLine) case ast.Stmt: p.useNodeComments = true // A labeled statement will un-indent to position the // label. Set indent to 1 so we don't get indent "underflow". if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt { p.indent = 1 } p.stmt(n, false, ignoreMultiLine) case ast.Decl: p.useNodeComments = true p.decl(n, ignoreMultiLine) case ast.Spec: p.useNodeComments = true p.spec(n, 1, false, ignoreMultiLine) case *ast.File: p.comments = n.Comments p.useNodeComments = n.Comments == nil p.file(n) default: panic(osError{fmt.Errorf("printer.Fprint: unsupported node type %T", n)}) } p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) // flush tabwriter, if any if tw != nil { tw.Flush() // ignore errors } return }
// Fprint "pretty-prints" an AST node to output and returns the number // of bytes written and an error (if any) for a given configuration cfg. // Position information is interpreted relative to the file set fset. // The node type must be *ast.File, or assignment-compatible to ast.Expr, // ast.Decl, ast.Spec, or ast.Stmt. // func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) { // redirect output through a trimmer to eliminate trailing whitespace // (Input to a tabwriter must be untrimmed since trailing tabs provide // formatting information. The tabwriter could provide trimming // functionality but no tabwriter is used when RawFormat is set.) output = &trimmer{output: output} // setup tabwriter if needed and redirect output var tw *tabwriter.Writer if cfg.Mode&RawFormat == 0 { minwidth := cfg.Tabwidth padchar := byte('\t') if cfg.Mode&UseSpaces != 0 { padchar = ' ' } twmode := tabwriter.DiscardEmptyColumns if cfg.Mode&TabIndent != 0 { minwidth = 0 twmode |= tabwriter.TabIndent } tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode) output = tw } // setup printer and print node var p printer p.init(output, cfg, fset) go func() { switch n := node.(type) { case ast.Expr: p.nesting = 1 p.useNodeComments = true p.expr(n, ignoreMultiLine) case ast.Stmt: p.nesting = 1 p.useNodeComments = true // A labeled statement will un-indent to position the // label. Set indent to 1 so we don't get indent "underflow". if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt { p.indent = 1 } p.stmt(n, false, ignoreMultiLine) case ast.Decl: p.nesting = 1 p.useNodeComments = true p.decl(n, ignoreMultiLine) case ast.Spec: p.nesting = 1 p.useNodeComments = true p.spec(n, 1, false, ignoreMultiLine) case *ast.File: p.nesting = 0 p.comments = n.Comments p.useNodeComments = n.Comments == nil p.file(n) default: p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n) runtime.Goexit() } p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) p.errors <- nil // no errors }() err := <-p.errors // wait for completion of goroutine // flush tabwriter, if any if tw != nil { tw.Flush() // ignore errors } return p.written, err }
func main() { usage() tabw := tabwriter.NewWriter(os.Stdout, 1, 8, '\t', 0) io.Copy(tabw, os.Stdin) }
// Expand all variables in Vars within the given string. This does // not assume any prefix or suffix that sets off a variable from the // rest of the text, so a var of A set to HI expanded into HAPPY will // become HHIPPY. func Expand(x string) string { for k, v := range Vars { x = strings.Join(strings.Split(x, k), v) } return x } // Override the way help is displayed (not recommended) var Help = func() string { h0 := new(bytes.Buffer) h := tabwriter.NewWriter(h0, 0, 8, 2, ' ', 0) if len(opts) > 1 { fmt.Fprintln(h, "Options:") } for _, o := range opts { fmt.Fprint(h, " ") if len(o.shortnames) > 0 { for _, sn := range o.shortnames[0 : len(o.shortnames)-1] { fmt.Fprintf(h, "-%c, ", sn) } fmt.Fprintf(h, "-%c", o.shortnames[len(o.shortnames)-1]) if o.allowsArg != nil { fmt.Fprintf(h, " %s", *o.allowsArg) } } fmt.Fprintf(h, "\t")