SEATC 0.2.25 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4f8a08919fcf81f075f88a69a19351ee1b70b4f
4
- data.tar.gz: 69a945e50c7d071f976d3b355f2be54342e681b1
3
+ metadata.gz: 1ee0f7663dc5ac8a81806784220d5baefe59928d
4
+ data.tar.gz: e63d166143186e066c83810bff146b916c86b4e0
5
5
  SHA512:
6
- metadata.gz: 126bfff0a299a1a93dfa93661f1af2001d468d082fa0334e84b73acb4780dd768187797ab2702bda42293bc0f6d99b8e5c2151292a020a667ebe98d41296797d
7
- data.tar.gz: 92088d3ec6ddea4f4781809ed8e8664e811fdb261a506f651de2f9d8c2461a2981450c254f932d418c2b26b3ee6b27cbea80ba785ba016b9040f3879f7241b60
6
+ metadata.gz: 94f842f9b803d0466d77012e132973a52c6fb63ec78dff55f2eebef5036f8f46ec70e1c6af944b557ce4e8d8053296d356a2c1dd54a33b116a825a93870ef397
7
+ data.tar.gz: 18c030b8a471dc94354a2223618c6ce9b37dee08eb139a0d0a1fc60257586727fa3de7c83b79eea2975a07a39898a84bcd20b5b6f23017447ea7068bd036f769
@@ -1,52 +1,85 @@
1
+ # Automaton Analyzer State
1
2
  class AutomatonState
2
3
  @id
3
4
  @nombre
4
5
  @transitions
5
6
  @final
7
+ # @param id [Integer] ID for the state
8
+ # @param nombre [String] Name of the state (JFlap Label)
9
+ # @param final [Boolean] Determine if the state is final state
6
10
  def initialize(id, nombre, final)
7
11
  @id = id
8
12
  @nombre = nombre
9
13
  @transitions = Hash.new
10
14
  @final = final
11
15
  end
16
+ # Add a transition to the state
17
+ # @param char [String] Transition value
18
+ # @param to [Integer] State where the transition goes
19
+ # @return [Void]
12
20
  def addTrans(char, to)
13
21
  if @transitions[char] == nil
14
22
  @transitions[char] = Hash.new
15
23
  end
16
24
  @transitions[char][to] = to
17
25
  end
26
+ # Return the list of transitions
27
+ # @param char [String] List of transitions for an specific input
28
+ # @return [Hash] List of transitions
18
29
  def transAt(char)
19
30
  ret = @transitions[char]
20
31
  end
32
+ # Return all the transitions for the state
33
+ # @return [Hash] List of all transitions
21
34
  def getTrans
22
35
  return @transitions
23
36
  end
37
+ # Return name of the state
38
+ # @return [String] Name of the state
24
39
  def getName
25
40
  return @nombre
26
41
  end
42
+ # Return if the state is final state
43
+ # @return [Boolean] 1 if the state is final, 0 otherwise
27
44
  def final()
28
45
  ret = @final
29
46
  end
30
47
  end
31
48
 
49
+ # Analyzer for both kind of automatons: deterministic and non-deterministic
50
+ # First create the analyzer with new,
51
+ # then use the analyze method to know if the string is accepted or not
52
+ # @attr valid [Boolean] Determine if a string is valid or not in certain time of the instance
53
+ # @attr errno [Integer] Identifier for some errors on the analyzer
54
+ # @attr deterministic [Boolean] Determine if {#isDeterministic} check is needed
32
55
  class AutomatonAnalyzer
33
56
  attr_accessor :valid, :deterministic, :errno
57
+ # Return errno of the analyzer
58
+ # @return [Boolean] 0 errno is that the analyzer completed with no error, otherwise it is different to 0
34
59
  def errno()
35
60
  return @errno
36
61
  end
37
- def initialize(deterministic)
62
+ # Initialize the analyzer
63
+ # @param deterministic [Boolean] Define if the Automaton will be deterministic or non-deterministic
64
+ def initialize(deterministic)
38
65
  @deterministic = deterministic
39
66
  @errno = 0
40
- end
41
- def isDeterministic(states)
42
- return false if !@deterministic
43
- states.each do |estado|
44
- transiciones = estado.getTrans
45
- transiciones.each do |transition|
46
- return false if estado.transAt(transition[0]).length > 1
47
- end
67
+ end
68
+ # Check if the automaton is deterministic
69
+ # @param states [Array] List of automaton's transitions
70
+ # @return [Boolean] 1 if the automaton is deterministic, 0 otherwise
71
+ def isDeterministic(states)
72
+ return false if !@deterministic
73
+ states.each do |estado|
74
+ transiciones = estado.getTrans
75
+ transiciones.each do |transition|
76
+ return false if estado.transAt(transition[0]).length > 1
48
77
  end
49
78
  end
79
+ end
80
+ # Return state id from a read line
81
+ # @param modified [String] Line where ID of the state is contained
82
+ # @return [Integer] State ID
50
83
  def getStateID(modified)
51
84
  modified.slice! "\t\t<state id=\""
52
85
  lastQuota = true
@@ -60,7 +93,9 @@ class AutomatonAnalyzer
60
93
  end
61
94
  id = id
62
95
  end
63
-
96
+ # Return state name from a read line
97
+ # @param modified [String] Line where name of the state is contained
98
+ # @return [String] State name
64
99
  def getStateName(modified)
