aboutsummaryrefslogtreecommitdiff
path: root/spec/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'spec/parser.go')
-rw-r--r--spec/parser.go64
1 files changed, 60 insertions, 4 deletions
diff --git a/spec/parser.go b/spec/parser.go
index 3e86779..1654752 100644
--- a/spec/parser.go
+++ b/spec/parser.go
@@ -9,12 +9,19 @@ type RootNode struct {
}
type ProductionNode struct {
- LHS string
- RHS []*AlternativeNode
+ Modifier *ModifierNode
+ LHS string
+ RHS []*AlternativeNode
+}
+
+type ModifierNode struct {
+ Name string
+ Parameter string
}
type AlternativeNode struct {
Elements []*ElementNode
+ Action *ActionNode
}
type ElementNode struct {
@@ -22,6 +29,11 @@ type ElementNode struct {
Pattern string
}
+type ActionNode struct {
+ Name string
+ Parameter string
+}
+
func raiseSyntaxError(synErr *SyntaxError) {
panic(synErr)
}
@@ -87,13 +99,34 @@ func (p *parser) parseProduction() *ProductionNode {
if p.consume(tokenKindEOF) {
return nil
}
+
+ var mod *ModifierNode
+ if p.consume(tokenKindModifierMarker) {
+ if !p.consume(tokenKindID) {
+ raiseSyntaxError(synErrNoModifierName)
+ }
+ name := p.lastTok.text
+
+ var param string
+ if p.consume(tokenKindID) {
+ param = p.lastTok.text
+ }
+
+ mod = &ModifierNode{
+ Name: name,
+ Parameter: param,
+ }
+ }
+
if !p.consume(tokenKindID) {
raiseSyntaxError(synErrNoProductionName)
}
lhs := p.lastTok.text
+
if !p.consume(tokenKindColon) {
raiseSyntaxError(synErrNoColon)
}
+
alt := p.parseAlternative()
rhs := []*AlternativeNode{alt}
for {
@@ -103,12 +136,15 @@ func (p *parser) parseProduction() *ProductionNode {
alt := p.parseAlternative()
rhs = append(rhs, alt)
}
+
if !p.consume(tokenKindSemicolon) {
raiseSyntaxError(synErrNoSemicolon)
}
+
return &ProductionNode{
- LHS: lhs,
- RHS: rhs,
+ Modifier: mod,
+ LHS: lhs,
+ RHS: rhs,
}
}
@@ -121,8 +157,28 @@ func (p *parser) parseAlternative() *AlternativeNode {
}
elems = append(elems, elem)
}
+
+ var act *ActionNode
+ if p.consume(tokenKindActionLeader) {
+ if !p.consume(tokenKindID) {
+ raiseSyntaxError(synErrNoActionName)
+ }
+ name := p.lastTok.text
+
+ var param string
+ if p.consume(tokenKindID) {
+ param = p.lastTok.text
+ }
+
+ act = &ActionNode{
+ Name: name,
+ Parameter: param,
+ }
+ }
+
return &AlternativeNode{
Elements: elems,
+ Action: act,
}
}