diff options
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r-- | grammar/grammar.go | 334 |
1 files changed, 171 insertions, 163 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go index 50272e0..1e05289 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -5,10 +5,11 @@ import ( "io" "strings" - mlcompiler "github.com/nihei9/maleeni/compiler" - mlspec "github.com/nihei9/maleeni/spec" verr "github.com/nihei9/vartan/error" + "github.com/nihei9/vartan/grammar/lexical" + "github.com/nihei9/vartan/grammar/symbol" spec "github.com/nihei9/vartan/spec/grammar" + "github.com/nihei9/vartan/spec/grammar/parser" ) type astActionEntry struct { @@ -33,8 +34,8 @@ const ( // We use the priority of the production to resolve shift/reduce conflicts. type precAndAssoc struct { // termPrec and termAssoc represent the precedence of the terminal symbols. - termPrec map[symbolNum]int - termAssoc map[symbolNum]assocType + termPrec map[symbol.SymbolNum]int + termAssoc map[symbol.SymbolNum]assocType // prodPrec and prodAssoc represent the precedence and the associativities of the production. // These values are inherited from the right-most terminal symbols in the RHS of the productions. @@ -42,7 +43,7 @@ type precAndAssoc struct { prodAssoc map[productionNum]assocType } -func (pa *precAndAssoc) terminalPrecedence(sym symbolNum) int { +func (pa *precAndAssoc) terminalPrecedence(sym symbol.SymbolNum) int { prec, ok := pa.termPrec[sym] if !ok { return precNil @@ -51,7 +52,7 @@ func (pa *precAndAssoc) terminalPrecedence(sym symbolNum) int { return prec } -func (pa *precAndAssoc) terminalAssociativity(sym symbolNum) assocType { +func (pa *precAndAssoc) terminalAssociativity(sym symbol.SymbolNum) assocType { assoc, ok := pa.termAssoc[sym] if !ok { return assocTypeNil @@ -82,12 +83,12 @@ const reservedSymbolNameError = "error" type Grammar struct { name string - lexSpec *mlspec.LexSpec - skipLexKinds []mlspec.LexKindName + lexSpec *lexical.LexSpec + skipSymbols []symbol.Symbol productionSet *productionSet - augmentedStartSymbol symbol - errorSymbol symbol - symbolTable *symbolTableReader + augmentedStartSymbol symbol.Symbol + errorSymbol symbol.Symbol + symbolTable *symbol.SymbolTableReader astActions map[productionID][]*astActionEntry precAndAssoc *precAndAssoc @@ -95,13 +96,34 @@ type Grammar struct { recoverProductions map[productionID]struct{} } +type buildConfig struct { + isReportingEnabled bool +} + +type BuildOption func(config *buildConfig) + +func EnableReporting() BuildOption { + return func(config *buildConfig) { + config.isReportingEnabled = true + } +} + type GrammarBuilder struct { - AST *spec.RootNode + AST *parser.RootNode errs verr.SpecErrors } -func (b *GrammarBuilder) Build() (*Grammar, error) { +func (b *GrammarBuilder) Build(opts ...BuildOption) (*spec.CompiledGrammar, *spec.Report, error) { + gram, err := b.build() + if err != nil { + return nil, nil, err + } + + return compile(gram, opts...) +} + +func (b *GrammarBuilder) build() (*Grammar, error) { var specName string { errOccurred := false @@ -143,12 +165,12 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { return nil, err } - lexSpec, err := b.genLexSpec(b.AST) + lexSpec, skip, err := b.genLexSpecAndSkipSymbols(symTab.Reader(), b.AST) if err != nil { return nil, err } - prodsAndActs, err := b.genProductionsAndActions(b.AST, symTab.reader(), ss.errSym, ss.augStartSym, ss.startSym) + prodsAndActs, err := b.genProductionsAndActions(b.AST, symTab.Reader(), ss.errSym, ss.augStartSym, ss.startSym) if err != nil { return nil, err } @@ -156,7 +178,7 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { return nil, b.errs } - pa, err := b.genPrecAndAssoc(symTab.reader(), ss.errSym, prodsAndActs) + pa, err := b.genPrecAndAssoc(symTab.Reader(), ss.errSym, prodsAndActs) if err != nil { return nil, err } @@ -171,20 +193,23 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { // When a terminal symbol that cannot be reached from the start symbol has the skip directive, // the compiler treats its terminal as a used symbol, not unused. - for _, sym := range lexSpec.skip { - s := sym.String() - if _, ok := syms.unusedTerminals[s]; !ok { - prod := syms.usedTerminals[s] - b.errs = append(b.errs, &verr.SpecError{ - Cause: semErrTermCannotBeSkipped, - Detail: s, - Row: prod.Pos.Row, - Col: prod.Pos.Col, - }) - continue - } + { + r := symTab.Reader() + for _, sym := range skip { + s, _ := r.ToText(sym) + if _, ok := syms.unusedTerminals[s]; !ok { + prod := syms.usedTerminals[s] + b.errs = append(b.errs, &verr.SpecError{ + Cause: semErrTermCannotBeSkipped, + Detail: s, + Row: prod.Pos.Row, + Col: prod.Pos.Col, + }) + continue + } - delete(syms.unusedTerminals, s) + delete(syms.unusedTerminals, s) + } } for sym, prod := range syms.unusedProductions { @@ -209,16 +234,14 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { return nil, b.errs } - lexSpec.lexSpec.Name = specName - return &Grammar{ name: specName, - lexSpec: lexSpec.lexSpec, - skipLexKinds: lexSpec.skip, + lexSpec: lexSpec, + skipSymbols: skip, productionSet: prodsAndActs.prods, augmentedStartSymbol: prodsAndActs.augStartSym, errorSymbol: ss.errSym, - symbolTable: symTab.reader(), + symbolTable: symTab.Reader(), astActions: prodsAndActs.astActs, recoverProductions: prodsAndActs.recoverProds, precAndAssoc: pa, @@ -226,14 +249,14 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { } type usedAndUnusedSymbols struct { - unusedProductions map[string]*spec.ProductionNode - unusedTerminals map[string]*spec.ProductionNode - usedTerminals map[string]*spec.ProductionNode + unusedProductions map[string]*parser.ProductionNode + unusedTerminals map[string]*parser.ProductionNode + usedTerminals map[string]*parser.ProductionNode } -func findUsedAndUnusedSymbols(root *spec.RootNode) *usedAndUnusedSymbols { - prods := map[string]*spec.ProductionNode{} - lexProds := map[string]*spec.ProductionNode{} +func findUsedAndUnusedSymbols(root *parser.RootNode) *usedAndUnusedSymbols { + prods := map[string]*parser.ProductionNode{} + lexProds := map[string]*parser.ProductionNode{} mark := map[string]bool{} { for _, p := range root.Productions { @@ -262,9 +285,9 @@ func findUsedAndUnusedSymbols(root *spec.RootNode) *usedAndUnusedSymbols { delete(mark, reservedSymbolNameError) } - usedTerms := make(map[string]*spec.ProductionNode, len(lexProds)) - unusedProds := map[string]*spec.ProductionNode{} - unusedTerms := map[string]*spec.ProductionNode{} + usedTerms := make(map[string]*parser.ProductionNode, len(lexProds)) + unusedProds := map[string]*parser.ProductionNode{} + unusedTerms := map[string]*parser.ProductionNode{} for sym, used := range mark { if p, ok := prods[sym]; ok { if used { @@ -294,7 +317,7 @@ func findUsedAndUnusedSymbols(root *spec.RootNode) *usedAndUnusedSymbols { } } -func markUsedSymbols(mark map[string]bool, marked map[string]bool, prods map[string]*spec.ProductionNode, prod *spec.ProductionNode) { +func markUsedSymbols(mark map[string]bool, marked map[string]bool, prods map[string]*parser.ProductionNode, prod *parser.ProductionNode) { if marked[prod.LHS] { return } @@ -320,7 +343,7 @@ func markUsedSymbols(mark map[string]bool, marked map[string]bool, prods map[str } } -func (b *GrammarBuilder) checkSpellingInconsistenciesOfUserDefinedIDs(root *spec.RootNode) { +func (b *GrammarBuilder) checkSpellingInconsistenciesOfUserDefinedIDs(root *parser.RootNode) { var ids []string { for _, prod := range root.Productions { @@ -344,7 +367,7 @@ func (b *GrammarBuilder) checkSpellingInconsistenciesOfUserDefinedIDs(root *spec } } - duplicated := mlspec.FindSpellingInconsistencies(ids) + duplicated := lexical.FindSpellingInconsistencies(ids) if len(duplicated) == 0 { return } @@ -367,7 +390,7 @@ func (b *GrammarBuilder) checkSpellingInconsistenciesOfUserDefinedIDs(root *spec } } -func collectUserDefinedIDsFromDirective(dir *spec.DirectiveNode) []string { +func collectUserDefinedIDsFromDirective(dir *parser.DirectiveNode) []string { var ids []string for _, param := range dir.Parameters { if param.Group != nil { @@ -386,20 +409,20 @@ func collectUserDefinedIDsFromDirective(dir *spec.DirectiveNode) []string { } type symbols struct { - errSym symbol - augStartSym symbol - startSym symbol + errSym symbol.Symbol + augStartSym symbol.Symbol + startSym symbol.Symbol } -func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *symbols, error) { - symTab := newSymbolTable() - w := symTab.writer() - r := symTab.reader() +func (b *GrammarBuilder) genSymbolTable(root *parser.RootNode) (*symbol.SymbolTable, *symbols, error) { + symTab := symbol.NewSymbolTable() + w := symTab.Writer() + r := symTab.Reader() // We need to register the reserved symbol before registering others. - var errSym symbol + var errSym symbol.Symbol { - sym, err := w.registerTerminalSymbol(reservedSymbolNameError) + sym, err := w.RegisterTerminalSymbol(reservedSymbolNameError) if err != nil { return nil, nil, err } @@ -407,7 +430,7 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym } for _, prod := range root.LexProductions { - if sym, exist := r.toSymbol(prod.LHS); exist { + if sym, exist := r.ToSymbol(prod.LHS); exist { if sym == errSym { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrErrSymIsReserved, @@ -426,7 +449,7 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym continue } - _, err := w.registerTerminalSymbol(prod.LHS) + _, err := w.RegisterTerminalSymbol(prod.LHS) if err != nil { return nil, nil, err } @@ -435,7 +458,7 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym startProd := root.Productions[0] augStartText := fmt.Sprintf("%s'", startProd.LHS) var err error - augStartSym, err := w.registerStartSymbol(augStartText) + augStartSym, err := w.RegisterStartSymbol(augStartText) if err != nil { return nil, nil, err } @@ -447,7 +470,7 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym }) } - startSym, err := w.registerNonTerminalSymbol(startProd.LHS) + startSym, err := w.RegisterNonTerminalSymbol(startProd.LHS) if err != nil { return nil, nil, err } @@ -460,11 +483,11 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym } for _, prod := range root.Productions { - sym, err := w.registerNonTerminalSymbol(prod.LHS) + sym, err := w.RegisterNonTerminalSymbol(prod.LHS) if err != nil { return nil, nil, err } - if sym.isTerminal() { + if sym.IsTerminal() { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDuplicateName, Detail: prod.LHS, @@ -488,25 +511,21 @@ func (b *GrammarBuilder) genSymbolTable(root *spec.RootNode) (*symbolTable, *sym }, nil } -type lexSpec struct { - lexSpec *mlspec.LexSpec - skip []mlspec.LexKindName -} - -func (b *GrammarBuilder) genLexSpec(root *spec.RootNode) (*lexSpec, error) { - entries := []*mlspec.LexEntry{} - skipKinds := []mlspec.LexKindName{} +func (b *GrammarBuilder) genLexSpecAndSkipSymbols(symTab *symbol.SymbolTableReader, root *parser.RootNode) (*lexical.LexSpec, []symbol.Symbol, error) { + entries := []*lexical.LexEntry{} + skipSyms := []symbol.Symbol{} for _, prod := range root.LexProductions { entry, skip, specErr, err := genLexEntry(prod) if err != nil { - return nil, err + return nil, nil, err } if specErr != nil { b.errs = append(b.errs, specErr) continue } if skip { - skipKinds = append(skipKinds, mlspec.LexKindName(prod.LHS)) + sym, _ := symTab.ToSymbol(prod.LHS) + skipSyms = append(skipSyms, sym) } entries = append(entries, entry) } @@ -524,35 +543,32 @@ func (b *GrammarBuilder) genLexSpec(root *spec.RootNode) (*lexSpec, error) { } checkedFragments[fragment.LHS] = struct{}{} - entries = append(entries, &mlspec.LexEntry{ + entries = append(entries, &lexical.LexEntry{ Fragment: true, - Kind: mlspec.LexKindName(fragment.LHS), - Pattern: mlspec.LexPattern(fragment.RHS), + Kind: spec.LexKindName(fragment.LHS), + Pattern: fragment.RHS, }) } - return &lexSpec{ - lexSpec: &mlspec.LexSpec{ - Entries: entries, - }, - skip: skipKinds, - }, nil + return &lexical.LexSpec{ + Entries: entries, + }, skipSyms, nil } -func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecError, error) { +func genLexEntry(prod *parser.ProductionNode) (*lexical.LexEntry, bool, *verr.SpecError, error) { alt := prod.RHS[0] elem := alt.Elements[0] var pattern string if elem.Literally { - pattern = mlspec.EscapePattern(elem.Pattern) + pattern = spec.EscapePattern(elem.Pattern) } else { pattern = elem.Pattern } - var modes []mlspec.LexModeName + var modes []spec.LexModeName var skip bool - var push mlspec.LexModeName + var push spec.LexModeName var pop bool dirConsumed := map[string]struct{}{} for _, dir := range prod.Directives { @@ -585,7 +601,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecE Col: param.Pos.Col, }, nil } - modes = append(modes, mlspec.LexModeName(param.ID)) + modes = append(modes, spec.LexModeName(param.ID)) } case "skip": if len(dir.Parameters) > 0 { @@ -606,7 +622,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecE Col: dir.Pos.Col, }, nil } - push = mlspec.LexModeName(dir.Parameters[0].ID) + push = spec.LexModeName(dir.Parameters[0].ID) case "pop": if len(dir.Parameters) > 0 { return nil, false, &verr.SpecError{ @@ -636,10 +652,10 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecE }, nil } - return &mlspec.LexEntry{ + return &lexical.LexEntry{ Modes: modes, - Kind: mlspec.LexKindName(prod.LHS), - Pattern: mlspec.LexPattern(pattern), + Kind: spec.LexKindName(prod.LHS), + Pattern: pattern, Push: push, Pop: pop, }, skip, nil, nil @@ -647,15 +663,15 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, *verr.SpecE type productionsAndActions struct { prods *productionSet - augStartSym symbol + augStartSym symbol.Symbol astActs map[productionID][]*astActionEntry - prodPrecsTerm map[productionID]symbol + prodPrecsTerm map[productionID]symbol.Symbol prodPrecsOrdSym map[productionID]string - prodPrecPoss map[productionID]*spec.Position + prodPrecPoss map[productionID]*parser.Position recoverProds map[productionID]struct{} } -func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *symbolTableReader, errSym symbol, augStartSym symbol, startSym symbol) (*productionsAndActions, error) { +func (b *GrammarBuilder) genProductionsAndActions(root *parser.RootNode, symTab *symbol.SymbolTableReader, errSym symbol.Symbol, augStartSym symbol.Symbol, startSym symbol.Symbol) (*productionsAndActions, error) { if len(root.Productions) == 0 { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrNoProduction, @@ -665,12 +681,12 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s prods := newProductionSet() astActs := map[productionID][]*astActionEntry{} - prodPrecsTerm := map[productionID]symbol{} + prodPrecsTerm := map[productionID]symbol.Symbol{} prodPrecsOrdSym := map[productionID]string{} - prodPrecPoss := map[productionID]*spec.Position{} + prodPrecPoss := map[productionID]*parser.Position{} recoverProds := map[productionID]struct{}{} - p, err := newProduction(augStartSym, []symbol{ + p, err := newProduction(augStartSym, []symbol.Symbol{ startSym, }) if err != nil { @@ -680,7 +696,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s prods.append(p) for _, prod := range root.Productions { - lhsSym, ok := symTab.toSymbol(prod.LHS) + lhsSym, ok := symTab.ToSymbol(prod.LHS) if !ok { // All symbols are assumed to be pre-detected, so it's a bug if we cannot find them here. return nil, fmt.Errorf("symbol '%v' is undefined", prod.LHS) @@ -698,11 +714,11 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s LOOP_RHS: for _, alt := range prod.RHS { - altSyms := make([]symbol, len(alt.Elements)) + altSyms := make([]symbol.Symbol, len(alt.Elements)) offsets := map[string]int{} ambiguousIDOffsets := map[string]struct{}{} for i, elem := range alt.Elements { - sym, ok := symTab.toSymbol(elem.ID) + sym, ok := symTab.ToSymbol(elem.ID) if !ok { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrUndefinedSym, @@ -724,7 +740,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s }) continue LOOP_RHS } - if _, found := symTab.toSymbol(elem.Label.Name); found { + if _, found := symTab.ToSymbol(elem.Label.Name); found { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrInvalidLabel, Detail: elem.Label.Name, @@ -877,12 +893,12 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s }) continue LOOP_RHS } - elemSym, ok := symTab.toSymbol(elem.ID) + elemSym, ok := symTab.ToSymbol(elem.ID) if !ok { // If the symbol was not found, it's a bug. return nil, fmt.Errorf("a symbol corresponding to an ID (%v) was not found", elem.ID) } - if elemSym.isTerminal() { + if elemSym.IsTerminal() { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, Detail: fmt.Sprintf("the expansion symbol cannot be applied to a terminal symbol (%v: %v)", param.ID, elem.ID), @@ -912,7 +928,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s param := dir.Parameters[0] switch { case param.ID != "": - sym, ok := symTab.toSymbol(param.ID) + sym, ok := symTab.ToSymbol(param.ID) if !ok { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, @@ -930,7 +946,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s Col: param.Pos.Col, }) } - if !sym.isTerminal() { + if !sym.IsTerminal() { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, Detail: fmt.Sprintf("the symbol must be a terminal: %v", param.ID), @@ -980,12 +996,12 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTab *s }, nil } -func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbol, prodsAndActs *productionsAndActions) (*precAndAssoc, error) { - termPrec := map[symbolNum]int{} - termAssoc := map[symbolNum]assocType{} +func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbol.SymbolTableReader, errSym symbol.Symbol, prodsAndActs *productionsAndActions) (*precAndAssoc, error) { + termPrec := map[symbol.SymbolNum]int{} + termAssoc := map[symbol.SymbolNum]assocType{} ordSymPrec := map[string]int{} { - var precGroup []*spec.DirectiveNode + var precGroup []*parser.DirectiveNode for _, dir := range b.AST.Directives { if dir.Name == "prec" { if dir.Parameters == nil || len(dir.Parameters) != 1 || dir.Parameters[0].Group == nil { @@ -1045,7 +1061,7 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo for _, p := range dir.Parameters { switch { case p.ID != "": - sym, ok := symTab.toSymbol(p.ID) + sym, ok := symTab.ToSymbol(p.ID) if !ok { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, @@ -1064,7 +1080,7 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo }) return nil, nil } - if !sym.isTerminal() { + if !sym.IsTerminal() { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, Detail: fmt.Sprintf("associativity can take only terminal symbol ('%v' is a non-terminal)", p.ID), @@ -1073,7 +1089,7 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo }) return nil, nil } - if prec, alreadySet := termPrec[sym.num()]; alreadySet { + if prec, alreadySet := termPrec[sym.Num()]; alreadySet { if prec == precN { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDuplicateAssoc, @@ -1081,7 +1097,7 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo Row: p.Pos.Row, Col: p.Pos.Col, }) - } else if assoc := termAssoc[sym.num()]; assoc == assocTy { + } else if assoc := termAssoc[sym.Num()]; assoc == assocTy { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDuplicateAssoc, Detail: fmt.Sprintf("'%v' already has different precedence", p.ID), @@ -1099,8 +1115,8 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo break ASSOC_PARAM_LOOP } - termPrec[sym.num()] = precN - termAssoc[sym.num()] = assocTy + termPrec[sym.Num()] = precN + termAssoc[sym.Num()] = assocTy case p.OrderedSymbol != "": if prec, alreadySet := ordSymPrec[p.OrderedSymbol]; alreadySet { if prec == precN { @@ -1145,11 +1161,11 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo for _, prod := range prodsAndActs.prods.getAllProductions() { // A #prec directive changes only precedence, not associativity. if term, ok := prodsAndActs.prodPrecsTerm[prod.id]; ok { - if prec, ok := termPrec[term.num()]; ok { + if prec, ok := termPrec[term.Num()]; ok { prodPrec[prod.num] = prec prodAssoc[prod.num] = assocTypeNil } else { - text, _ := symTab.toText(term) + text, _ := symTab.ToText(term) b.errs = append(b.errs, &verr.SpecError{ Cause: semErrUndefinedPrec, Detail: text, @@ -1171,16 +1187,16 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo } } else { // A production inherits precedence and associativity from the right-most terminal symbol. - mostrightTerm := symbolNil + mostrightTerm := symbol.SymbolNil for _, sym := range prod.rhs { - if !sym.isTerminal() { + if !sym.IsTerminal() { continue } mostrightTerm = sym } - if !mostrightTerm.isNil() { - prodPrec[prod.num] = termPrec[mostrightTerm.num()] - prodAssoc[prod.num] = termAssoc[mostrightTerm.num()] + if !mostrightTerm.IsNil() { + prodPrec[prod.num] = termPrec[mostrightTerm.Num()] + prodAssoc[prod.num] = termAssoc[mostrightTerm.Num()] } } } @@ -1196,25 +1212,13 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTableReader, errSym symbo }, nil } -type compileConfig struct { - isReportingEnabled bool -} - -type CompileOption func(config *compileConfig) - -func EnableReporting() CompileOption { - return func(config *compileConfig) { - config.isReportingEnabled = true - } -} - -func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec.Report, error) { - config := &compileConfig{} +func compile(gram *Grammar, opts ...BuildOption) (*spec.CompiledGrammar, *spec.Report, error) { + config := &buildConfig{} for _, opt := range opts { opt(config) } - lexSpec, err, cErrs := mlcompiler.Compile(gram.lexSpec, mlcompiler.CompressionLevel(mlcompiler.CompressionLevelMax)) + lexSpec, err, cErrs := lexical.Compile(gram.lexSpec, lexical.CompressionLevelMax) if err != nil { if len(cErrs) > 0 { var b strings.Builder @@ -1230,35 +1234,44 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec kind2Term := make([]int, len(lexSpec.KindNames)) for i, k := range lexSpec.KindNames { - if k == mlspec.LexKindNameNil { - kind2Term[mlspec.LexKindIDNil] = symbolNil.num().Int() + if k == spec.LexKindNameNil { + kind2Term[spec.LexKindIDNil] = symbol.SymbolNil.Num().Int() continue } - sym, ok := gram.symbolTable.toSymbol(k.String()) + sym, ok := gram.symbolTable.ToSymbol(k.String()) if !ok { return nil, nil, fmt.Errorf("terminal symbol '%v' was not found in a symbol table", k) } - kind2Term[i] = sym.num().Int() + kind2Term[i] = sym.Num().Int() } - termTexts, err := gram.symbolTable.terminalTexts() + termTexts, err := gram.symbolTable.TerminalTexts() if err != nil { return nil, nil, err } - termSkip := make([]int, len(termTexts)) - for i, k := range lexSpec.KindNames { - for _, sk := range gram.skipLexKinds { - if k != sk { - continue + var termSkip []int + { + r := gram.symbolTable.Reader() + // I want to use gram.symbolTable.terminalSymbols() here instead of gram.symbolTable.terminalTexts(), + // but gram.symbolTable.terminalSymbols() is different in length from terminalTexts + // because it does not contain a predefined symbol, like EOF. + // Therefore, we use terminalTexts, although it takes more time to lookup for symbols. + termSkip = make([]int, len(termTexts)) + for _, t := range termTexts { + s, _ := r.ToSymbol(t) + for _, sk := range gram.skipSymbols { + if s != sk { + continue + } + termSkip[s.Num()] = 1 + break } - termSkip[kind2Term[i]] = 1 - break } } - nonTerms, err := gram.symbolTable.nonTerminalTexts() + nonTerms, err := gram.symbolTable.NonTerminalTexts() if err != nil { return nil, nil, err } @@ -1316,7 +1329,7 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec 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() + lhsSyms[p.num] = p.lhs.Num().Int() altSymCounts[p.num] = p.rhsLen if _, ok := gram.recoverProductions[p.id]; ok { @@ -1339,15 +1352,9 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec } return &spec.CompiledGrammar{ - Name: gram.name, - LexicalSpecification: &spec.LexicalSpecification{ - Lexer: "maleeni", - Maleeni: &spec.Maleeni{ - Spec: lexSpec, - KindToTerminal: kind2Term, - }, - }, - ParsingTable: &spec.ParsingTable{ + Name: gram.name, + Lexical: lexSpec, + Syntactic: &spec.SyntacticSpec{ Action: action, GoTo: goTo, StateCount: tab.stateCount, @@ -1358,10 +1365,11 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec Terminals: termTexts, TerminalCount: tab.terminalCount, TerminalSkip: termSkip, + KindToTerminal: kind2Term, NonTerminals: nonTerms, NonTerminalCount: tab.nonTerminalCount, - EOFSymbol: symbolEOF.num().Int(), - ErrorSymbol: gram.errorSymbol.num().Int(), + EOFSymbol: symbol.SymbolEOF.Num().Int(), + ErrorSymbol: gram.errorSymbol.Num().Int(), ErrorTrapperStates: tab.errorTrapperStates, RecoverProductions: recoverProds, }, @@ -1371,7 +1379,7 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec }, report, nil } -func writeCompileError(w io.Writer, cErr *mlcompiler.CompileError) { +func writeCompileError(w io.Writer, cErr *lexical.CompileError) { if cErr.Fragment { fmt.Fprintf(w, "fragment ") } |