65
100
  modified.slice! "\" name=\""
66
101
  lastQuota = true
@@ -72,7 +107,9 @@ class AutomatonAnalyzer
72
107
  end
73
108
  id = id
74
109
  end
75
-
110
+ # Return the next state of the transition
111
+ # @param modified [String] Line where next state is contained is contained
112
+ # @return [Integer] Next state of a transition
76
113
  def readTransInt(modified)
77
114
  lastQuota = true
78
115
  id = 0
@@ -86,7 +123,11 @@ class AutomatonAnalyzer
86
123
  id = id
87
124
 
88
125
  end
89
-
126
+ # Return if a string is valid for an automaton
127
+ # @param initial [AutomatonState] Initial state
128
+ # @param states [Array[AutomatonState]] List of transitions
129
+ # @param line [String] String to be validated
130
+ # @return [Boolean] True if the string is accepted, false otherwise
90
131
  def validateString(initial, states, line)
91
132
  st = initial
92
133
  usedLine = String.new line
@@ -106,7 +147,10 @@ class AutomatonAnalyzer
106
147
  end
107
148
  end
108
149
 
109
- #Returns true if the automaton ends in final state, returns false otherwise
150
+ # Returns true if the automaton ends in final state, returns false otherwise
151
+ # @param sourceFile [String] JFLAP file location
152
+ # @param testString [String] String to be analyzed
153
+ # @return [Boolean] True if the string is accepted, False otherwise
110
154
  def analyze(sourceFile, testString)
111
155
  file = File.new(sourceFile, "r")
112
156
  line = file.read
@@ -1,34 +1,50 @@
1
1
  require 'thread'
2
2
  load 'Grammar Reader.rb'
3
3
 
4
+ # Analyzer for grammars
5
+ # For using it first creates the analyzer with new,
6
+ # then use the analyze method to know if the string is accepted or not
7
+ # @attr mutex [Object] Mutex for managing concurrency
8
+ # @attr valid [Boolean] Determine if a string is valid or not in certain time of the instance
9
+ # @attr errno [Integer] Identifier for some errors on the analyzer
4
10
  class GrammarAnalyzer
5
11
  attr_accessor :mutex, :valid, :errno
6
-
12
+ # Return errno of the analyzer
13
+ # @return [Integer] 0 errno is that the analyzer completed with no error, otherwise it is different to 0
7
14
  def errno()
8
15
  return @errno
9
16
  end
10
-
17
+ # Initialize the analyzer
11
18
  def initialize
12
19
  @mutex = Mutex.new
13
20
  @valid = false
14
21
  end
15
-
22
+ # Synchronized println in case of need
23
+ # @param s [String] String to be printed
24
+ # @return [Void]
16
25
  def println(s)
17
26
  @mutex.synchronize {
18
27
  puts s
19
28
  }
20
29
  end
21
-
30
+ # Check if a char is non-terminal
31
+ # @param char Char to be checked
32
+ # @return [bool] True if the char is non-terminal, False otherwise
22
33
  def isNT(char)
23
34
  return "A" <= char && char <= "Z"
24
35
  end
25
-
36
+ # Method for removing the first char of a string
37
+ # @param line [String] String to be modified
38
+ # @return [String] Modified string
26
39
  def removeFirst(line)
27
40
  line.reverse!
28
41
  line.chop!
29
42
  line.reverse!
30
43
  end
31
-
44
+ # Determine if the analyzer must continue or not
45
+ # @param prod [String] Actual produced line
46
+ # @param line [String] Final line to be matched
47
+ # @return [Boolean] True if analyzer can continue, False otherwise
32
48
  def canContinue(prod, line)
33
49
  p = String.new prod
34
50
  s = 0
@@ -38,6 +54,11 @@ class GrammarAnalyzer
38
54
  return s <= line.length
39
55
  end
40
56
 
57
+ # Threaded method to determine if the string is accepted or not
58
+ # @param prod [String] Actual produced line
59
+ # @param line [String] String to be matched
60
+ # @param prods [Hash] Productions of the grammar
61
+ # @return [Void]
41
62
  def analyzer(prod, line, prods)
42
63
  while canContinue(prod, line)
43
64
  if prod.length == 0
@@ -65,7 +86,10 @@ class GrammarAnalyzer
65
86
  end
66
87
  end
67
88
  end
68
-
89
+ # Determine if a string is valid for a Grammar
90
+ # @param file [String] JFLAP file location
91
+ # @param line [String] String to be checked
92
+ # @return [Boolean] True if the string can be matched, False otherwise
69
93
  def analyze(file, line)
70
94
  reader = GrammarReader.new
71
95
  prods = reader.createProductions(reader.readFile(file))
@@ -1,16 +1,24 @@
1
+ # Reader for JFLAP Grammar file
2
+ # @attr error [Integer] Identifier for certain errors on reading
1
3
  class GrammarReader
2
- SYNTAX_ERROR = 1
3
- PRODUCTION_ERROR = 2
4
+ # Grammar Reader SYNTAX ERROR
5
+ SYNTAX_ERROR = 100
6
+ # Grammar Reader PRODUCTION ERROR
7
+ PRODUCTION_ERROR = 101
4
8
  attr_accessor :error
5
-
6
9
  def initialize()
7
10
  @error = 0
