Пример #1
0
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
}
Пример #2
0
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()
}
Пример #3
0
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
}
Пример #4
0
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
}