1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "ebnf"
10 "flag"
11 "fmt"
12 "go/scanner"
13 "go/token"
14 "io/ioutil"
15 "os"
16 "path/filepath"
17 )
18
19 var fset = token.NewFileSet()
20 var start = flag.String("start", "Start", "name of start production")
21
22 func usage() {
23 fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
24 flag.PrintDefaults()
25 os.Exit(1)
26 }
27
28
29 var (
30 open = []byte(`<pre class="ebnf">`)
31 close = []byte(`</pre>`)
32 )
33
34 func report(err os.Error) {
35 scanner.PrintError(os.Stderr, err)
36 os.Exit(1)
37 }
38
39 func extractEBNF(src []byte) []byte {
40 var buf bytes.Buffer
41
42 for {
43
44 i := bytes.Index(src, open)
45 if i < 0 {
46 break
47 }
48 i += len(open)
49
50
51
52 for _, ch := range src[0:i] {
53 if ch == '\n' {
54 buf.WriteByte('\n')
55 }
56 }
57
58
59 j := bytes.Index(src[i:], close)
60 if j < 0 {
61 j = len(src) - i
62 }
63 j += i
64
65
66 buf.Write(src[i:j])
67
68
69 src = src[j:]
70 }
71
72 return buf.Bytes()
73 }
74
75 func main() {
76 flag.Parse()
77
78 var (
79 filename string
80 src []byte
81 err os.Error
82 )
83 switch flag.NArg() {
84 case 0:
85 filename = "<stdin>"
86 src, err = ioutil.ReadAll(os.Stdin)
87 case 1:
88 filename = flag.Arg(0)
89 src, err = ioutil.ReadFile(filename)
90 default:
91 usage()
92 }
93 if err != nil {
94 report(err)
95 }
96
97 if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 {
98 src = extractEBNF(src)
99 }
100
101 grammar, err := ebnf.Parse(fset, filename, src)
102 if err != nil {
103 report(err)
104 }
105
106 if err = ebnf.Verify(fset, grammar, *start); err != nil {
107 report(err)
108 }
109 }