8
11
  end
12
+ # Return the left part of a production
13
+ # @param modified [String] String containing the left part of production
14
+ # @return [String] Left part of production
9
15
  def getLeft(modified)
10
16
  modified.slice! "\t\t<left>"
11
17
  ret = modified[0]
12
18
  end
13
-
19
+ # Return the right part of a production
20
+ # @param modified [String] String containing the right part of production
21
+ # @return [String] Right part of production
14
22
  def getRight(modified)
15
23
  modified.slice! "\t\t<right>"
16
24
  ret = ""
@@ -22,7 +30,9 @@ class GrammarReader
22
30
  return ret
23
31
  end
24
32
 
25
- #returns an Array containing the lines from the file
33
+ # Returns an Array containing the lines from the file
34
+ # @param file [String] File location
35
+ # @return [Array[String]] Array containing lines in file
26
36
  def readFile(file)
27
37
  file = File.new(file, "r")
28
38
  line = file.read
@@ -30,15 +40,17 @@ class GrammarReader
30
40
  lines = line.split("\n")
31
41
  end
32
42
 
33
- #returns the Hash containing the productions
43
+ # Returns a Hash containing the productions
44
+ # @param lines [Array[String]] Separated lines of the file
45
+ # @return [Hash] Hash containing in key the left part of the production, and in value an Array with the right parts of the production
34
46
  def createProductions(lines)
35
47
  productions = Hash.new
36
48
  if !lines[0].include? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!--Created with JFLAP"
37
- @error = 1
49
+ @error = SYNTAX_ERROR
38
50
  return productions
39
51
  end
40
52
  if !lines[1].include? "\t<type>grammar</type>"
41
- @error = 2
53
+ @error = SYNTAX_ERROR
42
54
  return productions
43
55
  end
44
56
  counter = 3
data/lib/PDA.rb CHANGED
@@ -1,51 +1,87 @@
1
+ # Transition of Pushdown Automaton
2
+ # @attr destination [Integer] Next state in the transition
3
+ # @attr push [String] Elements to push in stack
4
+ # @attr pop [String] Element to pop in stack
1
5
  class PDATransition
2
6
  attr_accessor :destination, :push, :pop
7
+ # @param destination [Integer] Destination of the transition
8
+ # @param push [String] String to be pushed on stack
9
+ # @param pop [String] String to be popped of the stack
3
10
  def initialize(destination, push, pop)
4
11
  @destination = destination
5
12
  @push = push
6
13
  @pop = pop
7
14
  end
15
+ # Return the destination
16
+ # @return [Integer] Next destination
8
17
  def getDestination()
9
18
  return @destination
10
19
  end
11
20
  end
12
21
 
22
+ # Pushdown Automaton state
23
+ # @attr id [Integer] ID of the state
24
+ # @attr nombre [String] Name of the state
25
+ # @attr transitions [Hash] Transitions of the state
26
+ # @attr final [Boolean] Determine if the state is final or not
13
27
  class PDAState
14
28
  @id
15
29
  @nombre
16
30
  @transitions
17
31
  @final
32
+ # @param id [Integer] ID of the state
33
+ # @param nombre [String] Name of the state
34
+ # @param final [Boolean] The state is final or not
18
35
  def initialize(id, nombre, final)
19
36
  @id = id
20
37
  @nombre = nombre
21
38
  @transitions = Hash.new
22
39
  @final = final
23
40
  end
41
+ # Add a transition with a determinated input
42
+ # @param char [String] Key where the transition will be added
43
+ # @param to [Integer] ID of the next state
44
+ # @param pop [String] Value to be popped of the stack
45
+ # @param push [String] Value to be pushed on the stack
46
+ # @return [Void]
24
47
  def addTrans(char, to, pop, push)
25
48
  if @transitions[char] == nil
26
49
  @transitions[char] = Hash.new
27
50
  end
28
51
  @transitions[char][to] = PDATransition.new to, push, pop
29
52
  end
53
+ # Return the transition for a determinated input
54
+ # @param char [String] Input to be searched
55
+ # @return [Hash] Transitions for the input
30
56
  def transAt(char)
31
57
  ret = @transitions[char]
32
58
  end
59
+
60
+ # Determine if the state is final or not
61
+ # @return [Boolean] True if the state is final, False otherwise
33
62
  def final()
34
63
  ret = @final
35
64
  end
36
65
  end
37
66
 
67
+ # Pushdown Automaton Analyzer
68
+ # @attr valid [Boolean] Determine if the analyzer has been invalidated or not
69
+ # @attr errno [Integer] Identifier for errors
38
70
  class PDAAnalyzer
39
71
  @valid = false
40
72
  attr_accessor :errno
73
+ # Determine error number
74
+ # @return [Integer] Identifier of the error (0 -> No error)
41
75
  def errno()
42
76
  return @errno
43
77
  end
44
-
78
+
45
79
  def initialize
46
80
  @errno = 0
47
81
  end
48
-
82
+ # Get a state ID
83
+ # @param modified [String] String containing the state ID
84
+ # @return [Integer] State ID
49
85
  def getStateID(modified)
50
86
  modified.slice! "\t\t<state id=\""
51
87
  lastQuota = true
@@ -59,7 +95,9 @@ class PDAAnalyzer
59
95
  end
60
96
  id = id
61
97
  end
