URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [exp/] [ebnf/] [ebnf.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package ebnf is a library for EBNF grammars. The input is text ([]byte)// satisfying the following grammar (represented itself in EBNF)://// Production = name "=" [ Expression ] "." .// Expression = Alternative { "|" Alternative } .// Alternative = Term { Term } .// Term = name | token [ "…" token ] | Group | Option | Repetition .// Group = "(" Expression ")" .// Option = "[" Expression "]" .// Repetition = "{" Expression "}" .//// A name is a Go identifier, a token is a Go string, and comments// and white space follow the same rules as for the Go language.// Production names starting with an uppercase Unicode letter denote// non-terminal productions (i.e., productions which allow white-space// and comments between tokens); all other production names denote// lexical productions.//package ebnfimport ("errors""fmt""text/scanner""unicode""unicode/utf8")// ----------------------------------------------------------------------------// Error handlingtype errorList []errorfunc (list errorList) Err() error {if len(list) == 0 {return nil}return list}func (list errorList) Error() string {switch len(list) {case 0:return "no errors"case 1:return list[0].Error()}return fmt.Sprintf("%s (and %d more errors)", list[0], len(list)-1)}func newError(pos scanner.Position, msg string) error {return errors.New(fmt.Sprintf("%s: %s", pos, msg))}// ----------------------------------------------------------------------------// Internal representationtype (// An Expression node represents a production expression.Expression interface {// Pos is the position of the first character of the syntactic constructPos() scanner.Position}// An Alternative node represents a non-empty list of alternative expressions.Alternative []Expression // x | y | z// A Sequence node represents a non-empty list of sequential expressions.Sequence []Expression // x y z// A Name node represents a production name.Name struct {StringPos scanner.PositionString string}// A Token node represents a literal.Token struct {StringPos scanner.PositionString string}// A List node represents a range of characters.Range struct {Begin, End *Token // begin ... end}// A Group node represents a grouped expression.Group struct {Lparen scanner.PositionBody Expression // (body)}// An Option node represents an optional expression.Option struct {Lbrack scanner.PositionBody Expression // [body]}// A Repetition node represents a repeated expression.Repetition struct {Lbrace scanner.PositionBody Expression // {body}}// A Production node represents an EBNF production.Production struct {Name *NameExpr Expression}// A Bad node stands for pieces of source code that lead to a parse error.Bad struct {TokPos scanner.PositionError string // parser error message}// A Grammar is a set of EBNF productions. The map// is indexed by production name.//Grammar map[string]*Production)func (x Alternative) Pos() scanner.Position { return x[0].Pos() } // the parser always generates non-empty Alternativefunc (x Sequence) Pos() scanner.Position { return x[0].Pos() } // the parser always generates non-empty Sequencesfunc (x *Name) Pos() scanner.Position { return x.StringPos }func (x *Token) Pos() scanner.Position { return x.StringPos }func (x *Range) Pos() scanner.Position { return x.Begin.Pos() }func (x *Group) Pos() scanner.Position { return x.Lparen }func (x *Option) Pos() scanner.Position { return x.Lbrack }func (x *Repetition) Pos() scanner.Position { return x.Lbrace }func (x *Production) Pos() scanner.Position { return x.Name.Pos() }func (x *Bad) Pos() scanner.Position { return x.TokPos }// ----------------------------------------------------------------------------// Grammar verificationfunc isLexical(name string) bool {ch, _ := utf8.DecodeRuneInString(name)return !unicode.IsUpper(ch)}type verifier struct {errors errorListworklist []*Productionreached Grammar // set of productions reached from (and including) the root productiongrammar Grammar}func (v *verifier) error(pos scanner.Position, msg string) {v.errors = append(v.errors, newError(pos, msg))}func (v *verifier) push(prod *Production) {name := prod.Name.Stringif _, found := v.reached[name]; !found {v.worklist = append(v.worklist, prod)v.reached[name] = prod}}func (v *verifier) verifyChar(x *Token) rune {s := x.Stringif utf8.RuneCountInString(s) != 1 {v.error(x.Pos(), "single char expected, found "+s)return 0}ch, _ := utf8.DecodeRuneInString(s)return ch}func (v *verifier) verifyExpr(expr Expression, lexical bool) {switch x := expr.(type) {case nil:// empty expressioncase Alternative:for _, e := range x {v.verifyExpr(e, lexical)}case Sequence:for _, e := range x {v.verifyExpr(e, lexical)}case *Name:// a production with this name must exist;// add it to the worklist if not yet processedif prod, found := v.grammar[x.String]; found {v.push(prod)} else {v.error(x.Pos(), "missing production "+x.String)}// within a lexical production references// to non-lexical productions are invalidif lexical && !isLexical(x.String) {v.error(x.Pos(), "reference to non-lexical production "+x.String)}case *Token:// nothing to do for nowcase *Range:i := v.verifyChar(x.Begin)j := v.verifyChar(x.End)if i >= j {v.error(x.Pos(), "decreasing character range")}case *Group:v.verifyExpr(x.Body, lexical)case *Option:v.verifyExpr(x.Body, lexical)case *Repetition:v.verifyExpr(x.Body, lexical)case *Bad:v.error(x.Pos(), x.Error)default:panic(fmt.Sprintf("internal error: unexpected type %T", expr))}}func (v *verifier) verify(grammar Grammar, start string) {// find root productionroot, found := grammar[start]if !found {var noPos scanner.Positionv.error(noPos, "no start production "+start)return}// initialize verifierv.worklist = v.worklist[0:0]v.reached = make(Grammar)v.grammar = grammar// work through the worklistv.push(root)for {n := len(v.worklist) - 1if n < 0 {break}prod := v.worklist[n]v.worklist = v.worklist[0:n]v.verifyExpr(prod.Expr, isLexical(prod.Name.String))}// check if all productions were reachedif len(v.reached) < len(v.grammar) {for name, prod := range v.grammar {if _, found := v.reached[name]; !found {v.error(prod.Pos(), name+" is unreachable")}}}}// Verify checks that:// - all productions used are defined// - all productions defined are used when beginning at start// - lexical productions refer only to other lexical productions//// Position information is interpreted relative to the file set fset.//func Verify(grammar Grammar, start string) error {var v verifierv.verify(grammar, start)return v.errors.Err()}
