// multaut displays a multi-NFA and multi-DFA func multaut(w http.ResponseWriter, r *http.Request) { // must read all input before writing anything exprlist := getexprs(r) nx := len(exprlist) // parse and echo the input treelist := make([]rx.Node, 0, nx) putheader(w, r, "Multi-expression Automata") fmt.Fprintf(w, "<P class=xleading>%d expressions:\n", nx) for i, s := range exprlist { fmt.Fprintf(w, "<BR><B>%c:</B> %s\n", rx.AcceptLabels[i], hx(s)) tree, err := rx.Parse(s) if !showerror(w, err) { treelist = append(treelist, rx.Augment(tree, i)) } } if nx > 0 && len(treelist) == nx { // if no errors dfa := rx.MultiDFA(treelist) // build combined DFA dmin := dfa.Minimize() showaut(w, dmin, exprlist) } putfooter(w, r) }
// load expressions, returning list and augmented parse tree list func load(filename string) []*RegEx { elist := make([]*RegEx, 0) // expression structure list rx.LoadExpressions(filename, func(l *rx.RegExParsed) { if l.Tree != nil { // if a real expression e := &RegEx{} e.index = len(elist) e.cnum = len(elist) e.RegExParsed = *l // save parse tree e.examples = genex(l.Tree) // gen examples unaugmented t := rx.Augment(l.Tree, e.index) e.dfa = rx.BuildDFA(t) // build DFA if verbose { fmt.Println() showexpr(e) // show details of expr showexamples(e) // show its examples } elist = append(elist, e) } }) if verbose { fmt.Printf("\nloaded %d expression(s), ignored %d more\n", rx.InputRegExCount, rx.InputErrorCount) } return elist }
// details responds to an inspection request for a single expression func details(w http.ResponseWriter, r *http.Request) { field := fmt.Sprintf("v%d", baseExpr) expr := r.FormValue(field) // must read before any writing expr = strings.TrimSpace(expr) // trim leading/trailing blanks putheader(w, r, "Inspect Expression") tree, err := rx.Parse(expr) if err == nil { fmt.Fprintf(w, "<P>Regular Expression: %s\n", hx(expr)) // must print (or at least stringize) tree before augmenting fmt.Fprintf(w, "<P>Initial Parse Tree: %s\n", hx(tree)) augt := rx.Augment(tree, 0) dfa := rx.BuildDFA(augt) dmin := dfa.Minimize() fmt.Fprintf(w, "<P>Augmented Tree: %s\n", hx(augt)) fmt.Fprintf(w, "<h2>Examples</h2>\n<P>") genexamples(w, tree, 0) genexamples(w, tree, 1) genexamples(w, tree, 2) genexamples(w, tree, 3) genexamples(w, tree, 5) genexamples(w, tree, 8) showaut(w, dmin, []string{expr}) } else { fmt.Fprint(w, "<P>") showerror(w, err) } fmt.Fprint(w, "<h2>Try another?</h2>") putform(w, "/details", "Enter a regular expression:", 1, []string{expr}, 0, nil) putfooter(w, r) }
func main() { // get command line options nways := 1 if len(os.Args) == 3 { nways, _ = strconv.Atoi(os.Args[2]) } if len(os.Args) < 2 || len(os.Args) > 3 || nways < 1 { log.Fatal("usage: rxtime exprfile [n]") } filename := os.Args[1] // load expressions from file exprs := rx.LoadExpressions(filename, nil) nexprs := len(exprs) if nways < 1 || nways > nexprs { log.Fatal(fmt.Sprintf( "cannot combine %d expressions(s) in %d way(s)", nexprs, nways)) } // record individual complexity scores and make augmented parse trees cx := make([]int, nexprs) for i, t := range exprs { cx[i] = rx.ComplexityScore(t.Tree) t.Tree = rx.Augment(t.Tree, i) } // initialize index list for first combination {0,1,2...} xlist := make([]int, nways) for i := range xlist { xlist[i] = i } // try all possible n-way combinations by varying the index list tlist := make([]rx.Node, nways) for xlist != nil { for i, x := range xlist { tlist[i] = exprs[x].Tree } _ = rxsys.Interval() // reset timer dfa1 := rx.MultiDFA(tlist) // make DFA t1 := rxsys.Interval().Seconds() // measure time dfa2 := dfa1.Minimize() // minimize DFA t2 := rxsys.Interval().Seconds() // measure time fmt.Printf("%6d %6d %8.3f %8.3f", len(dfa1.Dstates), len(dfa2.Dstates), t1, t2) if nways == 1 { fmt.Printf(" %6d", cx[xlist[0]]) } fmt.Print(" {") for _, x := range xlist { fmt.Printf(" %d", x) } fmt.Print(" }\n") xlist = advance(xlist, nexprs) // get next combination } }
// lpxc -- list and parse expressions for comparison, returning augtree list func lpxc(w http.ResponseWriter, exprlist []string) []rx.Node { treelist := make([]rx.Node, 0) for i, s := range exprlist { fmt.Fprintf(w, "<SPAN class=%s><BR><B>%c:</B> %s</SPAN>\n", colorname(i), rx.AcceptLabels[i], hx(s)) tree, err := rx.Parse(s) if !showerror(w, err) { treelist = append(treelist, rx.Augment(tree, i)) } } return treelist }
func main() { rflag := flag.Bool("R", false, "reproducible output") flag.Parse() if *rflag { rand.Seed(0) } else { rand.Seed(int64(time.Now().Nanosecond())) } // load and process regexps exprs := make([]*RegEx, 0) tlist := make([]rx.Node, 0) rx.LoadExpressions(rx.OneInputFile(), func(l *rx.RegExParsed) { if l.Err != nil { fmt.Fprintln(os.Stderr, l.Err) } if l.Tree != nil { atree := rx.Augment(l.Tree, len(tlist)) tlist = append(tlist, atree) exprs = append(exprs, &RegEx{len(exprs), l.Expr}) } }) // echo the input with index numbers fmt.Print(`{"Expressions":`) rx.Jlist(os.Stdout, exprs) fmt.Println(",") // build the DFA and produce examples synthx := rx.MultiDFA(tlist).Synthesize() // convert into expected form with int array replacing BitSet results := make([]*Example, 0, len(synthx)) for _, x := range synthx { results = append(results, &Example{x.State, x.RXset.Members(), x.Example}) } // output the array of synthesized examples fmt.Print(`"Examples":`) rx.Jlist(os.Stdout, results) fmt.Println("}") }
// load expressions, returning list and augmented parse tree list func load(filename string) ([]*rx.RegExParsed, []rx.Node) { errcount := 0 // error count exprs := make([]*rx.RegExParsed, 0) // expression structure list trees := make([]rx.Node, 0) // augmented parse tree list rx.LoadExpressions(filename, func(l *rx.RegExParsed) { if l.Tree != nil { // if a real expression augtree := rx.Augment(l.Tree, len(trees)) trees = append(trees, augtree) exprs = append(exprs, l) } else if l.Err != nil { // if erroneous errcount++ } // else is just a comment }) fmt.Printf("%d expressions loaded\n", len(exprs)) if errcount != 0 { fmt.Printf("(%d improper expressions ignored)\n", errcount) } return exprs, trees }
// draw produces a Dot file for rendering a DFA or NFA in the user's browser. func draw(w http.ResponseWriter, r *http.Request, which string) { exprlist := getexprs(r) // must load data before writing anything nx := len(exprlist) putheader(w, r, which+" Graph") // write page header fmt.Fprintln(w, "<P class=xleading>") treelist := make([]rx.Node, 0) for i, e := range exprlist { if nx > 1 { fmt.Fprintf(w, "%c. ", rx.AcceptLabels[i]) } fmt.Fprintf(w, "%s<BR>\n", hx(e)) tree, err := rx.Parse(e) if !showerror(w, err) { treelist = append(treelist, rx.Augment(tree, i)) } } if nx > 0 && len(treelist) == nx { // if no errors dfa := rx.MultiDFA(treelist) // build combined DFA dmin := dfa.Minimize() // minimize it fmt.Fprintln(w, `<script type="text/vnd.graphviz" id="graph">`) if which == "NFA" { dmin.GraphNFA(w, "") } else if nx == 1 { dmin.ToDot(w, "", "") } else { which = "Multi" dmin.ToDot(w, "", rx.AcceptLabels) } fmt.Fprintln(w, `</script>`) tDraw.Execute(w, which) } putfooter(w, r) }
// refexamine advertises the Examine page func refexamine(w http.ResponseWriter) { fmt.Fprint(w, ` <P> On the <A HREF="/examine">Examine</A> page you can enter a regular expression to generate several kinds of data: parse trees, synthetic examples, and the automata state lists. Links from there produce diagrams of either the <A HREF="http://en.wikipedia.org/wiki/Nondeterministic_finite_automaton">NFA</A> or <A HREF="http://en.wikipedia.org/wiki/Deterministic_finite_automaton">DFA</A> for the language. `) tree, _ := rx.Parse(HomeExample) augt := rx.Augment(tree, 0) fmt.Fprintf(w, ` <DIV CLASS=inblock>Regular Expression: %s <BR>Augmented Parse Tree: %s <BR class=xleading>Examples:<BR>`, hx(HomeExample), hx(augt)) genexamples(w, augt, 0) genexamples(w, augt, 2) genexamples(w, augt, 4) fmt.Fprintln(w, `<DIV class="rside smaller">`) genexam(w, "submit this example to see full output", HomeExample) fmt.Fprintln(w, `</DIV></DIV>`) }
// load slurps up expressions, returning list and augmented parse tree list func load() ([]*rx.RegExParsed, []rx.Node) { exprs := make([]*rx.RegExParsed, 0) // expression structure list trees := make([]rx.Node, 0) // augmented parse tree list rx.LoadFromScanner(input, func(l *rx.RegExParsed) { echo(l, len(exprs)) if l.Tree != nil { // if a real expression image := fmt.Sprintf("%s", l.Tree) cx := rx.ComplexityScore(l.Tree) augtree := rx.Augment(l.Tree, len(trees)) trees = append(trees, augtree) exprs = append(exprs, l) if *opt['i'] { individual(l, cx, len(exprs), image, augtree) } } }) babble("%d expression(s) loaded\n", rx.InputRegExCount) if rx.InputErrorCount != 0 && (!errsilent || verbose) { fmt.Printf("(%d expression(s) rejected)\n", rx.InputErrorCount) } return exprs, trees }
func main() { args := os.Args if len(args) != 3 { log.Fatal("usage: rxx efile sfile") } ename := args[1] sfile := rx.MkScanner(args[2]) labels := "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" elist := make([]tester, 0, len(labels)) // load and compile regexps fmt.Println() tlist := make([]rx.Node, 0) // list of valid parse trees rx.LoadExpressions(ename, func(x *rx.RegExParsed) { spec := x.Expr ptree := x.Tree err := x.Err if err != nil { fmt.Printf("ERR %s\n", spec) elist = append(elist, tester{" ", spec, nil, 0}) } else if ptree == nil { fmt.Printf(" %s\n", spec) elist = append(elist, tester{" ", spec, nil, 0}) } else { i := len(tlist) if i >= len(labels) { log.Fatal("too many regular expressions") } label := string(labels[i : i+1]) fmt.Printf("%s: %s\n", label, spec) atree := rx.Augment(ptree, len(tlist)) tlist = append(tlist, atree) elist = append(elist, tester{label, spec, ptree, i}) } }) dfa := rx.MultiDFA(tlist) _ = dfa.Minimize() // should have no effect _ = dfa.Minimize() // should again have no effect dfa = dfa.Minimize() // not necessary, but a good stress test dfa = dfa.Minimize() // especially if done more than once // read and test candidate strings fmt.Println() for sfile.Scan() { s := string(sfile.Bytes()) results := dfa.Accepts(s) if results == nil { results = &rx.BitSet{} } for _, e := range elist { if e.tree == nil { fmt.Print(" ") } else { if results.Test(e.index) { fmt.Print(e.label) } else { fmt.Print("-") } } } fmt.Printf(" %s\n", s) } rx.CkErr(sfile.Err()) }