62
-
98
+ # Get a state name
99
+ # @param modified [String] String containing the state name
100
+ # @return [String] State name
63
101
  def getStateName(modified)
64
102
  modified.slice! "\" name=\""
65
103
  lastQuota = true
@@ -71,7 +109,9 @@ class PDAAnalyzer
71
109
  end
72
110
  id = id
73
111
  end
74
-
112
+ # Get a transition push
113
+ # @param modified [String] String containing the transition push
114
+ # @return [String] Transtion push
75
115
  def readPush(modified)
76
116
  lastQuota = true
77
117
  id = ""
@@ -82,7 +122,9 @@ class PDAAnalyzer
82
122
  end
83
123
  id = id
84
124
  end
85
-
125
+ # Get a transition pop
126
+ # @param modified [String] String containing the transition pop
127
+ # @return [String] Transtion pop
86
128
  def readPop(modified)
87
129
  lastQuota = true
88
130
  id = ""
@@ -93,7 +135,9 @@ class PDAAnalyzer
93
135
  end
94
136
  id = id
95
137
  end
96
-
138
+ # Get a transition next state
139
+ # @param modified [String] String containing the transition next state
140
+ # @return [Integer] Transtion next state
97
141
  def readTransInt(modified)
98
142
  lastQuota = true
99
143
  id = 0
@@ -105,9 +149,13 @@ class PDAAnalyzer
105
149
  id = id + char.to_i
106
150
  end
107
151
  id = id
108
-
109
152
  end
110
-
153
+ # Validate an input string
154
+ # @param initial [PDAState] Initial state
155
+ # @param states [Hash] Transitions of the automaton
156
+ # @param line [String] Line to be validated
157
+ # @param stack [Array] Stack of the automaton
158
+ # @return [Boolean] True if the string was accepted, False otherwise
111
159
  def validateString(initial, states, line, stack)
112
160
  st = initial
113
161
  usedLine = String.new line
@@ -142,8 +190,12 @@ class PDAAnalyzer
142
190
  end
143
191
  end
144
192
 
145
- #Returns true if the automaton ends in final state, returns false otherwise
193
+ # Analyze a JFLAP file for Pushdown automaton and determine if a string is valid for that automaton
194
+ # @param sourceFile [String] JFLAP File location
195
+ # @param testString [String] String to be validated
196
+ # @return [Boolean] True if the string was accepted, false otherwise
146
197
  def analyze(sourceFile, testString)
198
+ @valid = false
147
199
  file = File.new(sourceFile, "r")
148
200
  line = file.read
149
201
  file.close
@@ -1,6 +1,11 @@
1
+ # Regular Expression Analyzer
2
+ # @attr regex [Regexp] Regular Expression
3
+ # @attr errno [Integer] Identifier for errors
1
4
  class RegularExpression
2
5
  @regex
3
6
  attr_accessor :errno
7
+ # Identifier for errors
8
+ # @return [Integer] If there are errors value is more than 0, otherwise is 0
4
9
  def errno()
5
10
  return @errno
6
11
  end
@@ -8,14 +13,18 @@ class RegularExpression
8
13
  def initialize
9
14
  @errno = 0
10
15
  end
11
-
16
+ # File reader
17
+ # @param file [String] File location
18
+ # @return [Array[String]] Array containing separated lines of the file
12
19
  def readFile(file)
13
20
  file = File.new(file, "r")
14
21
  line = file.read
15
22
  file.close
16
23
  lines = line.split("\n")
17
24
  end
18
-
25
+ # Regular expression creation
26
+ # @param lines [Array[String]] Lines of the file
27
+ # @return [Void]
19
28
  def createRegex(lines)
20
29
  regex = ""
21
30
  # if lines[0].contains? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>") != nil
@@ -39,6 +48,10 @@ class RegularExpression
39
48
  regex.reverse!
40
49
  @regex = Regexp.new "^" + regex + "$"
41
50
  end
51
+ # Determine if a string is accepted by a regular expression
52
+ # @param file [String] JFLAP file location
53
+ # @param input [String] String to be validated
54
+ # @return [Boolean] True if string was accepted, False otherwise
42
55
  def analyze(file, input)
43
56
  createRegex(readFile(file))
44
57
  return false if @errno != 0
@@ -1,3 +1,7 @@
1
+ # Regular Grammar Production, since it is deprecated it is needed to add a Regular Grammar Checker to {#GrammarAnalyzer}
2
+ # @deprecated
3
+ # @attr left [String] Left part of production
4
+ # @attr right [Array] Right part of production
1
5
  class RegularGrammarProduction
2
6
  @left
3
7
  @right
@@ -5,20 +9,32 @@ class RegularGrammarProduction
5
9
  @left = left
6
10
  @right = []
7
11
  end
12
+ # Add element to right production
13
+ # @param right [String] New production to push
14
+ # @return [Void]
8
15
  def addRight(right)
9
16
  @right.push(right)
10
17
  end
18
+ # Get elements from right production
19
+ # @return [Array[String]] productions
11
20
  def getRight()
12
21
  return @right
13
22
  end
14
23
  end
15
24
 
16
- SYNTAX_ERROR = 1
17
- PRODUCTION_ERROR = 2
18
-
25
+ # Regular Grammar Analyzer, since it is deprecated it is needed to add a Regular Grammar Checker to {#GrammarAnalyzer}
26
+ # @deprecated
27
+ # @attr valid [Boolean] Determine if the string is valid in a certain time
28
+ # @attr errno [Integer] Identify errors
19
29
  class RegularGrammar
