func (p *Parser) computeReachableItemSetKernels(itemSet *ItemSet) ([]syms.SymbolID, map[syms.SymbolID]ItemSet) { sym2isker := make(map[syms.SymbolID]ItemSet) for _, dotRule := range sortedDotRules(*itemSet) { rhs := p.Rules.Get(dotRule.ruleID).RHS if dotRule.dotPos >= len(rhs) { continue } dotSymbol := rhs[dotRule.dotPos] newDotRule := DotRule{dotRule.ruleID, dotRule.dotPos + 1} if isker, ok := sym2isker[dotSymbol]; ok { isker.dotRules[newDotRule] = true // is a kernel rule } else { isker = ItemSet{ make(map[DotRule]bool), make(map[syms.SymbolID]ItemSetID), } isker.dotRules[newDotRule] = true // is a kernel rule sym2isker[dotSymbol] = isker } } symbols := make([]syms.SymbolID, len(sym2isker)) symIndex := 0 for sid := range sym2isker { symbols[symIndex] = sid symIndex++ } symbols = syms.SortedSymbols(symbols) return symbols, sym2isker }
func (p *Parser) sprintTransitions(transitions map[syms.SymbolID]ItemSetID) string { var b bytes.Buffer symbols := make([]syms.SymbolID, 0, 0) for sid := range transitions { symbols = append(symbols, sid) } for _, sid := range syms.SortedSymbols(symbols) { b.WriteString(fmt.Sprint(p.Syms.Get(sid).Name, " -> ", transitions[sid], " ; ")) } return b.String() }
func (p *Parser) symNames(m map[syms.SymbolID]Action) []string { fsid := make([]syms.SymbolID, 0, 10) for sid := range m { fsid = append(fsid, sid) } f := make([]string, 0, 10) for _, sid := range syms.SortedSymbols(fsid) { str := p.Syms.Get(sid).Name f = append(f, str) } return f }
func (p *Parser) buildParseTable() error { // defer tlog.FuncLog(tlog.Func("buildParseTable")) symNames := func(m map[syms.SymbolID]bool) []string { fsid := make([]syms.SymbolID, 0, 10) for sid := range m { fsid = append(fsid, sid) } f := make([]string, 0, 10) for _, sid := range syms.SortedSymbols(fsid) { f = append(f, p.Syms.Get(sid).Name) } return f } // build first sets for extended symbols first := make(map[ExtSymbol]map[syms.SymbolID]bool) { addFirst := func(sym ExtSymbol, symfirst syms.SymbolID) bool { m, ok := first[sym] if !ok { m = make(map[syms.SymbolID]bool) first[sym] = m } if _, exists := m[symfirst]; exists { return false } m[symfirst] = true return true } for _, extrule := range p.extRules { for _, exts := range extrule.rhs { if p.Syms.Get(exts.symbolID).IsTerm { addFirst(exts, exts.symbolID) } } } loop := true for loop { loop = false for i := len(p.extRules) - 1; i >= 0; i-- { extrule := p.extRules[i] // fmt.Println("test first for rule: ", g.ExtRuleString(extrule)) if len(extrule.rhs) == 0 { loop = addFirst(extrule.lhs, syms.EMPTY) || loop } for idx, exts := range extrule.rhs { for x := range first[exts] { if x != syms.EMPTY { loop = addFirst(extrule.lhs, x) || loop } } if !first[exts][syms.EMPTY] { break } else if idx == len(extrule.rhs)-1 { loop = addFirst(extrule.lhs, syms.EMPTY) || loop } } } } } if p.debug { fmt.Println("\nfirstSet:") for exts := range first { fmt.Println(p.ExtSymString(exts), symNames(first[exts])) } } // build follow sets for extended symbols follow := make(map[ExtSymbol]map[syms.SymbolID]bool) { addFollow := func(sym ExtSymbol, symfollow syms.SymbolID) bool { m, ok := follow[sym] if !ok { m = make(map[syms.SymbolID]bool) follow[sym] = m } if _, exists := m[symfollow]; exists { return false } m[symfollow] = true return true } addFollow(p.extRules[0].lhs, syms.EOF) loop := true for loop { loop = false for i := len(p.extRules) - 1; i >= 0; i-- { extrule := p.extRules[i] // fmt.Println("test follow for rule: ", g.ExtRuleString(extrule)) for idx, exts := range extrule.rhs { if p.Syms.Get(exts.symbolID).IsTerm { continue } if idx == len(extrule.rhs)-1 { for x := range follow[extrule.lhs] { loop = addFollow(exts, x) || loop } } for idx2, exts2 := range extrule.rhs[idx+1:] { // fmt.Println("test follow for pair: ", p.ExtSymString(exts), p.ExtSymString(exts2)) for x := range first[exts2] { if x != syms.EMPTY { loop = addFollow(exts, x) || loop } } if !first[exts2][syms.EMPTY] { break } else if idx2 == len(extrule.rhs)-1 { for x := range follow[extrule.lhs] { loop = addFollow(exts, x) || loop } } } // fmt.Println("added follow of: ", p.ExtSymString(exts), symNames(follow[exts])) } } } } if p.debug { fmt.Println("\nfollowSet:") for exts := range follow { fmt.Println(p.ExtSymString(exts), symNames(follow[exts])) } } // then the action/goto table p.parsetable = make([]map[syms.SymbolID]Action, len(p.itemSets)) { for isID, is := range p.itemSets { m := make(map[syms.SymbolID]Action, len(is.transitions)) for sid, endIsID := range is.transitions { if p.Syms.Get(sid).IsTerm { m[sid] = Action{actiontype: Shift, state: endIsID, ruleID: -1} } else { m[sid] = Action{actiontype: Goto, state: endIsID, ruleID: -1} } } p.parsetable[isID] = m } // Reduce actions: warnings := make(map[grammar.RuleID]bool) for _, extrule := range p.extRules { if len(extrule.rhs) == 0 { continue } lastState := extrule.rhs[len(extrule.rhs)-1].stop transitions := p.parsetable[lastState] // fmt.Println("parsetable from rule ", g.ExtRuleString(extrule)) for term := range follow[extrule.lhs] { act, found := transitions[term] newact := Action{actiontype: Reduce, state: -1, ruleID: extrule.original} // fmt.Println("add transition:", lastState, " for term ", p.symbols.name(term)) if found && act != newact { if !warnings[extrule.original] { msg := fmt.Sprint("shift/reduce conflict on term: ", p.Syms.Get(term).Name, "\naction: ", act, "\nnewaction: ", newact, "\nreduce by rule: ", p.Rules.Get(extrule.original).String(*p.Syms, -1)) log.Printf("Warning:\n%s\n", msg) warnings[extrule.original] = true } // return GrammarConflictError(msg) } else { transitions[term] = newact } } } } if p.debug { fmt.Println("\nparsetable:") for state, m := range p.parsetable { fmt.Println(state, " -> ") for sid, a := range m { fmt.Println("\t", p.Syms.Get(sid).Name, ":", a) } } } return nil }