func gen(args []string) { flags := flag.NewFlagSet("", flag.ExitOnError) out := flags.String("o", "out.go", "output file") if len(args) == 0 { log.SetPrefix("") log.Fatal("Usage: pg gen [flags] <file>\nFlags:\n\t-o output file (instead of out.go)") } in := args[len(args)-1] flags.Parse(args[:len(args)-1]) f, err := os.Open(in) if err != nil { log.Fatalf("cannot open file: %v", err) } defer f.Close() src, err := ioutil.ReadAll(f) if err != nil { log.Fatalf("cannot read file: %v", err) } g, err := parser.Parse(src, in) if err != nil { log.Fatalf(err.Error()) } buf, err := generator.GenerateSLR(g) if err != nil { log.Fatalf(err.Error()) } if err = ioutil.WriteFile(*out, buf, 0644); err != nil { log.Fatalf("cannot write file: %v", err) } }
func TestParseErrors(t *testing.T) { errors := []struct { src string err string }{ {"E E E", `test:1:3: expected →, got E (and 1 more error)`}, {"E ->", `test:1:5: expected an expression (and 1 more error)`}, {"E -> .", `test:1:6: expected an expression`}, {"E -> T ", `test:1:8: production not terminated with . (and 1 more error)`}, {"E -> T | | D | | .", `test:1:10: expected an expression (and 4 more errors)`}, {"E -> T | | D.", `test:1:10: expected an expression (and 2 more errors)`}, {"E -> T F -> D.", `test:1:10: unexpected -> (and 3 more errors)`}, {`"foo"`, `test:1:1: expected a production, got "foo"`}, {"?", `test:1:1: syntax error: illegal character U+003F '?'`}, } for i, e := range errors { _, err := parser.Parse([]byte(e.src), "test") if err == nil { t.Errorf("%d: got no error, want %q", i, e.err) } else if err.Error() != e.err { t.Errorf("%d: got error %q, want %q", i, err.Error(), e.err) } } }
func format(args []string) { flags := flag.NewFlagSet("", flag.ExitOnError) write := flags.Bool("w", false, "write to file (instead of stdout)") if len(args) == 0 { log.SetPrefix("") log.Fatal("Usage: pg fmt [flags] <file>\nFlags:\n\t-w write to file (instead of stdout)") } in := args[len(args)-1] flags.Parse(args[:len(args)-1]) f, err := os.Open(in) if err != nil { log.Fatalf("cannot open file: %v", err) } defer f.Close() src, err := ioutil.ReadAll(f) if err != nil { log.Fatalf("cannot read file: %v", err) } g, err := parser.Parse(src, in) if err != nil { log.Fatalf(err.Error()) } if *write { f.Close() var buf bytes.Buffer if err := printer.Fprint(&buf, g); err != nil { log.Fatalf("cannot print grammar: %v", err) } if err = ioutil.WriteFile(in, buf.Bytes(), 0644); err != nil { log.Fatalf("cannot write grammar: %v", err) } return } if err := printer.Fprint(os.Stdout, g); err != nil { log.Fatalf("cannot print grammar: %v", err) } }
func TestParse(t *testing.T) { const src = `Start -> Expr. Expr → Term "+" Expr | Term "-" Expr | Term | ε. Term → Factor "*" Term | Factor "/" Term | Factor . Factor → "(" Expr ")" | Number . Number → Digit | Digit Number . Digit → "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .` expected := ast.Grammar([]*ast.Production{ { Name: &ast.Name{Name: "Start"}, Expr: &ast.Name{Name: "Expr"}, }, { Name: &ast.Name{Name: "Expr"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "+"}, &ast.Name{Name: "Expr"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Term"}, &ast.Terminal{Terminal: "-"}, &ast.Name{Name: "Expr"}, }), &ast.Name{Name: "Term"}, &ast.Epsilon{Epsilon: "ε"}, }), }, { Name: &ast.Name{Name: "Term"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "*"}, &ast.Name{Name: "Term"}, }), ast.Sequence([]ast.Expression{ &ast.Name{Name: "Factor"}, &ast.Terminal{Terminal: "/"}, &ast.Name{Name: "Term"}, }), &ast.Name{Name: "Factor"}, }), }, { Name: &ast.Name{Name: "Factor"}, Expr: ast.Alternative([]ast.Expression{ ast.Sequence([]ast.Expression{ &ast.Terminal{Terminal: "("}, &ast.Name{Name: "Expr"}, &ast.Terminal{Terminal: ")"}, }), &ast.Name{Name: "Number"}, }), }, { Name: &ast.Name{Name: "Number"}, Expr: ast.Alternative([]ast.Expression{ &ast.Name{Name: "Digit"}, ast.Sequence([]ast.Expression{ &ast.Name{Name: "Digit"}, &ast.Name{Name: "Number"}, }), }), }, { Name: &ast.Name{Name: "Digit"}, Expr: ast.Alternative([]ast.Expression{ &ast.Terminal{Terminal: "0"}, &ast.Terminal{Terminal: "1"}, &ast.Terminal{Terminal: "2"}, &ast.Terminal{Terminal: "3"}, &ast.Terminal{Terminal: "4"}, &ast.Terminal{Terminal: "5"}, &ast.Terminal{Terminal: "6"}, &ast.Terminal{Terminal: "7"}, &ast.Terminal{Terminal: "8"}, &ast.Terminal{Terminal: "9"}, }), }, }) g, err := parser.Parse([]byte(src), "test") if err != nil { t.Errorf("error: %v", err) } check(t, g, expected) }