20
30
  @valid
21
31
  attr_accessor :errno
32
+ # Regular Grammar SYNTAX ERROR Identificator
33
+ SYNTAX_ERROR = 1
34
+ # Regular Grammar PRODUCTION ERROR Identificator
35
+ PRODUCTION_ERROR = 2
36
+ #Identify errors
37
+ # @return [Integer] 0 if no errors, different from 0 otherwise
22
38
  def errno()
23
39
  return @errno
24
40
  end
@@ -27,11 +43,16 @@ class RegularGrammar
27
43
  @valid = false
28
44
  @errno = 0
29
45
  end
46
+ # Get left part of production
47
+ # @param modified [String] String containing left part of production
48
+ # @return [String] Left part of production
30
49
  def getLeft(modified)
31
50
  modified.slice! "\t\t<left>"
32
51
  ret = modified[0]
33
52
  end
34
-
53
+ # Get right part of production
54
+ # @param modified [String] String containing right part of production
55
+ # @return [String] Right part of production
35
56
  def getRight(modified)
36
57
  modified.slice! "\t\t<right>"
37
58
  ret = ""
@@ -43,7 +64,9 @@ class RegularGrammar
43
64
  return ret
44
65
  end
45
66
 
46
- #returns an Array containing the lines from the file
67
+ # Returns an Array containing the lines from the file
68
+ # @param file [String] File location
69
+ # @return [Array[String]] Separated lines of the file
47
70
  def readFile(file)
48
71
  file = File.new(file, "r")
49
72
  line = file.read
@@ -51,7 +74,9 @@ class RegularGrammar
51
74
  lines = line.split("\n")
52
75
  end
53
76
 
54
- #returns the Hash containing the productions
77
+ # Returns the Hash containing the productions
78
+ # @param lines [Array[String]] Separated lines of JFLAP file
79
+ # @return [Hash] Productions of the grammar
55
80
  def createProductions(lines)
56
81
  productions = Hash.new
57
82
  if !lines[0].include? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
@@ -87,18 +112,29 @@ class RegularGrammar
87
112
  return productions
88
113
  end
89
114
 
115
+ # Verify lambda production
116
+ # @param string [String] String to be verified
117
+ # @return [Void]
90
118
  def chompLambda(string)
91
119
  if !@valid
92
120
  @valid = (string.length==0)
93
121
  end
94
122
  end
95
-
123
+
124
+ # Verify only terminal production
125
+ # @param string [String] String to be verified
126
+ # @return [Void]
96
127
  def chompChar(string, char)
97
128
  if !@valid
98
129
  @valid = (string.length == 1 && string[0] == char)
99
130
  end
100
131
  end
101
132
 
133
+ # Analyze an input
134
+ # @param productions [Hash] Grammar productions
135
+ # @param line [String] String to be verified
136
+ # @param state [RegularGrammarState] Actual State
137
+ # @return [Boolean] True if string is accepted, False otherwise
102
138
  def analyzeInput(productions, line, state)
103
139
  # Right Grammar S -> aS | a
104
140
  prods = productions[state].getRight()
@@ -174,6 +210,10 @@ class RegularGrammar
174
210
  end
175
211
  end
176
212
 
213
+ # Analyze a string from a JFLAP file
214
+ # @param file [String] JFLAP File location
215
+ # @param line [String] String to be verified
216
+ # @return [Boolean] True if string is accepted, False otherwise
177
217
  def analyze(file, line)
178
218
  productions = createProductions(readFile(file))
179
219
  @valid = analyzeInput(productions, line, "S")
@@ -1,262 +1,306 @@
1
1
  require 'thread'
2
2
  load 'Turing Reader.rb'
3
+ # Turing machine state
4
+ # @attr tag [String] Tag of the state
5
+ # @attr id [Integer] ID of the state
6
+ # @attr name [String] Name of the state
7
+ # @attr initial [Boolean] Determine if state is initial
8
+ # @attr final [Boolean] Determine if the state is final
9
+ # @attr transitions [Hash] List of transitions
3
10
  class TuringState
4
- attr_accessor :tag, :id, :name, :initial, :final, :transitions
5
- def initialize
6
- @transitions = Hash.new
7
- end
11
+ attr_accessor :tag, :id, :name, :initial, :final, :transitions
12
+ def initialize
13
+ @transitions = Hash.new
14
+ end
8
15
  end
9
16
 
17
+ # Turing Machine Transition
18
+ # @attr to [Integer] Next state
19
+ # @attr write [String] Element to write on the Turing machine tape
20
+ # @attr write [String] Position to move in the Turing machine tape
10
21
  class TuringTransition
11
22
  attr_accessor :to, :write, :move
12
23
  end
13
24
 
25
+ # Turing Machine Analyzer
26
+ # @attr reader [TuringReader] File reader
27
+ # @attr lines [Array[String]] Separated lines of the file
28
+ # @attr states [Array[TuringState]] List of states
29
+ # @attr valid [Boolean] Determine if there is a valid string
30
+ # @attr errno [Integer] Identifier for errors
31
+ # @attr initial [TuringState] Initial State
14
32
  class TuringAnalyzer
