diff options
Diffstat (limited to 'spec/parser.go')
-rw-r--r-- | spec/parser.go | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/spec/parser.go b/spec/parser.go index 1654752..a2c41f8 100644 --- a/spec/parser.go +++ b/spec/parser.go @@ -6,6 +6,7 @@ import ( type RootNode struct { Productions []*ProductionNode + Fragments []*FragmentNode } type ProductionNode struct { @@ -34,6 +35,11 @@ type ActionNode struct { Parameter string } +type FragmentNode struct { + LHS string + RHS string +} + func raiseSyntaxError(synErr *SyntaxError) { panic(synErr) } @@ -78,21 +84,60 @@ func (p *parser) parse() (root *RootNode, retErr error) { } func (p *parser) parseRoot() *RootNode { - prod := p.parseProduction() - if prod == nil { - raiseSyntaxError(synErrNoProduction) - } - root := &RootNode{ - Productions: []*ProductionNode{prod}, - } + var prods []*ProductionNode + var fragments []*FragmentNode for { + fragment := p.parseFragment() + if fragment != nil { + fragments = append(fragments, fragment) + continue + } + prod := p.parseProduction() - if prod == nil { - break + if prod != nil { + prods = append(prods, prod) + continue } - root.Productions = append(root.Productions, prod) + + break + } + if len(prods) == 0 { + raiseSyntaxError(synErrNoProduction) + } + + return &RootNode{ + Productions: prods, + Fragments: fragments, + } +} + +func (p *parser) parseFragment() *FragmentNode { + if !p.consume(tokenKindKWFragment) { + return nil + } + + if !p.consume(tokenKindID) { + raiseSyntaxError(synErrNoProductionName) + } + lhs := p.lastTok.text + + if !p.consume(tokenKindColon) { + raiseSyntaxError(synErrNoColon) + } + + if !p.consume(tokenKindTerminalPattern) { + raiseSyntaxError(synErrFragmentNoPattern) + } + rhs := p.lastTok.text + + if !p.consume(tokenKindSemicolon) { + raiseSyntaxError(synErrNoSemicolon) + } + + return &FragmentNode{ + LHS: lhs, + RHS: rhs, } - return root } func (p *parser) parseProduction() *ProductionNode { |