aboutsummaryrefslogtreecommitdiff
path: root/grammar/grammar.go
diff options
context:
space:
mode:
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r--grammar/grammar.go21
1 files changed, 20 insertions, 1 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go
index b405429..4e5b3b2 100644
--- a/grammar/grammar.go
+++ b/grammar/grammar.go
@@ -701,6 +701,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
for _, alt := range prod.RHS {
altSyms := make([]symbol, len(alt.Elements))
offsets := map[string]int{}
+ ambiguousIDOffsets := map[string]struct{}{}
for i, elem := range alt.Elements {
var sym symbol
if elem.Pattern != "" {
@@ -756,7 +757,15 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
// A symbol having a label can be specified by both the label and the symbol name.
// So record the symbol's position, whether or not it has a label.
if elem.ID != "" {
- offsets[elem.ID] = i
+ if _, exist := offsets[elem.ID]; exist {
+ // When the same symbol appears multiple times in an alternative, the symbol is ambiguous. When we need
+ // to specify the symbol in a directive, we cannot use the name of the ambiguous symbol. Instead, specify
+ // a label to resolve the ambiguity.
+ delete(offsets, elem.ID)
+ ambiguousIDOffsets[elem.ID] = struct{}{}
+ } else {
+ offsets[elem.ID] = i
+ }
}
}
@@ -842,6 +851,16 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
continue LOOP_RHS
}
+ if _, ambiguous := ambiguousIDOffsets[param.ID]; ambiguous {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrAmbiguousElem,
+ Detail: fmt.Sprintf("'%v' is ambiguous", param.ID),
+ Row: param.Pos.Row,
+ Col: param.Pos.Col,
+ })
+ continue LOOP_RHS
+ }
+
offset, ok := offsets[param.ID]
if !ok {
b.errs = append(b.errs, &verr.SpecError{