aboutsummaryrefslogtreecommitdiff
path: root/vfsm.rb
blob: 3417725e9f0ac04199258acc198e21b364673699 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
class Node
	def initialize id, accepting = false
		@id = id
		@accepting = accepting
		@edges = []
	end

	def id
		return @id
	end

	def accepting! accepting=true
		@accepting = accepting
	end

	def accepting?
		return @accepting
	end

	def pushedge on, to
		tempto = @edges.select do |edge|
			edge[0] == on
		end
		@edges.push [on, to]
	end

	def goto on
		to = @edges.select do |edge|
			edge[0] == on
		end

		if to.length == 0 then
			return :reject
		else
			ret = []
			to.each do |x|
				ret.push x[1]
			end
			return ret
		end
	end
end

if ARGV[0] == nil or ARGV[1] == nil then
	puts "Usage: ruby vfsm.rb <machine description file> <input>"
	exit
end

inedges = false
nodes = []
currentnodes = []

lineno = 0
File.foreach(ARGV[0]) do |line|
	lineno += 1
	linearray = line.chomp.split
	unless inedges then
		if linearray == [] then
			#do nothing
		elsif linearray[0].downcase == "comment:" then
			#do nothing
		elsif linearray[0].downcase == "nodes:" then
			#do nothing
			#ignore line for backwards compatability
		elsif linearray[0].downcase == "start:" then
			tempsnode = nodes.select do |node|
				node.id == linearray[1]
			end
			if tempsnode.length == 0 then
				startnode = Node.new linearray[1]
				nodes.push startnode
				currentnodes.push startnode
			else
				currentnodes.push tempsnode[0]
			end
		elsif linearray[0].downcase == "accept:" then
			linearray[1..-1].each do |node|
				anodes = nodes.select do |inode|
					node == inode.id
				end
				if anodes.length == 0 then
					mynode = Node.new node, true
					nodes.push mynode
				else
					anodes[0].accepting!
				end
			end
		elsif linearray[0].downcase == "edges:" then
			inedges = true
		else
			puts "Syntax error at line #{lineno}"
			puts line
			exit
		end
	else
		if linearray[0].downcase == "end:" then
			inedges = false
		else
			fnode = nil
			tnode = nil
			fnodes = nodes.select do |node|
				node.id == linearray[0]
			end
			if fnodes.length == 0 then
				fnode = Node.new linearray[0]
				nodes.push fnode
			else
				fnode = fnodes[0]
			end
			tnodes = nodes.select do |node|
				node.id == linearray[2]
			end
			if tnodes.length == 0 then
				tnode = Node.new linearray[2]
				nodes.push tnode
			else
				tnode = tnodes[0]
			end
			if linearray[1].downcase == "epsilon:" or linearray[1].downcase == "lambda:" then
				fnode.pushedge :lambda, tnode
			else
				fnode.pushedge linearray[1], tnode
			end
		end
	end
end

def printnodes nodes
	print "{"
	nodes.each do |node|
		if node.accepting? then
			print "((#{node.id})),"
		else
			print "(#{node.id}),"
		end
	end
	print "}"
end

ARGV[1].chomp.split.each do |input|
	printnodes currentnodes

	nextnodes = []
	currentnodes.each do |node|
		nextnode = node.goto input
		unless nextnode == :reject
			nextnode.each do |x|
				nextnodes.push x
			end
		end
	end

	oldnext = nextnodes.dup
	begin
		epsnodes = []
		nextnodes.each do |node|
			tmp = node.goto :lambda
			tmp.each do |x|
				epsnodes.push tmp
			end
		end
		epsnodes.each do |node|
			nextnodes.push node
		end
	end while oldnext != nextnodes
	
	if nextnodes == [] then
		puts
		puts "Invalid input, REJECTED"
		exit
	else
		currentnodes = nextnodes
	end
end

printnodes currentnodes

acc = false
currentnodes.each do |node|
	acc = true if node.accepting?
end
if acc then
	puts "Valid input, ACCEPTED"
else
	puts "Invalid input, REJECTED"
end