예제 #1
0
파일: nnf_test.go 프로젝트: dtromb/parser
func TestNNF(t *testing.T) {
	// Build a simple BNF aGrammar description aGrammar.
	gb := parser.OpenGrammarBuilder()

	gb.Name("a4").
		Terminals("a").
		Nonterminals("S", "A", "E").
		Rule().Lhs("`*").Rhs("S", "`.").
		Rule().Lhs("S").Rhs("A", "A", "A", "A").
		Rule().Lhs("A").Rhs("a").
		Rule().Lhs("A").Rhs("E").
		Rule().Lhs("E").Rhs("`e")

	g, err := gb.Build()
	if err != nil {
		t.Error(err)
		return
	}

	var aGrammar parser.Grammar
	var rTransform parser.SyntaxTreeTransform

	nnf, err := IsNihilisticNormalForm(g)
	if err != nil {
		t.Error()
		return
	}
	if !nnf {
		fmt.Println("Grammar is not NNF, transforming.")
		aGrammar, rTransform, err = GetNihilisticAugmentGrammar(g)
		if err != nil {
			t.Error(err)
			return
		}
	} else {
		t.Error("Grammar returned NNF.")
		return
	}

	fmt.Println("Name: " + aGrammar.Name())
	terms := make([]string, aGrammar.NumTerminals())
	for i, t := range aGrammar.Terminals() {
		terms[i] = t.String()
	}
	nterms := make([]string, aGrammar.NumNonterminals())
	for i, t := range aGrammar.Nonterminals() {
		nterms[i] = t.String()
	}
	fmt.Println("Terminals: " + strings.Join(terms, ", "))
	fmt.Println("Nonterminals: " + strings.Join(nterms, ", "))
	fmt.Println("Productions:")
	for _, p := range aGrammar.Productions() {
		fmt.Println("   " + p.String())
	}
	rTransform = rTransform
}
예제 #2
0
파일: class.go 프로젝트: dtromb/parser
func (gci *GrammarClassIndex) Initialize(g parser.Grammar) error {
	gci.g = g
	gci.gclass = parser.CONSTANT
	gci.greg = parser.STRICT_UNITARY
	for _, p := range g.Productions() {
		if p.Lhs(0).Asterisk() {
			continue
		}
		preg := parser.GetProductionClass(p)
		if preg > gci.gclass {
			gci.gclass = preg
			if gci.gclass > parser.REGULAR {
				gci.greg = parser.NONREGULAR
			}
		}
		if gci.gclass <= parser.REGULAR {
			gci.greg = gci.greg.Join(parser.GetProductionRegularity(p))
		}
	}
	return nil
}
예제 #3
0
파일: name.go 프로젝트: dtromb/parser
func (ni *NameIndex) Initialize(g parser.Grammar) error {
	ni.nonterminalsByName = make(map[string]parser.GrammarParticle)
	ni.terminalsByName = make(map[string]parser.GrammarParticle)
	for i := 0; i < g.NumNonterminals(); i++ {
		nt := g.Nonterminal(i)
		ni.nonterminalsByName[nt.Name()] = nt
	}
	for i := 0; i < g.NumTerminals(); i++ {
		t := g.Terminal(i)
		ni.terminalsByName[t.Name()] = t
	}
	ni.lhsNames = make(map[string][]parser.Production)
	ni.rhsNames = make(map[string][]parser.Production)
	for _, p := range g.Productions() {
		var rhs, lhs []byte
		for i := 0; i < p.LhsLen(); i++ {
			lhs = append(lhs, p.Lhs(i).Name()...)
			if i < p.LhsLen()-1 {
				lhs = append(lhs, "|"...)
			}
		}
		if _, has := ni.lhsNames[string(lhs)]; !has {
			ni.lhsNames[string(lhs)] = []parser.Production{}
		}
		ni.lhsNames[string(lhs)] = append(ni.lhsNames[string(lhs)], p)
		for i := 0; i < p.RhsLen(); i++ {
			rhs = append(rhs, p.Rhs(i).Name()...)
			if i < p.RhsLen()-1 {
				rhs = append(rhs, "|"...)
			}
		}
		if _, has := ni.rhsNames[string(rhs)]; !has {
			ni.rhsNames[string(rhs)] = []parser.Production{}
		}
		ni.rhsNames[string(rhs)] = append(ni.rhsNames[string(rhs)], p)
	}
	return nil
}
예제 #4
0
파일: basic.go 프로젝트: dtromb/parser
func (bgi *BasicGrammarIndex) Initialize(g parser.Grammar) error {
	bgi.grammar = g
	bgi.epsilons = make(map[parser.GrammarParticle]parser.Production)
	bgi.lhsIncludes = make(map[parser.GrammarParticle][]parser.Production)
	bgi.rhsIncludes = make(map[parser.GrammarParticle][]parser.Production)
	bgi.lhsStarts = make(map[parser.GrammarParticle][]parser.Production)
	bgi.rhsStarts = make(map[parser.GrammarParticle][]parser.Production)
	bgi.lhsEnds = make(map[parser.GrammarParticle][]parser.Production)
	bgi.rhsEnds = make(map[parser.GrammarParticle][]parser.Production)
	lhicn := make(map[parser.GrammarParticle]map[parser.Production]int)
	rhicn := make(map[parser.GrammarParticle]map[parser.Production]int)
	for _, p := range g.Productions() {
		if p.LhsLen() == 1 && p.Lhs(0).Asterisk() {
			bgi.lhsStarts[p.Lhs(0)] = []parser.Production{p}
			bgi.lhsEnds[p.Lhs(0)] = []parser.Production{p}
			bgi.rhsStarts[p.Lhs(0)] = []parser.Production{p}
			if _, has := bgi.rhsStarts[p.Rhs(0)]; !has {
				bgi.rhsStarts[p.Rhs(0)] = []parser.Production{}
			}
			bgi.rhsIncludes[p.Rhs(0)] = append(bgi.rhsIncludes[p.Rhs(0)], p)
			if _, has := bgi.rhsIncludes[p.Rhs(0)]; !has {
				bgi.rhsIncludes[p.Rhs(0)] = []parser.Production{}
			}
			bgi.rhsIncludes[p.Rhs(1)] = []parser.Production{p}
			bgi.rhsEnds[p.Rhs(1)] = []parser.Production{p}
			continue
		}
		if p.LhsLen() == 1 && p.Lhs(0).Nonterminal() && p.RhsLen() == 1 && p.Rhs(0).Epsilon() {
			bgi.epsilons[p.Lhs(0)] = p
		}
		iterm := p.Lhs(0)
		bgi.lhsStarts[iterm] = append(bgi.lhsStarts[iterm], p)
		eterm := p.Lhs(p.LhsLen() - 1)
		bgi.lhsEnds[eterm] = append(bgi.lhsEnds[eterm], p)
		iterm = p.Rhs(0)
		bgi.rhsStarts[iterm] = append(bgi.rhsStarts[iterm], p)
		eterm = p.Rhs(p.RhsLen() - 1)
		bgi.rhsEnds[eterm] = append(bgi.rhsEnds[eterm], p)
		for idx := 0; idx < p.LhsLen(); idx++ {
			pt := p.Lhs(idx)
			if m, has := lhicn[pt]; !has {
				m = make(map[parser.Production]int)
				m[p] = 1
				lhicn[pt] = m
			} else {
				lhicn[pt][p] = 1
			}
		}
		for idx := 0; idx < p.RhsLen(); idx++ {
			pt := p.Rhs(idx)
			if m, has := rhicn[pt]; !has {
				m = make(map[parser.Production]int)
				m[p] = 1
				rhicn[pt] = m
			} else {
				rhicn[pt][p] = 1
			}
		}
	}
	for pt, set := range lhicn {
		slc := make([]parser.Production, 0, len(set))
		for p, _ := range set {
			slc = append(slc, p)
		}
		bgi.lhsIncludes[pt] = slc
	}
	for pt, set := range rhicn {
		slc := make([]parser.Production, 0, len(set))
		for p, _ := range set {
			slc = append(slc, p)
		}
		bgi.rhsIncludes[pt] = slc
	}

	// Close epsilons.
	changed := true
	for changed {
		changed = false
		for _, p := range g.Productions() {
			if p.LhsLen() != 1 || !p.Lhs(0).Nonterminal() {
				continue
			}
			nt := p.Lhs(0)
			if bgi.Epsilon(nt) {
				continue
			}
			neweps := true
			for i := 0; i < p.RhsLen(); i++ {
				t := p.Rhs(i)
				if !t.Nonterminal() || !bgi.Epsilon(t) {
					neweps = false
					break
				}
			}
			if neweps {
				bgi.epsilons[nt] = p
				changed = true
			}
		}
	}

	return nil
}
예제 #5
0
파일: ffset.go 프로젝트: dtromb/parser
func (ff *FFIndex) Initialize(g parser.Grammar) error {
	ff.grammar = g
	index := parser.GetIndexedGrammar(g)
	idx, err := index.GetIndex(GRAMMAR_CLASS_INDEX)
	if err != nil {
		return err
	}
	cidx := idx.(*GrammarClassIndex)
	if cidx.Class() >= parser.CONTEXT_SENSITIVE {
		return errors.New("cannot first/follow index a non-context-free grammar")
	}
	idx, err = index.GetIndex(BASIC_INDEX)
	bidx := idx.(*BasicGrammarIndex)
	if err != nil {
		return err
	}

	// FIRST set calculation
	ff.firstSets = make(map[parser.GrammarParticle][]parser.GrammarParticle)
	for _, nt := range index.Nonterminals() {
		fs := tree.NewTree()
		ntseen := tree.NewTree()
		ntpending := []parser.GrammarParticle{nt}
		for len(ntpending) > 0 {
			cnt := ntpending[0]
			ntpending = ntpending[1:]
			for i := 0; i < bidx.NumLhsStarts(cnt); i++ {
				p := bidx.LhsStart(cnt, i)
				for j := 0; j < p.RhsLen(); j++ {
					rt := p.Rhs(j)
					if rt.Terminal() {
						fs.Insert(rt)
						break
					} else if rt.Nonterminal() {
						if _, has := ntseen.Lookup(c.LTE, rt); !has {
							ntseen.Insert(rt)
							fs.Insert(rt)
							ntpending = append(ntpending, rt)
						}
						if !bidx.Epsilon(rt) {
							break
						}
					} else {
						break
					}
				}
			}
		}
		ff.firstSets[nt] = make([]parser.GrammarParticle, 0, fs.Size())
		for c := fs.First(); c.HasNext(); {
			ff.firstSets[nt] = append(ff.firstSets[nt], c.Next().(parser.GrammarParticle))
		}
	}

	// LAST set calculation
	ff.lastSets = make(map[parser.GrammarParticle][]parser.GrammarParticle)
	for _, nt := range index.Nonterminals() {
		fs := tree.NewTree()
		ntseen := tree.NewTree()
		ntpending := []parser.GrammarParticle{nt}
		for len(ntpending) > 0 {
			cnt := ntpending[0]
			ntpending = ntpending[1:]
			for i := 0; i < bidx.NumLhsStarts(cnt); i++ {
				p := bidx.LhsStart(cnt, i)
				for j := p.RhsLen() - 1; j >= 0; j-- {
					rt := p.Rhs(j)
					if rt.Terminal() {
						fs.Insert(rt)
						break
					}
					if rt.Nonterminal() {
						if _, has := ntseen.Lookup(c.LTE, rt); !has {
							ntseen.Insert(rt)
							fs.Insert(rt)
							ntpending = append(ntpending, rt)
							if !bidx.Epsilon(rt) {
								break
							}
						}
					}
				}
			}
		}
		ff.lastSets[nt] = make([]parser.GrammarParticle, 0, fs.Size())
		for c := fs.First(); c.HasNext(); {
			ff.lastSets[nt] = append(ff.lastSets[nt], c.Next().(parser.GrammarParticle))
		}
	}

	// IN set calculation
	ff.inSets = make(map[parser.GrammarParticle][]parser.GrammarParticle)
	for _, nt := range index.Nonterminals() {
		fs := tree.NewTree()
		ntseen := tree.NewTree()
		ntpending := []parser.GrammarParticle{nt}
		for len(ntpending) > 0 {
			cnt := ntpending[0]
			ntpending = ntpending[1:]
			for i := 0; i < bidx.NumLhsStarts(cnt); i++ {
				p := bidx.LhsStart(cnt, i)
				for j := p.RhsLen() - 1; j >= 0; j-- {
					rt := p.Rhs(j)
					if rt.Terminal() {
						fs.Insert(rt)
					}
					if rt.Nonterminal() {
						if _, has := ntseen.Lookup(c.LTE, rt); !has {
							ntseen.Insert(rt)
							fs.Insert(rt)
							ntpending = append(ntpending, rt)
						}
					}
				}
			}
		}
		ff.inSets[nt] = make([]parser.GrammarParticle, 0, fs.Size())
		for c := fs.First(); c.HasNext(); {
			ff.inSets[nt] = append(ff.inSets[nt], c.Next().(parser.GrammarParticle))
		}
	}

	// FOLLOW set calculation
	followRefs := make(map[parser.GrammarParticle]tree.Tree)
	followSets := make(map[parser.GrammarParticle]tree.Tree)
	for _, p := range g.Productions() { // First-pass.
		for i := 0; i < p.RhsLen()-1; i++ {
			for j := i + 1; j < p.RhsLen(); j++ {
				if _, has := followSets[p.Rhs(i)]; !has {
					followSets[p.Rhs(i)] = tree.NewTree()
				}
				followSets[p.Rhs(i)].Insert(p.Rhs(j))
				if !bidx.Epsilon(p.Rhs(j)) {
					break
				}
			}
		}
		tp := p.Rhs(p.RhsLen() - 1)
		if _, has := followRefs[tp]; !has {
			followRefs[tp] = tree.NewTree()
		}
		followRefs[tp].Insert(p.Lhs(0))
	}
	var changed bool = true
	for changed { // Take closure.
		changed = false
		for p, prt := range followRefs {
			for cr := prt.First(); cr.HasNext(); {
				fp := cr.Next().(parser.GrammarParticle) // x in Follow(fp) -> x in Follow(p)
				if fromSet, has := followSets[fp]; has {
					if _, has := followSets[p]; !has {
						followSets[p] = tree.NewTree()
					}
					for k := fromSet.First(); k.HasNext(); {
						x := k.Next().(parser.GrammarParticle)
						if _, has := followSets[p].Lookup(c.LTE, x); !has {
							changed = true
							followSets[p].Insert(x)
						}
					}
				}
			}
		}
	}
	ff.followSets = make(map[parser.GrammarParticle][]parser.GrammarParticle)
	for r, v := range followSets { // Collect results.
		ff.followSets[r] = make([]parser.GrammarParticle, 0, v.Size())
		for c := v.First(); c.HasNext(); {
			ff.followSets[r] = append(ff.followSets[r], c.Next().(parser.GrammarParticle))
		}
	}

	return nil
}