ergo/vendor/github.com/goshuirc/e-nfa/enfa.go

186 lines
4.2 KiB
Go

package enfa
import "fmt"
type transitionInput struct {
srcState int
input string
}
type destState map[int]bool
type ENFA struct {
initState int
currentState map[int]bool
totalStates []int
finalStates []int
transition map[transitionInput]destState
inputMap map[string]bool
}
//New a new NFA
func NewENFA(initState int, isFinal bool) *ENFA {
retNFA := &ENFA{
transition: make(map[transitionInput]destState),
inputMap: make(map[string]bool),
initState: initState}
retNFA.currentState = make(map[int]bool)
retNFA.currentState[initState] = true
retNFA.AddState(initState, isFinal)
return retNFA
}
//Add new state in this NFA
func (d *ENFA) AddState(state int, isFinal bool) {
if state == -1 {
fmt.Println("Cannot add state as -1, it is dead state")
return
}
d.totalStates = append(d.totalStates, state)
if isFinal {
d.finalStates = append(d.finalStates, state)
}
}
//Add new transition function into NFA
func (d *ENFA) AddTransition(srcState int, input string, dstStateList ...int) {
find := false
//find input if exist in NFA input List
if _, ok := d.inputMap[input]; !ok {
//not exist, new input in this NFA
d.inputMap[input] = true
}
for _, v := range d.totalStates {
if v == srcState {
find = true
}
}
if !find {
fmt.Println("No such state:", srcState, " in current NFA")
return
}
dstMap := make(map[int]bool)
for _, destState := range dstStateList {
dstMap[destState] = true
}
targetTrans := transitionInput{srcState: srcState, input: input}
d.transition[targetTrans] = dstMap
}
func (d *ENFA) CheckPathExist(src int, input string, dst int) bool {
retMap, _ := d.transition[transitionInput{srcState: src, input: input}]
if _, ok := retMap[dst]; ok {
return true
}
return false
}
func (d *ENFA) Input(testInput string) []int {
updateCurrentState := make(map[int]bool)
for current, _ := range d.currentState {
for _, realTestInput := range []string{testInput, "*", "?"} {
intputTrans := transitionInput{srcState: current, input: realTestInput}
valMap, ok := d.transition[intputTrans]
if ok {
for dst, _ := range valMap {
updateCurrentState[dst] = true
//Update epsilon input way... if exist
epsilonTrans := transitionInput{srcState: dst}
if eMap, ok := d.transition[epsilonTrans]; ok {
for eDst, _ := range eMap {
updateCurrentState[eDst] = true
}
}
}
} else {
//dead state, remove in current state
//do nothing.
}
}
}
//update curret state
d.currentState = updateCurrentState
//return result
var ret []int
for state, _ := range updateCurrentState {
ret = append(ret, state)
}
return ret
}
//To verify current state if it is final state
func (d *ENFA) Verify() bool {
for _, val := range d.finalStates {
for cState, _ := range d.currentState {
if val == cState {
return true
}
}
}
return false
}
//Reset NFA state to initilize state, but all state and transition function will remain
func (d *ENFA) Reset() {
initState := make(map[int]bool)
initState[d.initState] = true
d.currentState = initState
}
//Verify if list of input could be accept by NFA or not
func (d *ENFA) VerifyInputs(inputs []string) bool {
for _, v := range inputs {
d.Input(v)
}
return d.Verify()
}
//To print detail transition table contain of current NFA
func (d *ENFA) PrintTransitionTable() {
fmt.Println("===================================================")
//list all inputs
var inputList []string
for key, _ := range d.inputMap {
if key == "" {
fmt.Printf("\tε|")
} else {
fmt.Printf("\t%s|", key)
}
inputList = append(inputList, key)
}
fmt.Printf("\n")
fmt.Println("---------------------------------------------------")
for _, state := range d.totalStates {
fmt.Printf("%d |", state)
for _, key := range inputList {
checkInput := transitionInput{srcState: state, input: key}
if dstState, ok := d.transition[checkInput]; ok {
fmt.Printf("\t")
for val, _ := range dstState {
fmt.Printf("%d,", val)
}
fmt.Printf("|")
} else {
fmt.Printf("\tNA|")
}
}
fmt.Printf("\n")
}
fmt.Println("---------------------------------------------------")
fmt.Println("===================================================")
}