aboutsummaryrefslogtreecommitdiff
path: root/grammar/grammar.go
diff options
context:
space:
mode:
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r--grammar/grammar.go107
1 files changed, 93 insertions, 14 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go
index 812a845..27fafc9 100644
--- a/grammar/grammar.go
+++ b/grammar/grammar.go
@@ -68,15 +68,21 @@ func (pa *precAndAssoc) productionAssociativity(prod productionNum) assocType {
return assoc
}
+const reservedSymbolNameError = "error"
+
type Grammar struct {
lexSpec *mlspec.LexSpec
skipLexKinds []mlspec.LexKindName
sym2AnonPat map[symbol]string
productionSet *productionSet
augmentedStartSymbol symbol
+ errorSymbol symbol
symbolTable *symbolTable
astActions map[productionID][]*astActionEntry
precAndAssoc *precAndAssoc
+
+ // recoverProductions is a set of productions having the recover directive.
+ recoverProductions map[productionID]struct{}
}
type GrammarBuilder struct {
@@ -155,8 +161,10 @@ func (b *GrammarBuilder) Build() (*Grammar, error) {
sym2AnonPat: symTabAndLexSpec.sym2AnonPat,
productionSet: prodsAndActs.prods,
augmentedStartSymbol: prodsAndActs.augStartSym,
+ errorSymbol: symTabAndLexSpec.errSym,
symbolTable: symTabAndLexSpec.symTab,
astActions: prodsAndActs.astActs,
+ recoverProductions: prodsAndActs.recoverProds,
precAndAssoc: pa,
}, nil
}
@@ -193,6 +201,9 @@ func findUsedAndUnusedSymbols(root *spec.RootNode) (*usedAndUnusedSymbols, error
start := root.Productions[0]
mark[start.LHS] = true
markUsedSymbols(mark, map[string]bool{}, prods, start)
+
+ // We don't have to check the error symbol because the error symbol doesn't have a production.
+ delete(mark, reservedSymbolNameError)
}
usedTerms := make(map[string]*spec.ProductionNode, len(lexProds))
@@ -255,6 +266,7 @@ type symbolTableAndLexSpec struct {
anonPat2Sym map[string]symbol
sym2AnonPat map[symbol]string
lexSpec *mlspec.LexSpec
+ errSym symbol
skip []mlspec.LexKindName
skipSyms []string
}
@@ -265,6 +277,16 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT
symTab := newSymbolTable()
entries := []*mlspec.LexEntry{}
+ // We need to register the reserved symbol before registering others.
+ var errSym symbol
+ {
+ sym, err := symTab.registerTerminalSymbol(reservedSymbolNameError)
+ if err != nil {
+ return nil, err
+ }
+ errSym = sym
+ }
+
anonPat2Sym := map[string]symbol{}
sym2AnonPat := map[symbol]string{}
{
@@ -311,13 +333,22 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT
skipKinds := []mlspec.LexKindName{}
skipSyms := []string{}
for _, prod := range root.LexProductions {
- if _, exist := symTab.toSymbol(prod.LHS); exist {
- b.errs = append(b.errs, &verr.SpecError{
- Cause: semErrDuplicateTerminal,
- Detail: prod.LHS,
- Row: prod.Pos.Row,
- Col: prod.Pos.Col,
- })
+ if sym, exist := symTab.toSymbol(prod.LHS); exist {
+ if sym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrErrSymIsReserved,
+ Row: prod.Pos.Row,
+ Col: prod.Pos.Col,
+ })
+ } else {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDuplicateTerminal,
+ Detail: prod.LHS,
+ Row: prod.Pos.Row,
+ Col: prod.Pos.Col,
+ })
+ }
+
continue
}
@@ -368,6 +399,7 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT
lexSpec: &mlspec.LexSpec{
Entries: entries,
},
+ errSym: errSym,
skip: skipKinds,
skipSyms: skipSyms,
}, nil
@@ -465,14 +497,16 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecE
}
type productionsAndActions struct {
- prods *productionSet
- augStartSym symbol
- astActs map[productionID][]*astActionEntry
+ prods *productionSet
+ augStartSym symbol
+ astActs map[productionID][]*astActionEntry
+ recoverProds map[productionID]struct{}
}
func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAndLexSpec *symbolTableAndLexSpec) (*productionsAndActions, error) {
symTab := symTabAndLexSpec.symTab
anonPat2Sym := symTabAndLexSpec.anonPat2Sym
+ errSym := symTabAndLexSpec.errSym
if len(root.Productions) == 0 {
b.errs = append(b.errs, &verr.SpecError{
@@ -484,6 +518,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
prods := newProductionSet()
var augStartSym symbol
astActs := map[productionID][]*astActionEntry{}
+ recoverProds := map[productionID]struct{}{}
startProd := root.Productions[0]
augStartText := fmt.Sprintf("%s'", startProd.LHS)
@@ -492,16 +527,33 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
if err != nil {
return nil, err
}
+ if augStartSym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrErrSymIsReserved,
+ Row: startProd.Pos.Row,
+ Col: startProd.Pos.Col,
+ })
+ }
+
startSym, err := symTab.registerNonTerminalSymbol(startProd.LHS)
if err != nil {
return nil, err
}
+ if startSym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrErrSymIsReserved,
+ Row: startProd.Pos.Row,
+ Col: startProd.Pos.Col,
+ })
+ }
+
p, err := newProduction(augStartSym, []symbol{
startSym,
})
if err != nil {
return nil, err
}
+
prods.append(p)
for _, prod := range root.Productions {
@@ -517,6 +569,13 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
Col: prod.Pos.Col,
})
}
+ if sym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrErrSymIsReserved,
+ Row: prod.Pos.Row,
+ Col: prod.Pos.Col,
+ })
+ }
}
for _, prod := range root.Productions {
@@ -670,6 +729,17 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
}
}
astActs[p.id] = astAct
+ case "recover":
+ if len(dir.Parameters) > 0 {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDirInvalidParam,
+ Detail: fmt.Sprintf("'recover' directive needs no parameter"),
+ Row: dir.Pos.Row,
+ Col: dir.Pos.Col,
+ })
+ continue LOOP_RHS
+ }
+ recoverProds[p.id] = struct{}{}
default:
b.errs = append(b.errs, &verr.SpecError{
Cause: semErrDirInvalidName,
@@ -684,9 +754,10 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
}
return &productionsAndActions{
- prods: prods,
- augStartSym: augStartSym,
- astActs: astActs,
+ prods: prods,
+ augStartSym: augStartSym,
+ astActs: astActs,
+ recoverProds: recoverProds,
}, nil
}
@@ -859,7 +930,7 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error
return nil, err
}
- lr0, err := genLR0Automaton(gram.productionSet, gram.augmentedStartSymbol)
+ lr0, err := genLR0Automaton(gram.productionSet, gram.augmentedStartSymbol, gram.errorSymbol)
if err != nil {
return nil, err
}
@@ -929,11 +1000,16 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error
lhsSyms := make([]int, len(gram.productionSet.getAllProductions())+1)
altSymCounts := make([]int, len(gram.productionSet.getAllProductions())+1)
+ recoverProds := make([]int, len(gram.productionSet.getAllProductions())+1)
astActEnties := make([][]int, len(gram.productionSet.getAllProductions())+1)
for _, p := range gram.productionSet.getAllProductions() {
lhsSyms[p.num] = p.lhs.num().Int()
altSymCounts[p.num] = p.rhsLen
+ if _, ok := gram.recoverProductions[p.id]; ok {
+ recoverProds[p.num] = 1
+ }
+
astAct, ok := gram.astActions[p.id]
if !ok {
continue
@@ -972,6 +1048,9 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error
NonTerminals: nonTerms,
NonTerminalCount: tab.nonTerminalCount,
EOFSymbol: symbolEOF.num().Int(),
+ ErrorSymbol: gram.errorSymbol.num().Int(),
+ ErrorTrapperStates: tab.errorTrapperStates,
+ RecoverProductions: recoverProds,
ExpectedTerminals: tab.expectedTerminals,
},
ASTAction: &spec.ASTAction{