15
- attr_accessor :reader, :lines, :states, :valid, :errno
33
+ attr_accessor :reader, :lines, :states, :valid, :errno
34
+ @initial
16
35
 
36
+ # Determine the kind of error in the file
37
+ # @return [Integer] More than 0 for error, 0 for no error
17
38
  def errno()
18
39
  return @errno
19
- end
40
+ end
41
+
42
+ def initialize
43
+ @reader = TuringReader.new
44
+ @states = Array.new
45
+ @initial = nil
46
+ @valid = false
47
+ @errno = 0
48
+ end
20
49
 
21
- @initial
22
- def initialize
23
- @reader = TuringReader.new
24
- @states = Array.new
25
- @initial = nil
26
- @valid = false
27
- @errno = 0
50
+ # Analyze a string using a JFLAP Turing machine
51
+ # @param file [String] JFLAP file location
52
+ # @param line [String] String to be validated
53
+ # @return [Boolean] True if the string is accepted, False otherwise
54
+ def analyze(file, line)
55
+ @valid = false
56
+ @lines = @reader.readFile file
57
+ validateJFlap
58
+ deleteLine
59
+ validateTuringMachine
60
+ deleteLine
61
+ createStates
62
+ position = 0
63
+ until line[position] != "B"
64
+ position = position + 1
28
65
  end
66
+ validate line, @initial, position
67
+ return @valid
68
+ end
29
69
 
30
- def analyze file, line
31
- @lines = @reader.readFile file
32
- puts "Valid" if validateJFlap
33
- deleteLine
34
- puts "Valid" if validateTuringMachine
70
+ # Check if the file is from JFLAP
71
+ # @return [Boolean] True if file is from JFLAP, False otherwise
72
+ def validateJFlap
73
+ return true if @lines[0].match "JFLAP"
74
+ @errno = 1
75
+ return false
76
+ end
77
+
78
+ # Check if the file is from JFLAP Turing Machine
79
+ # @return [Boolean] True if file is from JFLAP Turing machine, False otherwise
80
+ def validateTuringMachine
81
+ return true if @lines[0].match "turing"
82
+ @errno = 2
83
+ return false
84
+ end
85
+
86
+ # Create the list of states
87
+ # @return [Void]
88
+ def createStates
89
+ return false if !lines[0].match "automaton"
90
+ deleteLine
91
+ if lines[0].match "<!--The list of states.-->"
35
92
  deleteLine
36
- createStates
37
- position = 0
38
- until line[position] != "B"
39
- position = position + 1
40
- end
41
- validate line, @initial, position
42
- return @valid
93
+ else
94
+ return false
43
95
  end
44
-
45
- def validateJFlap
46
- return true if @lines[0].match "JFLAP"
47
- @errno = 1
48
- return false
96
+ while createState
97
+ i = 1
49
98
  end
50
-
51
- def validateTuringMachine
52
- return true if @lines[0].match "turing"
53
- @errno = 2
54
- return false
99
+ if lines[0].match "<!--The list of transitions.-->"
100
+ deleteLine
101
+ else
102
+ return false
55
103
  end
56
-
57
- def createStates
58
- return false if !lines[0].match "automaton"
59
- deleteLine
60
- if lines[0].match "<!--The list of states.-->"
61
- deleteLine
62
- else
63
- return false
64
- end
65
- while createState
66
- end
67
- if lines[0].match "<!--The list of transitions.-->"
68
- deleteLine
69
- else
70
- return false
71
- end
72
- until createTransition == false
73
- end
74
- puts @states.to_s
104
+ until createTransition == false
105
+ i = 1
75
106
  end
107
+ end
76
108
 
77
- def createState
78
- state = TuringState.new
79
- return false if !lines[0].match "block"
80
- deleteTabs
81
- lines[0].slice! "<block "
82
- # Create id
83
- state.id = 0
84
- lines[0].slice! "id=\""
85
- until lines[0][0] == "\""
86
- state.id = state.id * 10
87
- state.id = state.id + lines[0][0].to_i
88
- lines[0].slice! lines[0][0]
89
- end
90
- lines[0].slice! "\" "
91
- # Create name
92
- state.name = ""
93
- lines[0].slice! "name=\""
94
- until lines[0][0] == "\""
95
- state.name = state.name + lines[0][0]
96
- lines[0].slice! lines[0][0]
97
- end
98
- deleteLine
99
- # Tags
100
- return false if !lines[0].match "tag"
101
- deleteLine
102
- # X position
103
- deleteLine
104
- # Y position
105
- deleteLine
106
- # Initial?
107
- state.initial = false
108
- if lines[0].match "initial"
109
- @initial = state.id if @initial == nil
110
- state.initial = true
111
- deleteLine
112
- end
113
- # Final?
114
- state.final = false
115
- if lines[0].match "final"
116
- state.final = true
117
- deleteLine
118
- end
119
- # Check closing bracket
120
- return false if !lines[0].match "</block>"
121
- deleteLine
122
- @states[state.id] = state
123
- return true
109
+ # Create a Turing state
110
+ # return [Boolean] False if there is an error, True otherwise
111
+ def createState
112
+ state = TuringState.new
113
+ return false if !lines[0].match "block"
114
+ deleteTabs
115
+ lines[0].slice! "<block "
116
+ # Create id
117
+ state.id = 0
118
+ lines[0].slice! "id=\""
119
+ until lines[0][0] == "\""
120
+ state.id = state.id * 10
121
+ state.id = state.id + lines[0][0].to_i
122
+ lines[0].slice! lines[0][0]
123
+ end
124
+ lines[0].slice! "\" "
125
+ # Create name
126
+ state.name = ""
127
+ lines[0].slice! "name=\""
128
+ until lines[0][0] == "\""
129
+ state.name = state.name + lines[0][0]
130
+ lines[0].slice! lines[0][0]
124
131
  end
