/* -*-go-*- * * Same-fringe solver. */ package main import ( "fmt" "io" "os" ) ///-------------------------------------------------------------------------- /// Utilities. var prog = os.Args[0] func bail(msg string) { fmt.Fprintf(os.Stderr, "%s: %s\n", prog, msg) os.Exit(1) } ///-------------------------------------------------------------------------- /// Iteration protocol. /// /// A data type implements the iteration protocol by providing a method which /// simply writes its consistuent elements to a provided channel. The /// iteration machinery runs this method in a separate goroutine. // A convenient abbreviation. type any interface {} type Iterable interface { // Simply put the items to the channel CH one at a time. Iterate(ch chan<- any) } // An iterator. type Iterator <-chan any // Returns an iterator for a given iterable thing. func MakeIterator(it Iterable) Iterator { ch := make(chan any) go func () { it.Iterate(ch) close(ch) } () return ch } // Returns the next item from an iterator IT. If there is indeed an item // available, return it and true; otherwise return nil and false. func (it Iterator) Next() (any, bool) { item, anyp := <-it return item, anyp } // Answer whether the iterators return the same items in the same order. // Equality is determined using `=='. Maybe we'll do better some day. func SameIterators(ia, ib Iterator) bool { for { a, any_a := ia.Next() b, any_b := ib.Next() if !any_a { return !any_b } if a != b { break } } return false } ///-------------------------------------------------------------------------- /// Node structure. // Just a simple binary tree. type Node struct { data byte left, right *Node } // Iteration is easy. Note that recursion is fine here: this is just a // simple function. func (n *Node) Iterate(ch chan<- any) { if n == nil { return } n.left.Iterate(ch) ch <- n.data n.right.Iterate(ch) } // Parse a tree from a textual description. The syntax is simple: // // tree ::= empty | `(' tree char tree `)' // // where the ambiguity is resolved by declaring that a `(' is a tree if we're // expecting a tree. func ParseTree(s string) *Node { var parse func(int) (*Node, int) n := len(s) i := 0 parse = func(i int) (*Node, int) { if i < n && s[i] == '(' { left, i := parse(i + 1) if i >= n { bail("no data") } data := s[i] right, i := parse(i + 1) if i >= n || s[i] != ')' { bail("missing )") } return &Node { data, left, right }, i + 1 } return nil, i } t, i := parse(0) if i < n { bail("trailing junk") } return t } ///-------------------------------------------------------------------------- /// Main program. func main() { switch len(os.Args) { case 2: t := ParseTree(os.Args[1]) i := MakeIterator(t) for { item, winp := i.Next() if !winp { break } fmt.Printf("%c", item) } fmt.Printf("\n") case 3: ia := MakeIterator(ParseTree(os.Args[1])) ib := MakeIterator(ParseTree(os.Args[2])) if SameIterators(ia, ib) { io.WriteString(os.Stdout, "match\n") } else { io.WriteString(os.Stdout, "no match\n") } default: bail("bad args") } } ///----- That's all, folks --------------------------------------------------