The Go Programming Language

Source file src/cmd/ebnflint/ebnflint.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     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	// Markers around EBNF sections in .html files
    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			// i = beginning of EBNF text
    44			i := bytes.Index(src, open)
    45			if i < 0 {
    46				break // no EBNF found - we are done
    47			}
    48			i += len(open)
    49	
    50			// write as many newlines as found in the excluded text
    51			// to maintain correct line numbers in error messages
    52			for _, ch := range src[0:i] {
    53				if ch == '\n' {
    54					buf.WriteByte('\n')
    55				}
    56			}
    57	
    58			// j = end of EBNF text (or end of source)
    59			j := bytes.Index(src[i:], close) // close marker
    60			if j < 0 {
    61				j = len(src) - i
    62			}
    63			j += i
    64	
    65			// copy EBNF text
    66			buf.Write(src[i:j])
    67	
    68			// advance
    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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.