132
+ deleteLine
133
+ # Tags
134
+ return false if !lines[0].match "tag"
135
+ deleteLine
136
+ # X position
137
+ deleteLine
138
+ # Y position
139
+ deleteLine
140
+ # Initial?
141
+ state.initial = false
142
+ if lines[0].match "initial"
143
+ @initial = state.id if @initial == nil
144
+ state.initial = true
145
+ deleteLine
146
+ end
147
+ # Final?
148
+ state.final = false
149
+ if lines[0].match "final"
150
+ state.final = true
151
+ deleteLine
152
+ end
153
+ # Check closing bracket
154
+ return false if !lines[0].match "</block>"
155
+ deleteLine
156
+ @states[state.id] = state
157
+ return true
158
+ end
125
159
 
126
- def createTransition
127
- from = 0
128
- to = 0
129
- if lines[0].match "<transition>"
130
- deleteLine
131
- else
132
- return false
133
- end
134
- # From
135
- deleteTabs
136
- lines[0].slice! "<from>"
137
- until lines[0][0] == "<"
138
- from = from * 10
139
- from = from + lines[0][0].to_i
140
- lines[0].slice! lines[0][0]
141
- end
142
- deleteLine
143
- # To
144
- deleteTabs
145
- lines[0].slice! "<to>"
146
- until lines[0][0] == "<"
147
- to = to * 10
148
- to = to + lines[0][0].to_i
149
- lines[0].slice! lines[0][0]
150
- end
151
- deleteLine
152
- # Read
153
- if lines[0].match "<read/>"
154
- read = nil
155
- else
156
- deleteTabs
157
- read = 0
158
- lines[0].slice! "<read>"
159
- until lines[0][0] == "<"
160
- read = read * 10
161
- read = read + lines[0][0].to_i
162
- lines[0].slice! lines[0][0]
163
- end
164
- end
165
- deleteLine
166
- # Write
167
- if lines[0].match "<write/>"
168
- write = nil
169
- else
170
- deleteTabs
171
- write = 0
172
- lines[0].slice! "<write>"
173
- until lines[0][0] == "<"
174
- write = write * 10
175
- write = write + lines[0][0].to_i
176
- lines[0].slice! lines[0][0]
177
- end
178
- end
179
- deleteLine
180
- if lines[0].match "<move>R"
181
- move = "R"
182
- elsif lines[0].match "<move>L"
183
- move = "L"
184
- elsif lines[0].match "<move>S"
185
- move = "S"
186
- else
187
- move = nil
188
- end
189
- if @states[from].transitions[read] == nil
190
- @states[from].transitions[read] = Array.new
191
- end
192
- trans = TuringTransition.new
193
- trans.to = to
194
- trans.write = write
195
- trans.move = move
196
- @states[from].transitions[read].push trans
197
- deleteLine
198
- if lines[0].match "</transition>"
199
- deleteLine
200
- return true
201
- end
202
- return false
160
+ # Create Turing transition
161
+ # return [Boolean] False if there is an error, True otherwise
162
+ def createTransition
163
+ from = 0
164
+ to = 0
165
+ if lines[0].match "<transition>"
166
+ deleteLine
167
+ else
168
+ return false
169
+ end
170
+ # From
171
+ deleteTabs
172
+ lines[0].slice! "<from>"
173
+ until lines[0][0] == "<"
174
+ from = from * 10
175
+ from = from + lines[0][0].to_i
176
+ lines[0].slice! lines[0][0]
177
+ end
178
+ deleteLine
179
+ # To
180
+ deleteTabs
181
+ lines[0].slice! "<to>"
182
+ until lines[0][0] == "<"
183
+ to = to * 10
184
+ to = to + lines[0][0].to_i
185
+ lines[0].slice! lines[0][0]
186
+ end
187
+ deleteLine
188
+ # Read
189
+ if lines[0].match "<read/>"
190
+ read = nil
191
+ else
192
+ deleteTabs
193
+ read = 0
194
+ lines[0].slice! "<read>"
195
+ until lines[0][0] == "<"
196
+ read = read * 10
197
+ read = read + lines[0][0].to_i
198
+ lines[0].slice! lines[0][0]
199
+ end
200
+ end
201
+ deleteLine
202
+ # Write
203
+ if lines[0].match "<write/>"
204
+ write = nil
205
+ else
206
+ deleteTabs
207
+ write = 0
208
+ lines[0].slice! "<write>"
209
+ until lines[0][0] == "<"
210
+ write = write * 10
211
+ write = write + lines[0][0].to_i
212
+ lines[0].slice! lines[0][0]
213
+ end
214
+ end
215
+ deleteLine
216
+ if lines[0].match "<move>R"
217
+ move = "R"
218
+ elsif lines[0].match "<move>L"
219
+ move = "L"
220
+ elsif lines[0].match "<move>S"
221
+ move = "S"
222
+ else
223
+ move = nil
203
224
  end
