diff options
Diffstat (limited to 'grammar/parsing_table_builder.go')
-rw-r--r-- | grammar/parsing_table_builder.go | 201 |
1 files changed, 46 insertions, 155 deletions
diff --git a/grammar/parsing_table_builder.go b/grammar/parsing_table_builder.go index e209c94..82b0d34 100644 --- a/grammar/parsing_table_builder.go +++ b/grammar/parsing_table_builder.go @@ -165,8 +165,8 @@ func (t *ParsingTable) writeGoTo(state stateNum, sym symbol, nextState stateNum) t.goToTable[pos] = newGoToEntry(nextState) } -type lalrTableBuilder struct { - automaton *lalr1Automaton +type lrTableBuilder struct { + automaton *lr0Automaton prods *productionSet termCount int nonTermCount int @@ -176,7 +176,7 @@ type lalrTableBuilder struct { conflicts []conflict } -func (b *lalrTableBuilder) build() (*ParsingTable, error) { +func (b *lrTableBuilder) build() (*ParsingTable, error) { var ptab *ParsingTable { initialState := b.automaton.states[b.automaton.initialState] @@ -262,104 +262,9 @@ func (b *lalrTableBuilder) build() (*ParsingTable, error) { return ptab, nil } -type slrTableBuilder struct { - automaton *lr0Automaton - prods *productionSet - follow *followSet - termCount int - nonTermCount int - symTab *symbolTable - sym2AnonPat map[symbol]string - - conflicts []conflict -} - -func (b *slrTableBuilder) build() (*ParsingTable, error) { - var ptab *ParsingTable - { - initialState := b.automaton.states[b.automaton.initialState] - ptab = &ParsingTable{ - actionTable: make([]actionEntry, len(b.automaton.states)*b.termCount), - goToTable: make([]goToEntry, len(b.automaton.states)*b.nonTermCount), - stateCount: len(b.automaton.states), - terminalCount: b.termCount, - nonTerminalCount: b.nonTermCount, - expectedTerminals: make([][]int, len(b.automaton.states)), - InitialState: initialState.num, - } - } - - var conflicts []conflict - for _, state := range b.automaton.states { - var eTerms []int - - for sym, kID := range state.next { - nextState := b.automaton.states[kID] - if sym.isTerminal() { - eTerms = append(eTerms, sym.num().Int()) - - c := ptab.writeShiftAction(state.num, sym, nextState.num) - if c != nil { - conflicts = append(conflicts, c) - continue - } - } else { - ptab.writeGoTo(state.num, sym, nextState.num) - } - } - - for prodID := range state.reducible { - prod, _ := b.prods.findByID(prodID) - flw, err := b.follow.find(prod.lhs) - if err != nil { - return nil, err - } - for sym := range flw.symbols { - eTerms = append(eTerms, sym.num().Int()) - - c := ptab.writeReduceAction(state.num, sym, prod.num) - if c != nil { - conflicts = append(conflicts, c) - continue - } - } - if flw.eof { - eTerms = append(eTerms, symbolEOF.num().Int()) - - c := ptab.writeReduceAction(state.num, symbolEOF, prod.num) - if c != nil { - conflicts = append(conflicts, c) - continue - } - } - } - - ptab.expectedTerminals[state.num] = eTerms - } - - b.conflicts = conflicts - - if len(conflicts) > 0 { - return nil, fmt.Errorf("%v conflicts", len(conflicts)) - } - - return ptab, nil -} - -type descriptionWriter struct { - automaton *lr0Automaton - prods *productionSet - follow *followSet - termCount int - nonTermCount int - symTab *symbolTable - sym2AnonPat map[symbol]string - conflicts []conflict -} - -func (dw *descriptionWriter) write(w io.Writer) { +func (b *lrTableBuilder) write(w io.Writer) { conflicts := map[stateNum][]conflict{} - for _, con := range dw.conflicts { + for _, con := range b.conflicts { switch c := con.(type) { case *shiftReduceConflict: conflicts[c.state] = append(conflicts[c.state], c) @@ -370,15 +275,15 @@ func (dw *descriptionWriter) write(w io.Writer) { fmt.Fprintf(w, "# Conflicts\n\n") - if len(dw.conflicts) > 0 { - fmt.Fprintf(w, "%v conflics:\n\n", len(dw.conflicts)) + if len(b.conflicts) > 0 { + fmt.Fprintf(w, "%v conflics:\n\n", len(b.conflicts)) - for _, conflict := range dw.conflicts { + for _, conflict := range b.conflicts { switch c := conflict.(type) { case *shiftReduceConflict: - fmt.Fprintf(w, "%v: shift/reduce conflict (shift %v, reduce %v) on %v\n", c.state, c.nextState, c.prodNum, dw.symbolToText(c.sym)) + fmt.Fprintf(w, "%v: shift/reduce conflict (shift %v, reduce %v) on %v\n", c.state, c.nextState, c.prodNum, b.symbolToText(c.sym)) case *reduceReduceConflict: - fmt.Fprintf(w, "%v: reduce/reduce conflict (reduce %v and %v) on %v\n", c.state, c.prodNum1, c.prodNum2, dw.symbolToText(c.sym)) + fmt.Fprintf(w, "%v: reduce/reduce conflict (reduce %v and %v) on %v\n", c.state, c.prodNum1, c.prodNum2, b.symbolToText(c.sym)) } } fmt.Fprintf(w, "\n") @@ -388,17 +293,17 @@ func (dw *descriptionWriter) write(w io.Writer) { fmt.Fprintf(w, "# Terminals\n\n") - termSyms := dw.symTab.terminalSymbols() + termSyms := b.symTab.terminalSymbols() fmt.Fprintf(w, "%v symbols:\n\n", len(termSyms)) for _, sym := range termSyms { - text, ok := dw.symTab.toText(sym) + text, ok := b.symTab.toText(sym) if !ok { text = fmt.Sprintf("<symbol not found: %v>", sym) } if strings.HasPrefix(text, "_") { - fmt.Fprintf(w, "%4v %v: \"%v\"\n", sym.num(), text, dw.sym2AnonPat[sym]) + fmt.Fprintf(w, "%4v %v: \"%v\"\n", sym.num(), text, b.sym2AnonPat[sym]) } else { fmt.Fprintf(w, "%4v %v\n", sym.num(), text) } @@ -408,25 +313,25 @@ func (dw *descriptionWriter) write(w io.Writer) { fmt.Fprintf(w, "# Productions\n\n") - fmt.Fprintf(w, "%v productions:\n\n", len(dw.prods.getAllProductions())) + fmt.Fprintf(w, "%v productions:\n\n", len(b.prods.getAllProductions())) - for _, prod := range dw.prods.getAllProductions() { - fmt.Fprintf(w, "%4v %v\n", prod.num, dw.productionToString(prod, -1)) + for _, prod := range b.prods.getAllProductions() { + fmt.Fprintf(w, "%4v %v\n", prod.num, b.productionToString(prod, -1)) } fmt.Fprintf(w, "\n# States\n\n") - fmt.Fprintf(w, "%v states:\n\n", len(dw.automaton.states)) + fmt.Fprintf(w, "%v states:\n\n", len(b.automaton.states)) - for _, state := range dw.automaton.states { + for _, state := range b.automaton.states { fmt.Fprintf(w, "state %v\n", state.num) for _, item := range state.items { - prod, ok := dw.prods.findByID(item.prod) + prod, ok := b.prods.findByID(item.prod) if !ok { fmt.Fprintf(w, "<production not found>\n") continue } - fmt.Fprintf(w, " %v\n", dw.productionToString(prod, item.dot)) + fmt.Fprintf(w, " %v\n", b.productionToString(prod, item.dot)) } fmt.Fprintf(w, "\n") @@ -437,16 +342,16 @@ func (dw *descriptionWriter) write(w io.Writer) { var accRec string { for sym, kID := range state.next { - nextState := dw.automaton.states[kID] + nextState := b.automaton.states[kID] if sym.isTerminal() { - shiftRecs = append(shiftRecs, fmt.Sprintf("shift %4v on %v", nextState.num, dw.symbolToText(sym))) + shiftRecs = append(shiftRecs, fmt.Sprintf("shift %4v on %v", nextState.num, b.symbolToText(sym))) } else { - gotoRecs = append(gotoRecs, fmt.Sprintf("goto %4v on %v", nextState.num, dw.symbolToText(sym))) + gotoRecs = append(gotoRecs, fmt.Sprintf("goto %4v on %v", nextState.num, b.symbolToText(sym))) } } for prodID := range state.reducible { - prod, ok := dw.prods.findByID(prodID) + prod, ok := b.prods.findByID(prodID) if !ok { reduceRecs = append(reduceRecs, "<production not found>") continue @@ -456,21 +361,17 @@ func (dw *descriptionWriter) write(w io.Writer) { continue } - if dw.follow != nil { - flw, err := dw.follow.find(prod.lhs) - if err != nil { - reduceRecs = append(reduceRecs, fmt.Sprintf("%v", err)) + var reducibleItem *lrItem + for _, item := range state.items { + if item.prod != prodID { continue } - for sym := range flw.symbols { - reduceRecs = append(reduceRecs, fmt.Sprintf("reduce %4v on %v", prod.num, dw.symbolToText(sym))) - } - if flw.eof { - reduceRecs = append(reduceRecs, fmt.Sprintf("reduce %4v on <EOF>", prod.num)) - } - } else { - var reducibleItem *lrItem - for _, item := range state.items { + + reducibleItem = item + break + } + if reducibleItem == nil { + for _, item := range state.emptyProdItems { if item.prod != prodID { continue } @@ -479,23 +380,13 @@ func (dw *descriptionWriter) write(w io.Writer) { break } if reducibleItem == nil { - for _, item := range state.emptyProdItems { - if item.prod != prodID { - continue - } - - reducibleItem = item - break - } - if reducibleItem == nil { - reduceRecs = append(reduceRecs, "<item not found>") - continue - } - } - for a := range reducibleItem.lookAhead.symbols { - reduceRecs = append(reduceRecs, fmt.Sprintf("reduce %4v on %v", prod.num, dw.symbolToText(a))) + reduceRecs = append(reduceRecs, "<item not found>") + continue } } + for a := range reducibleItem.lookAhead.symbols { + reduceRecs = append(reduceRecs, fmt.Sprintf("reduce %4v on %v", prod.num, b.symbolToText(a))) + } } } @@ -523,9 +414,9 @@ func (dw *descriptionWriter) write(w io.Writer) { for _, con := range cons { switch c := con.(type) { case *shiftReduceConflict: - fmt.Fprintf(w, " shift/reduce conflict (shift %v, reduce %v) on %v\n", c.nextState, c.prodNum, dw.symbolToText(c.sym)) + fmt.Fprintf(w, " shift/reduce conflict (shift %v, reduce %v) on %v\n", c.nextState, c.prodNum, b.symbolToText(c.sym)) case *reduceReduceConflict: - fmt.Fprintf(w, " reduce/reduce conflict (reduce %v and %v) on %v\n", c.prodNum1, c.prodNum2, dw.symbolToText(c.sym)) + fmt.Fprintf(w, " reduce/reduce conflict (reduce %v and %v) on %v\n", c.prodNum1, c.prodNum2, b.symbolToText(c.sym)) } } fmt.Fprintf(w, "\n") @@ -533,14 +424,14 @@ func (dw *descriptionWriter) write(w io.Writer) { } } -func (dw *descriptionWriter) productionToString(prod *production, dot int) string { +func (b *lrTableBuilder) productionToString(prod *production, dot int) string { var w strings.Builder - fmt.Fprintf(&w, "%v →", dw.symbolToText(prod.lhs)) + fmt.Fprintf(&w, "%v →", b.symbolToText(prod.lhs)) for n, rhs := range prod.rhs { if n == dot { fmt.Fprintf(&w, " ・") } - fmt.Fprintf(&w, " %v", dw.symbolToText(rhs)) + fmt.Fprintf(&w, " %v", b.symbolToText(rhs)) } if dot == len(prod.rhs) { fmt.Fprintf(&w, " ・") @@ -549,7 +440,7 @@ func (dw *descriptionWriter) productionToString(prod *production, dot int) strin return w.String() } -func (dw *descriptionWriter) symbolToText(sym symbol) string { +func (b *lrTableBuilder) symbolToText(sym symbol) string { if sym.isNil() { return "<NULL>" } @@ -557,13 +448,13 @@ func (dw *descriptionWriter) symbolToText(sym symbol) string { return "<EOF>" } - text, ok := dw.symTab.toText(sym) + text, ok := b.symTab.toText(sym) if !ok { return fmt.Sprintf("<symbol not found: %v>", sym) } if strings.HasPrefix(text, "_") { - pat, ok := dw.sym2AnonPat[sym] + pat, ok := b.sym2AnonPat[sym] if !ok { return fmt.Sprintf("<pattern not found: %v>", text) } |