URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [exp/] [ebnf/] [parser.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 ebnfimport ("io""strconv""text/scanner")type parser struct {errors errorListscanner scanner.Scannerpos scanner.Position // token positiontok rune // one token look-aheadlit string // token literal}func (p *parser) next() {p.tok = p.scanner.Scan()p.pos = p.scanner.Positionp.lit = p.scanner.TokenText()}func (p *parser) error(pos scanner.Position, msg string) {p.errors = append(p.errors, newError(pos, msg))}func (p *parser) errorExpected(pos scanner.Position, msg string) {msg = `expected "` + msg + `"`if pos.Offset == p.pos.Offset {// the error happened at the current position;// make the error message more specificmsg += ", found " + scanner.TokenString(p.tok)if p.tok < 0 {msg += " " + p.lit}}p.error(pos, msg)}func (p *parser) expect(tok rune) scanner.Position {pos := p.posif p.tok != tok {p.errorExpected(pos, scanner.TokenString(tok))}p.next() // make progress in any casereturn pos}func (p *parser) parseIdentifier() *Name {pos := p.posname := p.litp.expect(scanner.Ident)return &Name{pos, name}}func (p *parser) parseToken() *Token {pos := p.posvalue := ""if p.tok == scanner.String {value, _ = strconv.Unquote(p.lit)// Unquote may fail with an error, but only if the scanner found// an illegal string in the first place. In this case the error// has already been reported.p.next()} else {p.expect(scanner.String)}return &Token{pos, value}}// ParseTerm returns nil if no term was found.func (p *parser) parseTerm() (x Expression) {pos := p.posswitch p.tok {case scanner.Ident:x = p.parseIdentifier()case scanner.String:tok := p.parseToken()x = tokconst ellipsis = '…' // U+2026, the horizontal ellipsis characterif p.tok == ellipsis {p.next()x = &Range{tok, p.parseToken()}}case '(':p.next()x = &Group{pos, p.parseExpression()}p.expect(')')case '[':p.next()x = &Option{pos, p.parseExpression()}p.expect(']')case '{':p.next()x = &Repetition{pos, p.parseExpression()}p.expect('}')}return x}func (p *parser) parseSequence() Expression {var list Sequencefor x := p.parseTerm(); x != nil; x = p.parseTerm() {list = append(list, x)}// no need for a sequence if list.Len() < 2switch len(list) {case 0:p.errorExpected(p.pos, "term")return &Bad{p.pos, "term expected"}case 1:return list[0]}return list}func (p *parser) parseExpression() Expression {var list Alternativefor {list = append(list, p.parseSequence())if p.tok != '|' {break}p.next()}// len(list) > 0// no need for an Alternative node if list.Len() < 2if len(list) == 1 {return list[0]}return list}func (p *parser) parseProduction() *Production {name := p.parseIdentifier()p.expect('=')var expr Expressionif p.tok != '.' {expr = p.parseExpression()}p.expect('.')return &Production{name, expr}}func (p *parser) parse(filename string, src io.Reader) Grammar {p.scanner.Init(src)p.scanner.Filename = filenamep.next() // initializes pos, tok, litgrammar := make(Grammar)for p.tok != scanner.EOF {prod := p.parseProduction()name := prod.Name.Stringif _, found := grammar[name]; !found {grammar[name] = prod} else {p.error(prod.Pos(), name+" declared already")}}return grammar}// Parse parses a set of EBNF productions from source src.// It returns a set of productions. Errors are reported// for incorrect syntax and if a production is declared// more than once; the filename is used only for error// positions.//func Parse(filename string, src io.Reader) (Grammar, error) {var p parsergrammar := p.parse(filename, src)return grammar, p.errors.Err()}
