| // 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 | |
| import ( | |
| "container/vector" | |
| "go/scanner" | |
| "go/token" | |
| "os" | |
| "strconv" | |
| ) | |
| type parser struct { | |
| scanner.ErrorVector | |
| scanner scanner.Scanner | |
| pos token.Position // token position | |
| tok token.Token // one token look-ahead | |
| lit []byte // token literal | |
| } | |
| func (p *parser) next() { | |
| p.pos, p.tok, p.lit = p.scanner.Scan() | |
| if p.tok.IsKeyword() { | |
| // TODO Should keyword mapping always happen outside scanner? | |
| // Or should there be a flag to scanner to enable keyword mapping? | |
| p.tok = token.IDENT | |
| } | |
| } | |
| func (p *parser) errorExpected(pos token.Position, msg string) { | |
| msg = "expected " + msg | |
| if pos.Offset == p.pos.Offset { | |
| // the error happened at the current position; | |
| // make the error message more specific | |
| msg += ", found '" + p.tok.String() + "'" | |
| if p.tok.IsLiteral() { | |
| msg += " " + string(p.lit) | |
| } | |
| } | |
| p.Error(pos, msg) | |
| } | |
| func (p *parser) expect(tok token.Token) token.Position { | |
| pos := p.pos | |
| if p.tok != tok { | |
| p.errorExpected(pos, "'"+tok.String()+"'") | |
| } | |
| p.next() // make progress in any case | |
| return pos | |
| } | |
| func (p *parser) parseIdentifier() *Name { | |
| pos := p.pos | |
| name := string(p.lit) | |
| p.expect(token.IDENT) | |
| return &Name{pos, name} | |
| } | |
| func (p *parser) parseToken() *Token { | |
| pos := p.pos | |
| value := "" | |
| if p.tok == token.STRING { | |
| value, _ = strconv.Unquote(string(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(token.STRING) | |
| } | |
| return &Token{pos, value} | |
| } | |
| func (p *parser) parseTerm() (x Expression) { | |
| pos := p.pos | |
| switch p.tok { | |
| case token.IDENT: | |
| x = p.parseIdentifier() | |
| case token.STRING: | |
| tok := p.parseToken() | |
| x = tok | |
| if p.tok == token.ELLIPSIS { | |
| p.next() | |
| x = &Range{tok, p.parseToken()} | |
| } | |
| case token.LPAREN: | |
| p.next() | |
| x = &Group{pos, p.parseExpression()} | |
| p.expect(token.RPAREN) | |
| case token.LBRACK: | |
| p.next() | |
| x = &Option{pos, p.parseExpression()} | |
| p.expect(token.RBRACK) | |
| case token.LBRACE: | |
| p.next() | |
| x = &Repetition{pos, p.parseExpression()} | |
| p.expect(token.RBRACE) | |
| } | |
| return x | |
| } | |
| func (p *parser) parseSequence() Expression { | |
| var list vector.Vector | |
| for x := p.parseTerm(); x != nil; x = p.parseTerm() { | |
| list.Push(x) | |
| } | |
| // no need for a sequence if list.Len() < 2 | |
| switch list.Len() { | |
| case 0: | |
| return nil | |
| case 1: | |
| return list.At(0).(Expression) | |
| } | |
| // convert list into a sequence | |
| seq := make(Sequence, list.Len()) | |
| for i := 0; i < list.Len(); i++ { | |
| seq[i] = list.At(i).(Expression) | |
| } | |
| return seq | |
| } | |
| func (p *parser) parseExpression() Expression { | |
| var list vector.Vector | |
| for { | |
| x := p.parseSequence() | |
| if x != nil { | |
| list.Push(x) | |
| } | |
| if p.tok != token.OR { | |
| break | |
| } | |
| p.next() | |
| } | |
| // no need for an Alternative node if list.Len() < 2 | |
| switch list.Len() { | |
| case 0: | |
| return nil | |
| case 1: | |
| return list.At(0).(Expression) | |
| } | |
| // convert list into an Alternative node | |
| alt := make(Alternative, list.Len()) | |
| for i := 0; i < list.Len(); i++ { | |
| alt[i] = list.At(i).(Expression) | |
| } | |
| return alt | |
| } | |
| func (p *parser) parseProduction() *Production { | |
| name := p.parseIdentifier() | |
| p.expect(token.ASSIGN) | |
| expr := p.parseExpression() | |
| p.expect(token.PERIOD) | |
| return &Production{name, expr} | |
| } | |
| func (p *parser) parse(filename string, src []byte) Grammar { | |
| // initialize parser | |
| p.ErrorVector.Reset() | |
| p.scanner.Init(filename, src, p, 0) | |
| p.next() // initializes pos, tok, lit | |
| grammar := make(Grammar) | |
| for p.tok != token.EOF { | |
| prod := p.parseProduction() | |
| name := prod.Name.String | |
| if _, 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. | |
| // | |
| func Parse(filename string, src []byte) (Grammar, os.Error) { | |
| var p parser | |
| grammar := p.parse(filename, src) | |
| return grammar, p.GetError(scanner.Sorted) | |
| } |