SEATC 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/Grammar Analyzer.rb +80 -0
- data/lib/Grammar Reader.rb +69 -0
- data/lib/PDA.rb +227 -0
- data/lib/Regular Expression.rb +2 -0
- data/lib/Regular Grammar Analyzer.rb +3 -0
- data/samples/Pushdown.jff +27 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b1ed631327b6eefa9d013e3a8b0e2cd423558de
|
4
|
+
data.tar.gz: 4f248e1b1f23f7bf1aacfc2be63f4e51ddc49bf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 451e0ef6aa23b421096333ed51b408efb1df8b755e4dcc821f4f163797802c438e300b3c959b95cace611682ab4b14dc144e5992462e1069b57163fdbd0a7a67
|
7
|
+
data.tar.gz: 115f64c041986817124d9eaba62b7fef72ac0ac9d2fe64bf1f2ff8602252294322e2cb271a8316562609631e2270673ae8aa040ac5aef6dcbb30d693474257ff
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'thread'
|
2
|
+
load 'Grammar Reader.rb'
|
3
|
+
|
4
|
+
class GrammarAnalyzer
|
5
|
+
attr_accessor :mutex, :valid
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@valid = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def println(s)
|
13
|
+
@mutex.synchronize {
|
14
|
+
puts s
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def isNT(char)
|
19
|
+
return "A" <= char && char <= "Z"
|
20
|
+
end
|
21
|
+
|
22
|
+
def removeFirst(line)
|
23
|
+
line.reverse!
|
24
|
+
line.chop!
|
25
|
+
line.reverse!
|
26
|
+
end
|
27
|
+
|
28
|
+
def canContinue(prod, line)
|
29
|
+
p = String.new prod
|
30
|
+
s = 0
|
31
|
+
for i in 0...p.length
|
32
|
+
s = s + 1 if !isNT(p[i])
|
33
|
+
end
|
34
|
+
# puts s <= line.length
|
35
|
+
return s <= line.length
|
36
|
+
end
|
37
|
+
|
38
|
+
def analyzer(prod, line, prods)
|
39
|
+
#puts "Analyzing " + prod
|
40
|
+
while canContinue(prod, line)
|
41
|
+
if prod.length == 0
|
42
|
+
if line.length == 0
|
43
|
+
@valid = true
|
44
|
+
#println "Exito"
|
45
|
+
else
|
46
|
+
#println "Error"
|
47
|
+
end
|
48
|
+
return
|
49
|
+
end
|
50
|
+
if isNT(prod[0])
|
51
|
+
prods[prod[0]].each do |p|
|
52
|
+
t = Thread.new { analyzer(String.new(p + prod.slice(1, prod.length - 1)), String.new(line), prods)}
|
53
|
+
t.join
|
54
|
+
end
|
55
|
+
return
|
56
|
+
end
|
57
|
+
if prod[0] == line[0]
|
58
|
+
removeFirst line
|
59
|
+
removeFirst prod
|
60
|
+
else
|
61
|
+
# println "Error en el analisis"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def analyze(file, line)
|
68
|
+
reader = GrammarReader.new
|
69
|
+
prods = reader.createProductions(reader.readFile(file))
|
70
|
+
prods['S'].each do |p|
|
71
|
+
t = Thread.new { analyzer(String.new(p), String.new(line), prods)}
|
72
|
+
t.join
|
73
|
+
end
|
74
|
+
ret = @valid
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
ga = GrammarAnalyzer.new
|
80
|
+
puts ga.analyze("../samples/Regular Grammar.jff", "aaaa")
|
@@ -0,0 +1,69 @@
|
|
1
|
+
SYNTAX_ERROR = 1
|
2
|
+
PRODUCTION_ERROR = 2
|
3
|
+
|
4
|
+
class GrammarReader
|
5
|
+
attr_accessor :error
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
@error = 0
|
9
|
+
end
|
10
|
+
def getLeft(modified)
|
11
|
+
modified.slice! "\t\t<left>"
|
12
|
+
ret = modified[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def getRight(modified)
|
16
|
+
modified.slice! "\t\t<right>"
|
17
|
+
ret = ""
|
18
|
+
while(modified[0] != "<")
|
19
|
+
sliced = modified[0]
|
20
|
+
modified.slice! sliced
|
21
|
+
ret = ret + sliced
|
22
|
+
end
|
23
|
+
return ret
|
24
|
+
end
|
25
|
+
|
26
|
+
#returns an Array containing the lines from the file
|
27
|
+
def readFile(file)
|
28
|
+
file = File.new(file, "r")
|
29
|
+
line = file.read
|
30
|
+
file.close
|
31
|
+
lines = line.split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
#returns the Hash containing the productions
|
35
|
+
def createProductions(lines)
|
36
|
+
productions = Hash.new
|
37
|
+
if !lines[0].include? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!--Created with JFLAP 6.4.--><structure> "
|
38
|
+
@error = SYNTAX_ERROR
|
39
|
+
return productions
|
40
|
+
end
|
41
|
+
if !lines[1].include? "\t<type>grammar</type> "
|
42
|
+
@error = SYNTAX_ERROR
|
43
|
+
return productions
|
44
|
+
end
|
45
|
+
counter = 3
|
46
|
+
i = 0
|
47
|
+
modified = lines[counter]
|
48
|
+
while(modified.include? "production")
|
49
|
+
modified = lines[counter + 1]
|
50
|
+
left = getLeft(modified)
|
51
|
+
modified = lines[counter + 2]
|
52
|
+
right = getRight(modified)
|
53
|
+
while right[0] == "\t"
|
54
|
+
right.slice! "\t"
|
55
|
+
end
|
56
|
+
if right.length > 2
|
57
|
+
@error = PRODUCTION_ERROR
|
58
|
+
end
|
59
|
+
counter = counter + 4
|
60
|
+
modified = lines[counter]
|
61
|
+
if productions[left] == nil
|
62
|
+
productions[left] = Array.new
|
63
|
+
end
|
64
|
+
productions[left].push(right)
|
65
|
+
i = i + 1
|
66
|
+
end
|
67
|
+
return productions
|
68
|
+
end
|
69
|
+
end
|
data/lib/PDA.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
class PDATransition
|
2
|
+
attr_accessor :destination, :push, :pop
|
3
|
+
def initialize(destination, push, pop)
|
4
|
+
@destination = destination
|
5
|
+
@push = push
|
6
|
+
@pop = pop
|
7
|
+
end
|
8
|
+
def getDestination()
|
9
|
+
return @destination
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class PDAState
|
14
|
+
@id
|
15
|
+
@nombre
|
16
|
+
@transitions
|
17
|
+
@final
|
18
|
+
def initialize(id, nombre, final)
|
19
|
+
@id = id
|
20
|
+
@nombre = nombre
|
21
|
+
@transitions = Hash.new
|
22
|
+
@final = final
|
23
|
+
end
|
24
|
+
def addTrans(char, to, pop, push)
|
25
|
+
if @transitions[char] == nil
|
26
|
+
@transitions[char] = Hash.new
|
27
|
+
end
|
28
|
+
@transitions[char][to] = PDATransition.new to, push, pop
|
29
|
+
end
|
30
|
+
def transAt(char)
|
31
|
+
ret = @transitions[char]
|
32
|
+
end
|
33
|
+
def final()
|
34
|
+
ret = @final
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class PDAAnalyzer
|
39
|
+
@valid = false
|
40
|
+
def getStateID(modified)
|
41
|
+
modified.slice! "\t\t<state id=\""
|
42
|
+
lastQuota = true
|
43
|
+
id = 0
|
44
|
+
while(lastQuota)
|
45
|
+
id = id * 10
|
46
|
+
char = modified[0]
|
47
|
+
modified.slice! modified[0]
|
48
|
+
lastQuota = (modified[0] != "\"")
|
49
|
+
id = id + char.to_i
|
50
|
+
end
|
51
|
+
id = id
|
52
|
+
end
|
53
|
+
|
54
|
+
def getStateName(modified)
|
55
|
+
modified.slice! "\" name=\""
|
56
|
+
lastQuota = true
|
57
|
+
id = ""
|
58
|
+
while(lastQuota)
|
59
|
+
id = id + modified[0]
|
60
|
+
modified.slice! modified[0]
|
61
|
+
lastQuota = (modified[0] != "\"")
|
62
|
+
end
|
63
|
+
id = id
|
64
|
+
end
|
65
|
+
|
66
|
+
def readPush(modified)
|
67
|
+
lastQuota = true
|
68
|
+
id = ""
|
69
|
+
while(lastQuota)
|
70
|
+
id = id + modified[0]
|
71
|
+
modified.slice! modified[0]
|
72
|
+
lastQuota = (modified[0] != "<")
|
73
|
+
end
|
74
|
+
id = id
|
75
|
+
end
|
76
|
+
|
77
|
+
def readPop(modified)
|
78
|
+
lastQuota = true
|
79
|
+
id = ""
|
80
|
+
while(lastQuota)
|
81
|
+
id = id + modified[0]
|
82
|
+
modified.slice! modified[0]
|
83
|
+
lastQuota = (modified[0] != "<")
|
84
|
+
end
|
85
|
+
id = id
|
86
|
+
end
|
87
|
+
|
88
|
+
def readTransInt(modified)
|
89
|
+
lastQuota = true
|
90
|
+
id = 0
|
91
|
+
while(lastQuota)
|
92
|
+
id = id * 10
|
93
|
+
char = modified[0]
|
94
|
+
modified.slice! modified[0]
|
95
|
+
lastQuota = (modified[0] != "<")
|
96
|
+
id = id + char.to_i
|
97
|
+
end
|
98
|
+
id = id
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
def validateString(initial, states, line, stack)
|
103
|
+
st = initial
|
104
|
+
usedLine = String.new line
|
105
|
+
if(usedLine != "")
|
106
|
+
char = usedLine[0]
|
107
|
+
usedLine.slice! char
|
108
|
+
sts = states[st].transAt(char)
|
109
|
+
if sts != nil
|
110
|
+
sts.each do |transition|
|
111
|
+
pushable = String.new transition[1].push
|
112
|
+
if(stack.length == 0 && transition[1].pop != "")
|
113
|
+
return false
|
114
|
+
end
|
115
|
+
if(transition[1].pop != "")
|
116
|
+
pop = stack.pop
|
117
|
+
if(pop != transition[1].pop)
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
pushable.reverse!
|
122
|
+
while(pushable!="")
|
123
|
+
stack.push pushable[0]
|
124
|
+
pushable.slice! pushable[0]
|
125
|
+
end
|
126
|
+
v = validateString(transition[0], states, usedLine, stack)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
else
|
130
|
+
if(states[st].final == 1 || stack.length == 0)
|
131
|
+
@valid = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
#Returns true if the automaton ends in final state, returns false otherwise
|
137
|
+
def analyze(sourceFile, testString)
|
138
|
+
file = File.new(sourceFile, "r")
|
139
|
+
line = file.read
|
140
|
+
file.close
|
141
|
+
counter = 1
|
142
|
+
lines = line.split("\n")
|
143
|
+
for lin in lines
|
144
|
+
counter = counter + 1
|
145
|
+
end
|
146
|
+
if !lines[0].include? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!--Created with JFLAP 6.4.--><structure>"
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
# Check if pushdown automaton
|
150
|
+
if !lines[1].match "<type>pda</type>"
|
151
|
+
return false
|
152
|
+
end
|
153
|
+
states = []
|
154
|
+
counter = 4
|
155
|
+
i = 0
|
156
|
+
initialState = nil
|
157
|
+
modified = lines[counter]
|
158
|
+
while(modified.include? "state")
|
159
|
+
final = 0
|
160
|
+
aux = counter
|
161
|
+
id = getStateID(modified)
|
162
|
+
nombre = getStateName(modified)
|
163
|
+
if(lines[counter + 3 ].include? "initial")
|
164
|
+
aux = aux + 1
|
165
|
+
initialState = id
|
166
|
+
end
|
167
|
+
if(lines[aux + 3].include? "final")
|
168
|
+
final = 1
|
169
|
+
aux = aux + 1
|
170
|
+
end
|
171
|
+
counter = aux + 4
|
172
|
+
modified = lines[counter]
|
173
|
+
states[id] = PDAState.new(id, nombre, final)
|
174
|
+
i = i + 1
|
175
|
+
end
|
176
|
+
counter = counter + 1
|
177
|
+
modified = lines[counter]
|
178
|
+
while(modified.include? "transition")
|
179
|
+
counter = counter + 1
|
180
|
+
modified = lines[counter]
|
181
|
+
modified.slice! "\t\t\t<from>"
|
182
|
+
from = readTransInt(modified)
|
183
|
+
counter = counter + 1
|
184
|
+
modified = lines[counter]
|
185
|
+
modified.slice! "\t\t\t<to>"
|
186
|
+
to = readTransInt(modified)
|
187
|
+
counter = counter + 1
|
188
|
+
modified = lines[counter]
|
189
|
+
modified.slice! "\t\t\t<read>"
|
190
|
+
read = modified[0]
|
191
|
+
counter = counter + 1
|
192
|
+
modified = lines[counter]
|
193
|
+
if(modified.include? "<pop>")
|
194
|
+
modified.slice! "\t\t\t<pop>"
|
195
|
+
pop = readPop(modified)
|
196
|
+
else
|
197
|
+
pop=""
|
198
|
+
end
|
199
|
+
counter = counter + 1
|
200
|
+
modified = lines[counter]
|
201
|
+
if(modified.include? "<push>")
|
202
|
+
modified.slice! "\t\t\t<push>"
|
203
|
+
push = readPush(modified)
|
204
|
+
else
|
205
|
+
push=""
|
206
|
+
end
|
207
|
+
states[from].addTrans(read, to, pop, push)
|
208
|
+
counter = counter + 2
|
209
|
+
modified = lines[counter]
|
210
|
+
end
|
211
|
+
#Validate
|
212
|
+
lin = testString
|
213
|
+
stack = Array.new
|
214
|
+
valid = validateString(initialState, states, lin, stack)
|
215
|
+
if @valid
|
216
|
+
ret = true
|
217
|
+
else
|
218
|
+
ret = false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
ndfa= PDAAnalyzer.new
|
224
|
+
puts ndfa.analyze("../samples/Pushdown.jff", "aabb")
|
225
|
+
|
226
|
+
<% ndfa= PDAAnalyzer.new %>
|
227
|
+
<% res = ndfa.analyze("../samples/Pushdown.jff", "aabb") %>
|
data/lib/Regular Expression.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 6.4.--><structure>
|
2
|
+
<type>pda</type>
|
3
|
+
<automaton>
|
4
|
+
<!--The list of states.-->
|
5
|
+
<state id="0" name="q0">
|
6
|
+
<x>79.0</x>
|
7
|
+
<y>137.0</y>
|
8
|
+
<initial/>
|
9
|
+
<final/>
|
10
|
+
</state>
|
11
|
+
<!--The list of transitions.-->
|
12
|
+
<transition>
|
13
|
+
<from>0</from>
|
14
|
+
<to>0</to>
|
15
|
+
<read>a</read>
|
16
|
+
<pop/>
|
17
|
+
<push>A</push>
|
18
|
+
</transition>
|
19
|
+
<transition>
|
20
|
+
<from>0</from>
|
21
|
+
<to>0</to>
|
22
|
+
<read>b</read>
|
23
|
+
<pop>A</pop>
|
24
|
+
<push/>
|
25
|
+
</transition>
|
26
|
+
</automaton>
|
27
|
+
</structure>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: SEATC
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salvador Guerra Delgado
|
@@ -11,7 +11,7 @@ cert_chain: []
|
|
11
11
|
date: 2018-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A gem for development on SEATC, can be used for other system that requires
|
14
|
-
automaton analysis
|
14
|
+
automaton and grammars analysis
|
15
15
|
email: salvador.guerra.delgado2@gmail.com
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
@@ -20,9 +20,13 @@ files:
|
|
20
20
|
- Rakefile
|
21
21
|
- bin/Finite Automaton
|
22
22
|
- lib/Finite Automaton Analyzer.rb
|
23
|
+
- lib/Grammar Analyzer.rb
|
24
|
+
- lib/Grammar Reader.rb
|
25
|
+
- lib/PDA.rb
|
23
26
|
- lib/Regular Expression.rb
|
24
27
|
- lib/Regular Grammar Analyzer.rb
|
25
28
|
- samples/Finite Automaton.jff
|
29
|
+
- samples/Pushdown.jff
|
26
30
|
- samples/Regular Expression.jff
|
27
31
|
- samples/Regular Grammar.jff
|
28
32
|
homepage: http://rubygems.org/gems/SEATC
|
@@ -44,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
48
|
version: '0'
|
45
49
|
requirements: []
|
46
50
|
rubyforge_project:
|
47
|
-
rubygems_version: 2.
|
51
|
+
rubygems_version: 2.6.14
|
48
52
|
signing_key:
|
49
53
|
specification_version: 3
|
50
54
|
summary: SEATC
|