aboutsummaryrefslogtreecommitdiff
path: root/grammar/grammar.go
diff options
context:
space:
mode:
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r--grammar/grammar.go37
1 files changed, 37 insertions, 0 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go
index 7cd2409..6130e55 100644
--- a/grammar/grammar.go
+++ b/grammar/grammar.go
@@ -3,6 +3,7 @@ package grammar
import (
"fmt"
"os"
+ "strings"
mlcompiler "github.com/nihei9/maleeni/compiler"
mlspec "github.com/nihei9/maleeni/spec"
@@ -343,6 +344,42 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
if err != nil {
return nil, err
}
+ if _, exist := prods.findByID(p.id); exist {
+ // Report the line number of a duplicate alternative.
+ // When the alternative is empty, we report the position of its LHS.
+ var row int
+ if len(alt.Elements) > 0 {
+ row = alt.Elements[0].Pos.Row
+ } else {
+ row = prod.Pos.Row
+ }
+
+ var detail string
+ {
+ var b strings.Builder
+ fmt.Fprintf(&b, "%v →", prod.LHS)
+ for _, elem := range alt.Elements {
+ switch {
+ case elem.ID != "":
+ fmt.Fprintf(&b, " %v", elem.ID)
+ case elem.Pattern != "":
+ fmt.Fprintf(&b, ` "%v"`, elem.Pattern)
+ }
+ }
+ if len(alt.Elements) == 0 {
+ fmt.Fprintf(&b, " ε")
+ }
+
+ detail = b.String()
+ }
+
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDuplicateProduction,
+ Detail: detail,
+ Row: row,
+ })
+ continue LOOP_RHS
+ }
prods.append(p)
if alt.Directive != nil {