diff options
Diffstat (limited to 'grammar')
-rw-r--r-- | grammar/follow.go | 145 | ||||
-rw-r--r-- | grammar/follow_test.go | 204 | ||||
-rw-r--r-- | grammar/grammar.go | 49 | ||||
-rw-r--r-- | grammar/parsing_table.go | 2 | ||||
-rw-r--r-- | grammar/parsing_table_test.go | 386 | ||||
-rw-r--r-- | grammar/slr1.go | 61 | ||||
-rw-r--r-- | grammar/slr1_test.go | 233 |
7 files changed, 4 insertions, 1076 deletions
diff --git a/grammar/follow.go b/grammar/follow.go deleted file mode 100644 index 67e5f70..0000000 --- a/grammar/follow.go +++ /dev/null @@ -1,145 +0,0 @@ -package grammar - -import ( - "fmt" -) - -type followEntry struct { - symbols map[symbol]struct{} - eof bool -} - -func newFollowEntry() *followEntry { - return &followEntry{ - symbols: map[symbol]struct{}{}, - eof: false, - } -} - -func (e *followEntry) add(sym symbol) bool { - if _, ok := e.symbols[sym]; ok { - return false - } - e.symbols[sym] = struct{}{} - return true -} - -func (e *followEntry) addEOF() bool { - if !e.eof { - e.eof = true - return true - } - return false -} - -func (e *followEntry) merge(fst *firstEntry, flw *followEntry) bool { - changed := false - - if fst != nil { - for sym := range fst.symbols { - added := e.add(sym) - if added { - changed = true - } - } - } - - if flw != nil { - for sym := range flw.symbols { - added := e.add(sym) - if added { - changed = true - } - } - if flw.eof { - added := e.addEOF() - if added { - changed = true - } - } - } - - return changed -} - -type followSet struct { - set map[symbol]*followEntry -} - -func newFollow(prods *productionSet) *followSet { - flw := &followSet{ - set: map[symbol]*followEntry{}, - } - for _, prod := range prods.getAllProductions() { - if _, ok := flw.set[prod.lhs]; ok { - continue - } - flw.set[prod.lhs] = newFollowEntry() - } - return flw -} - -func (flw *followSet) find(sym symbol) (*followEntry, error) { - e, ok := flw.set[sym] - if !ok { - return nil, fmt.Errorf("an entry of FOLLOW was not found; symbol: %s", sym) - } - return e, nil -} - -func genFollowSet(prods *productionSet, first *firstSet) (*followSet, error) { - ntsyms := map[symbol]struct{}{} - for _, prod := range prods.getAllProductions() { - if _, ok := ntsyms[prod.lhs]; ok { - continue - } - ntsyms[prod.lhs] = struct{}{} - } - - follow := newFollow(prods) - for { - more := false - for ntsym := range ntsyms { - e, err := follow.find(ntsym) - if err != nil { - return nil, err - } - if ntsym.isStart() { - changed := e.addEOF() - if changed { - more = true - } - } - for _, prod := range prods.getAllProductions() { - for i, sym := range prod.rhs { - if sym != ntsym { - continue - } - fst, err := first.find(prod, i+1) - if err != nil { - return nil, err - } - changed := e.merge(fst, nil) - if changed { - more = true - } - if fst.empty { - flw, err := follow.find(prod.lhs) - if err != nil { - return nil, err - } - changed := e.merge(nil, flw) - if changed { - more = true - } - } - } - } - } - if !more { - break - } - } - - return follow, nil -} diff --git a/grammar/follow_test.go b/grammar/follow_test.go deleted file mode 100644 index 719582f..0000000 --- a/grammar/follow_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package grammar - -import ( - "strings" - "testing" - - "github.com/nihei9/vartan/spec" -) - -type follow struct { - nonTermText string - symbols []string - eof bool -} - -func TestFollowSet(t *testing.T) { - tests := []struct { - caption string - src string - follow []follow - }{ - { - caption: "productions contain only non-empty productions", - src: ` -#name test; - -expr - : expr add term - | term - ; -term - : term mul factor - | factor - ; -factor - : l_paren expr r_paren - | id - ; -add: "\+"; -mul: "\*"; -l_paren: "\("; -r_paren: "\)"; -id: "[A-Za-z_][0-9A-Za-z_]*"; -`, - follow: []follow{ - {nonTermText: "expr'", symbols: []string{}, eof: true}, - {nonTermText: "expr", symbols: []string{"add", "r_paren"}, eof: true}, - {nonTermText: "term", symbols: []string{"add", "mul", "r_paren"}, eof: true}, - {nonTermText: "factor", symbols: []string{"add", "mul", "r_paren"}, eof: true}, - }, - }, - { - caption: "productions contain an empty start production", - src: ` -#name test; - -s - : - ; -`, - follow: []follow{ - {nonTermText: "s'", symbols: []string{}, eof: true}, - {nonTermText: "s", symbols: []string{}, eof: true}, - }, - }, - { - caption: "productions contain an empty production", - src: ` -#name test; - -s - : foo - ; -foo - : -; -`, - follow: []follow{ - {nonTermText: "s'", symbols: []string{}, eof: true}, - {nonTermText: "s", symbols: []string{}, eof: true}, - {nonTermText: "foo", symbols: []string{}, eof: true}, - }, - }, - { - caption: "a start production contains a non-empty alternative and empty alternative", - src: ` -#name test; - -s - : foo - | - ; -foo: "foo"; -`, - follow: []follow{ - {nonTermText: "s'", symbols: []string{}, eof: true}, - {nonTermText: "s", symbols: []string{}, eof: true}, - }, - }, - { - caption: "a production contains non-empty alternative and empty alternative", - src: ` -#name test; - -s - : foo - ; -foo - : bar - | - ; -bar: "bar"; -`, - follow: []follow{ - {nonTermText: "s'", symbols: []string{}, eof: true}, - {nonTermText: "s", symbols: []string{}, eof: true}, - {nonTermText: "foo", symbols: []string{}, eof: true}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.caption, func(t *testing.T) { - flw, gram := genActualFollow(t, tt.src) - - for _, ttFollow := range tt.follow { - sym, ok := gram.symbolTable.toSymbol(ttFollow.nonTermText) - if !ok { - t.Fatalf("a symbol '%v' was not found", ttFollow.nonTermText) - } - - actualFollow, err := flw.find(sym) - if err != nil { - t.Fatalf("failed to get a FOLLOW entry; non-terminal symbol: %v (%v), error: %v", ttFollow.nonTermText, sym, err) - } - - expectedFollow := genExpectedFollowEntry(t, ttFollow.symbols, ttFollow.eof, gram.symbolTable) - - testFollow(t, actualFollow, expectedFollow) - } - }) - } -} - -func genActualFollow(t *testing.T, src string) (*followSet, *Grammar) { - ast, err := spec.Parse(strings.NewReader(src)) - if err != nil { - t.Fatal(err) - } - b := GrammarBuilder{ - AST: ast, - } - gram, err := b.Build() - if err != nil { - t.Fatal(err) - } - fst, err := genFirstSet(gram.productionSet) - if err != nil { - t.Fatal(err) - } - flw, err := genFollowSet(gram.productionSet, fst) - if err != nil { - t.Fatal(err) - } - if flw == nil { - t.Fatal("genFollow returned nil without any error") - } - - return flw, gram -} - -func genExpectedFollowEntry(t *testing.T, symbols []string, eof bool, symTab *symbolTable) *followEntry { - t.Helper() - - entry := newFollowEntry() - if eof { - entry.addEOF() - } - for _, sym := range symbols { - symID, _ := symTab.toSymbol(sym) - if symID.isNil() { - t.Fatalf("a symbol '%v' was not found", sym) - } - - entry.add(symID) - } - - return entry -} - -func testFollow(t *testing.T, actual, expected *followEntry) { - if actual.eof != expected.eof { - t.Errorf("eof is mismatched; want: %v, got: %v", expected.eof, actual.eof) - } - - if len(actual.symbols) != len(expected.symbols) { - t.Fatalf("unexpected symbol count of a FOLLOW entry; want: %v, got: %v", expected.symbols, actual.symbols) - } - - for eSym := range expected.symbols { - if _, ok := actual.symbols[eSym]; !ok { - t.Fatalf("invalid FOLLOW entry; want: %v, got: %v", expected.symbols, actual.symbols) - } - } -} diff --git a/grammar/grammar.go b/grammar/grammar.go index 410236b..368ede6 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -1286,16 +1286,8 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTable, errSym symbol, pro }, nil } -type Class string - -const ( - ClassSLR Class = "SLR(1)" - ClassLALR Class = "LALR(1)" -) - type compileConfig struct { reportFileName string - class Class } type CompileOption func(config *compileConfig) @@ -1306,16 +1298,8 @@ func EnableReporting(fileName string) CompileOption { } } -func SpecifyClass(class Class) CompileOption { - return func(config *compileConfig) { - config.class = class - } -} - func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error) { - config := &compileConfig{ - class: ClassLALR, - } + config := &compileConfig{} for _, opt := range opts { opt(config) } @@ -1385,39 +1369,15 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error return nil, err } - var class string - var automaton *lr0Automaton - switch config.class { - case ClassSLR: - class = "slr" - - followSet, err := genFollowSet(gram.productionSet, firstSet) - if err != nil { - return nil, err - } - - slr1, err := genSLR1Automaton(lr0, gram.productionSet, followSet) - if err != nil { - return nil, err - } - - automaton = slr1.lr0Automaton - case ClassLALR: - class = "lalr" - + var tab *ParsingTable + { lalr1, err := genLALR1Automaton(lr0, gram.productionSet, firstSet) if err != nil { return nil, err } - automaton = lalr1.lr0Automaton - } - - var tab *ParsingTable - { b := &lrTableBuilder{ - class: config.class, - automaton: automaton, + automaton: lalr1.lr0Automaton, prods: gram.productionSet, termCount: len(terms), nonTermCount: len(nonTerms), @@ -1520,7 +1480,6 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error }, }, ParsingTable: &spec.ParsingTable{ - Class: class, Action: action, GoTo: goTo, StateCount: tab.stateCount, diff --git a/grammar/parsing_table.go b/grammar/parsing_table.go index 57badd5..fd490b0 100644 --- a/grammar/parsing_table.go +++ b/grammar/parsing_table.go @@ -147,7 +147,6 @@ func (t *ParsingTable) writeGoTo(state stateNum, sym symbol, nextState stateNum) } type lrTableBuilder struct { - class Class automaton *lr0Automaton prods *productionSet termCount int @@ -553,7 +552,6 @@ func (b *lrTableBuilder) genReport(tab *ParsingTable, gram *Grammar) (*spec.Repo } return &spec.Report{ - Class: string(b.class), Terminals: terms, NonTerminals: nonTerms, Productions: prods, diff --git a/grammar/parsing_table_test.go b/grammar/parsing_table_test.go index 4ce8455..a699728 100644 --- a/grammar/parsing_table_test.go +++ b/grammar/parsing_table_test.go @@ -286,392 +286,6 @@ id: "[A-Za-z0-9_]+"; } } -func TestGenSLRParsingTable(t *testing.T) { - src := ` -#name test; - -expr - : expr add term - | term - ; -term - : term mul factor - | factor - ; -factor - : l_paren expr r_paren - | id - ; -add: "\+"; -mul: "\*"; -l_paren: "\("; -r_paren: "\)"; -id: "[A-Za-z_][0-9A-Za-z_]*"; -` - - var ptab *ParsingTable - var automaton *slr1Automaton - var gram *Grammar - var nonTermCount int - var termCount int - { - ast, err := spec.Parse(strings.NewReader(src)) - if err != nil { - t.Fatal(err) - } - b := GrammarBuilder{ - AST: ast, - } - gram, err = b.Build() - if err != nil { - t.Fatal(err) - } - first, err := genFirstSet(gram.productionSet) - if err != nil { - t.Fatal(err) - } - follow, err := genFollowSet(gram.productionSet, first) - if err != nil { - t.Fatal(err) - } - lr0, err := genLR0Automaton(gram.productionSet, gram.augmentedStartSymbol, gram.errorSymbol) - if err != nil { - t.Fatal(err) - } - automaton, err = genSLR1Automaton(lr0, gram.productionSet, follow) - if err != nil { - t.Fatal(err) - } - - nonTermTexts, err := gram.symbolTable.nonTerminalTexts() - if err != nil { - t.Fatal(err) - } - termTexts, err := gram.symbolTable.terminalTexts() - if err != nil { - t.Fatal(err) - } - nonTermCount = len(nonTermTexts) - termCount = len(termTexts) - - slr := &lrTableBuilder{ - automaton: automaton.lr0Automaton, - prods: gram.productionSet, - termCount: termCount, - nonTermCount: nonTermCount, - symTab: gram.symbolTable, - } - ptab, err = slr.build() - if err != nil { - t.Fatalf("failed to create a SLR parsing table: %v", err) - } - if ptab == nil { - t.Fatal("genSLRParsingTable returns nil without any error") - } - } - - genSym := newTestSymbolGenerator(t, gram.symbolTable) - genProd := newTestProductionGenerator(t, genSym) - genLR0Item := newTestLR0ItemGenerator(t, genProd) - - expectedKernels := map[int][]*lrItem{ - 0: { - genLR0Item("expr'", 0, "expr"), - }, - 1: { - genLR0Item("expr'", 1, "expr"), - genLR0Item("expr", 1, "expr", "add", "term"), - }, - 2: { - genLR0Item("expr", 1, "term"), - genLR0Item("term", 1, "term", "mul", "factor"), - }, - 3: { - genLR0Item("term", 1, "factor"), - }, - 4: { - genLR0Item("factor", 1, "l_paren", "expr", "r_paren"), - }, - 5: { - genLR0Item("factor", 1, "id"), - }, - 6: { - genLR0Item("expr", 2, "expr", "add", "term"), - }, - 7: { - genLR0Item("term", 2, "term", "mul", "factor"), - }, - 8: { - genLR0Item("expr", 1, "expr", "add", "term"), - genLR0Item("factor", 2, "l_paren", "expr", "r_paren"), - }, - 9: { - genLR0Item("expr", 3, "expr", "add", "term"), - genLR0Item("term", 1, "term", "mul", "factor"), - }, - 10: { - genLR0Item("term", 3, "term", "mul", "factor"), - }, - 11: { - genLR0Item("factor", 3, "l_paren", "expr", "r_paren"), - }, - } - - expectedStates := []expectedState{ - { - kernelItems: expectedKernels[0], - acts: map[symbol]testActionEntry{ - genSym("l_paren"): { - ty: ActionTypeShift, - nextState: expectedKernels[4], - }, - genSym("id"): { - ty: ActionTypeShift, - nextState: expectedKernels[5], - }, - }, - goTos: map[symbol][]*lrItem{ - genSym("expr"): expectedKernels[1], - genSym("term"): expectedKernels[2], - genSym("factor"): expectedKernels[3], - }, - }, - { - kernelItems: expectedKernels[1], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeShift, - nextState: expectedKernels[6], - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("expr'", "expr"), - }, - }, - }, - { - kernelItems: expectedKernels[2], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("expr", "term"), - }, - genSym("mul"): { - ty: ActionTypeShift, - nextState: expectedKernels[7], - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("expr", "term"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("expr", "term"), - }, - }, - }, - { - kernelItems: expectedKernels[3], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("term", "factor"), - }, - genSym("mul"): { - ty: ActionTypeReduce, - production: genProd("term", "factor"), - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("term", "factor"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("term", "factor"), - }, - }, - }, - { - kernelItems: expectedKernels[4], - acts: map[symbol]testActionEntry{ - genSym("l_paren"): { - ty: ActionTypeShift, - nextState: expectedKernels[4], - }, - genSym("id"): { - ty: ActionTypeShift, - nextState: expectedKernels[5], - }, - }, - goTos: map[symbol][]*lrItem{ - genSym("expr"): expectedKernels[8], - genSym("term"): expectedKernels[2], - genSym("factor"): expectedKernels[3], - }, - }, - { - kernelItems: expectedKernels[5], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("factor", "id"), - }, - genSym("mul"): { - ty: ActionTypeReduce, - production: genProd("factor", "id"), - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("factor", "id"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("factor", "id"), - }, - }, - }, - { - kernelItems: expectedKernels[6], - acts: map[symbol]testActionEntry{ - genSym("l_paren"): { - ty: ActionTypeShift, - nextState: expectedKernels[4], - }, - genSym("id"): { - ty: ActionTypeShift, - nextState: expectedKernels[5], - }, - }, - goTos: map[symbol][]*lrItem{ - genSym("term"): expectedKernels[9], - genSym("factor"): expectedKernels[3], - }, - }, - { - kernelItems: expectedKernels[7], - acts: map[symbol]testActionEntry{ - genSym("l_paren"): { - ty: ActionTypeShift, - nextState: expectedKernels[4], - }, - genSym("id"): { - ty: ActionTypeShift, - nextState: expectedKernels[5], - }, - }, - goTos: map[symbol][]*lrItem{ - genSym("factor"): expectedKernels[10], - }, - }, - { - kernelItems: expectedKernels[8], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeShift, - nextState: expectedKernels[6], - }, - genSym("r_paren"): { - ty: ActionTypeShift, - nextState: expectedKernels[11], - }, - }, - }, - { - kernelItems: expectedKernels[9], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("expr", "expr", "add", "term"), - }, - genSym("mul"): { - ty: ActionTypeShift, - nextState: expectedKernels[7], - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("expr", "expr", "add", "term"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("expr", "expr", "add", "term"), - }, - }, - }, - { - kernelItems: expectedKernels[10], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("term", "term", "mul", "factor"), - }, - genSym("mul"): { - ty: ActionTypeReduce, - production: genProd("term", "term", "mul", "factor"), - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("term", "term", "mul", "factor"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("term", "term", "mul", "factor"), - }, - }, - }, - { - kernelItems: expectedKernels[11], - acts: map[symbol]testActionEntry{ - genSym("add"): { - ty: ActionTypeReduce, - production: genProd("factor", "l_paren", "expr", "r_paren"), - }, - genSym("mul"): { - ty: ActionTypeReduce, - production: genProd("factor", "l_paren", "expr", "r_paren"), - }, - genSym("r_paren"): { - ty: ActionTypeReduce, - production: genProd("factor", "l_paren", "expr", "r_paren"), - }, - symbolEOF: { - ty: ActionTypeReduce, - production: genProd("factor", "l_paren", "expr", "r_paren"), - }, - }, - }, - } - - t.Run("initial state", func(t *testing.T) { - iniState := findStateByNum(automaton.states, ptab.InitialState) - if iniState == nil { - t.Fatalf("the initial state was not found: #%v", ptab.InitialState) - } - eIniState, err := newKernel(expectedKernels[0]) - if err != nil { - t.Fatalf("failed to create a kernel item: %v", err) - } - if iniState.id != eIniState.id { - t.Fatalf("the initial state is mismatched; want: %v, got: %v", eIniState.id, iniState.id) - } - }) - - for i, eState := range expectedStates { - t.Run(fmt.Sprintf("#%v", i), func(t *testing.T) { - k, err := newKernel(eState.kernelItems) - if err != nil { - t.Fatalf("failed to create a kernel item: %v", err) - } - state, ok := automaton.states[k.id] - if !ok { - t.Fatalf("state was not found: #%v", 0) - } - - testAction(t, &eState, state, ptab, automaton.lr0Automaton, gram, termCount) - testGoTo(t, &eState, state, ptab, automaton.lr0Automaton, nonTermCount) - }) - } -} - func testAction(t *testing.T, expectedState *expectedState, state *lrState, ptab *ParsingTable, automaton *lr0Automaton, gram *Grammar, termCount int) { nonEmptyEntries := map[symbolNum]struct{}{} for eSym, eAct := range expectedState.acts { diff --git a/grammar/slr1.go b/grammar/slr1.go deleted file mode 100644 index b11a66f..0000000 --- a/grammar/slr1.go +++ /dev/null @@ -1,61 +0,0 @@ -package grammar - -import "fmt" - -type slr1Automaton struct { - *lr0Automaton -} - -func genSLR1Automaton(lr0 *lr0Automaton, prods *productionSet, follow *followSet) (*slr1Automaton, error) { - for _, state := range lr0.states { - for prodID := range state.reducible { - prod, ok := prods.findByID(prodID) - if !ok { - return nil, fmt.Errorf("reducible production not found: %v", prodID) - } - - flw, err := follow.find(prod.lhs) - if err != nil { - return nil, err - } - - var reducibleItem *lrItem - for _, item := range state.items { - if item.prod != prodID { - continue - } - - reducibleItem = item - break - } - if reducibleItem == nil { - for _, item := range state.emptyProdItems { - if item.prod != prodID { - continue - } - - reducibleItem = item - break - } - if reducibleItem == nil { - return nil, fmt.Errorf("reducible item not found; state: %v, production: %v", state.num, prodID) - } - } - - if reducibleItem.lookAhead.symbols == nil { - reducibleItem.lookAhead.symbols = map[symbol]struct{}{} - } - - for sym := range flw.symbols { - reducibleItem.lookAhead.symbols[sym] = struct{}{} - } - if flw.eof { - reducibleItem.lookAhead.symbols[symbolEOF] = struct{}{} - } - } - } - - return &slr1Automaton{ - lr0Automaton: lr0, - }, nil -} diff --git a/grammar/slr1_test.go b/grammar/slr1_test.go deleted file mode 100644 index 6748802..0000000 --- a/grammar/slr1_test.go +++ /dev/null @@ -1,233 +0,0 @@ -package grammar - -import ( - "strings" - "testing" - - "github.com/nihei9/vartan/spec" -) - -func TestGenSLR1Automaton(t *testing.T) { - src := ` -#name test; - -expr - : expr add term - | term - ; -term - : term mul factor - | factor - ; -factor - : l_paren expr r_paren - | id - ; -add: "\+"; -mul: "\*"; -l_paren: "\("; -r_paren: "\)"; -id: "[A-Za-z_][0-9A-Za-z_]*"; -` - - var gram *Grammar - var automaton *slr1Automaton - { - ast, err := spec.Parse(strings.NewReader(src)) - if err != nil { - t.Fatal(err) - } - b := GrammarBuilder{ - AST: ast, - } - - gram, err = b.Build() - if err != nil { - t.Fatal(err) - } - - lr0, err := genLR0Automaton(gram.productionSet, gram.augmentedStartSymbol, gram.errorSymbol) - if err != nil { - t.Fatalf("failed to create a LR0 automaton: %v", err) - } - - firstSet, err := genFirstSet(gram.productionSet) - if err != nil { - t.Fatalf("failed to create a FIRST set: %v", err) - } - - followSet, err := genFollowSet(gram.productionSet, firstSet) - if err != nil { - t.Fatalf("failed to create a FOLLOW set: %v", err) - } - - automaton, err = genSLR1Automaton(lr0, gram.productionSet, followSet) - if err != nil { - t.Fatalf("failed to create a SLR1 automaton: %v", err) - } - if automaton == nil { - t.Fatalf("genSLR1Automaton returns nil without any error") - } - } - - initialState := automaton.states[automaton.initialState] - if initialState == nil { - t.Errorf("failed to get an initial status: %v", automaton.initialState) - } - - genSym := newTestSymbolGenerator(t, gram.symbolTable) - genProd := newTestProductionGenerator(t, genSym) - genLR0Item := newTestLR0ItemGenerator(t, genProd) - - expectedKernels := map[int][]*lrItem{ - 0: { - genLR0Item("expr'", 0, "expr"), - }, - 1: { - withLookAhead(genLR0Item("expr'", 1, "expr"), symbolEOF), - genLR0Item("expr", 1, "expr", "add", "term"), - }, - 2: { - withLookAhead(genLR0Item("expr", 1, "term"), genSym("add"), genSym("r_paren"), symbolEOF), - genLR0Item("term", 1, "term", "mul", "factor"), - }, - 3: { - withLookAhead(genLR0Item("term", 1, "factor"), genSym("add"), genSym("mul"), genSym("r_paren"), symbolEOF), - }, - 4: { - genLR0Item("factor", 1, "l_paren", "expr", "r_paren"), - }, - 5: { - withLookAhead(genLR0Item("factor", 1, "id"), genSym("add"), genSym("mul"), genSym("r_paren"), symbolEOF), - }, - 6: { - genLR0Item("expr", 2, "expr", "add", "term"), - }, - 7: { - genLR0Item("term", 2, "term", "mul", "factor"), - }, - 8: { - genLR0Item("expr", 1, "expr", "add", "term"), - genLR0Item("factor", 2, "l_paren", "expr", "r_paren"), - }, - 9: { - withLookAhead(genLR0Item("expr", 3, "expr", "add", "term"), genSym("add"), genSym("r_paren"), symbolEOF), - genLR0Item("term", 1, "term", "mul", "factor"), - }, - 10: { - withLookAhead(genLR0Item("term", 3, "term", "mul", "factor"), genSym("add"), genSym("mul"), genSym("r_paren"), symbolEOF), - }, - 11: { - withLookAhead(genLR0Item("factor", 3, "l_paren", "expr", "r_paren"), genSym("add"), genSym("mul"), genSym("r_paren"), symbolEOF), - }, - } - - expectedStates := []*expectedLRState{ - { - kernelItems: expectedKernels[0], - nextStates: map[symbol][]*lrItem{ - genSym("expr"): expectedKernels[1], - genSym("term"): expectedKernels[2], - genSym("factor"): expectedKernels[3], - genSym("l_paren"): expectedKernels[4], - genSym("id"): expectedKernels[5], - }, - reducibleProds: []*production{}, - }, - { - kernelItems: expectedKernels[1], - nextStates: map[symbol][]*lrItem{ - genSym("add"): expectedKernels[6], - }, - reducibleProds: []*production{ - genProd("expr'", "expr"), - }, - }, - { - kernelItems: expectedKernels[2], - nextStates: map[symbol][]*lrItem{ - genSym("mul"): expectedKernels[7], - }, - reducibleProds: []*production{ - genProd("expr", "term"), - }, - }, - { - kernelItems: expectedKernels[3], - nextStates: map[symbol][]*lrItem{}, - reducibleProds: []*production{ - genProd("term", "factor"), - }, - }, - { - kernelItems: expectedKernels[4], - nextStates: map[symbol][]*lrItem{ - genSym("expr"): expectedKernels[8], - genSym("term"): expectedKernels[2], - genSym("factor"): expectedKernels[3], - genSym("l_paren"): expectedKernels[4], - genSym("id"): expectedKernels[5], - }, - reducibleProds: []*production{}, - }, - { - kernelItems: expectedKernels[5], - nextStates: map[symbol][]*lrItem{}, - reducibleProds: []*production{ - genProd("factor", "id"), - }, - }, - { - kernelItems: expectedKernels[6], - nextStates: map[symbol][]*lrItem{ - genSym("term"): expectedKernels[9], - genSym("factor"): expectedKernels[3], - genSym("l_paren"): expectedKernels[4], - genSym("id"): expectedKernels[5], - }, - reducibleProds: []*production{}, - }, - { - kernelItems: expectedKernels[7], - nextStates: map[symbol][]*lrItem{ - genSym("factor"): expectedKernels[10], - genSym("l_paren"): expectedKernels[4], - genSym("id"): expectedKernels[5], - }, - reducibleProds: []*production{}, - }, - { - kernelItems: expectedKernels[8], - nextStates: map[symbol][]*lrItem{ - genSym("add"): expectedKernels[6], - genSym("r_paren"): expectedKernels[11], - }, - reducibleProds: []*production{}, - }, - { - kernelItems: expectedKernels[9], - nextStates: map[symbol][]*lrItem{ - genSym("mul"): expectedKernels[7], - }, - reducibleProds: []*production{ - genProd("expr", "expr", "add", "term"), - }, - }, - { - kernelItems: expectedKernels[10], - nextStates: map[symbol][]*lrItem{}, - reducibleProds: []*production{ - genProd("term", "term", "mul", "factor"), - }, - }, - { - kernelItems: expectedKernels[11], - nextStates: map[symbol][]*lrItem{}, - reducibleProds: []*production{ - genProd("factor", "l_paren", "expr", "r_paren"), - }, - }, - } - - testLRAutomaton(t, expectedStates, automaton.lr0Automaton) -} |