225
+ if @states[from].transitions[read] == nil
226
+ @states[from].transitions[read] = Array.new
227
+ end
228
+ trans = TuringTransition.new
229
+ trans.to = to
230
+ trans.write = write
231
+ trans.move = move
232
+ @states[from].transitions[read].push trans
233
+ deleteLine
234
+ if lines[0].match "</transition>"
235
+ deleteLine
236
+ return true
237
+ end
238
+ return false
239
+ end
204
240
 
205
- def deleteLine
206
- size = @lines.size
207
- newLines = Array.new
208
- for i in 0...size-1
209
- newLines[i] = @lines[i+1]
210
- end
211
- @lines = newLines
241
+ # Delete the first line
242
+ # @return [Void]
243
+ def deleteLine
244
+ size = @lines.size
245
+ newLines = Array.new
246
+ for i in 0...size-1
247
+ newLines[i] = @lines[i+1]
212
248
  end
249
+ @lines = newLines
250
+ end
213
251
 
214
- def deleteTabs
215
- until !lines[0].match "\t"
216
- lines[0].slice! "\t"
217
- end
252
+ # Clear tabs of the first line
253
+ # @return [Void]
254
+ def deleteTabs
255
+ until !lines[0].match "\t"
256
+ lines[0].slice! "\t"
218
257
  end
258
+ end
219
259
 
220
- def validate line, actual, position
221
- transitions = @states[actual].transitions
222
- # Launch no read transition
223
- read = line[position]
224
- if transitions[nil] != nil
225
- transitions[nil].each do |trans|
226
- if read == "B"
227
- if trans.write == nil
228
- line[position] = "B"
229
- else
230
- line[position] = trans.write
231
- end
232
- newPos = position - 1 if trans.move == "L"
233
- newPos = position + 1 if trans.move == "R"
234
- newPos = position if trans.move == "S"
235
- nilThread = Thread.new { validate(line, trans.to, newPos)}
236
- nilThread.join
237
- end
238
- end
239
- end
240
- # Launch read transition / End if no transition
241
- read = line[position]
242
- if transitions[read] == nil
243
- if @valid == false && @states[actual].final == true
244
- @valid = true
245
- end
260
+ # Validate a string
261
+ # @param line [String] Tape for Turing machine
262
+ # @param actual [TuringState] Actual state on the turing machine
263
+ # @param position [Integer] Position on the tape
264
+ # @return [Boolean] True if string is accepted, false otherwise
265
+ def validate(line, actual, position)
266
+ transitions = @states[actual].transitions
267
+ # Launch no read transition
268
+ read = line[position]
269
+ if transitions[nil] != nil
270
+ transitions[nil].each do |trans|
271
+ if read == "B"
272
+ if trans.write == nil
273
+ line[position] = "B"
274
+ else
275
+ line[position] = trans.write
276
+ end
277
+ newPos = position - 1 if trans.move == "L"
278
+ newPos = position + 1 if trans.move == "R"
279
+ newPos = position if trans.move == "S"
280
+ nilThread = Thread.new { validate(line, trans.to, newPos)}
281
+ nilThread.join
282
+ end
283
+ end
284
+ end
285
+ # Launch read transition / End if no transition
286
+ read = line[position]
287
+ if transitions[read] == nil
288
+ if @valid == false && @states[actual].final == true
289
+ @valid = true
290
+ end
291
+ else
292
+ transitions[read].each do |trans|
293
+ if trans.write == nil
294
+ line[position] = "B"
246
295
  else
247
- transitions[read].each do |trans|
248
- if trans.write == nil
249
- line[position] = "B"
250
- else
251
- line[position] = trans.write
252
- end
253
- newPos = position - 1 if trans.move == "L"
254
- newPos = position + 1 if trans.move == "R"
255
- newPos = position if trans.move == "S"
256
- thread = Thread.new { validate(line, trans.to, newPos)}
257
- thread.join
258
- end
296
+ line[position] = trans.write
259
297
  end
260
- end
261
-
298
+ newPos = position - 1 if trans.move == "L"
299
+ newPos = position + 1 if trans.move == "R"
300
+ newPos = position if trans.move == "S"
301
+ thread = Thread.new { validate(line, trans.to, newPos)}
302
+ thread.join
303
+ end
304
+ end
305
+ end
262
306
  end
@@ -1,10 +1,12 @@
1
+ # JFLAP Turing Machine File reader
1
2
  class TuringReader
2
-
3
+ # Lines of the file
4
+ # @param file [String] File location
5
+ # @return [Array[String]] Separated lines of the file
3
6
  def readFile(file)
4
7
  file = File.new file, "r"
5
8
  line = file.read
6
9
  file.close
7
10
  lines = line.split "\n"
8
11
  end
9
-
10
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SEATC
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.25
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Salvador Guerra Delgado
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-08 00:00:00.000000000 Z
11
+ date: 2018-11-01 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
14
  automaton and grammars analysis
@@ -60,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
60
  version: '0'
61
61
  requirements: []
62
62
  rubyforge_project:
63
- rubygems_version: 2.5.2.1
63
+ rubygems_version: 2.6.14
64
64
  signing_key:
65
65
  specification_version: 3
66
66
  summary: SEATC