Class: Sequitur::Production
- Inherits:
-
Object
- Object
- Sequitur::Production
- Defined in:
- lib/sequitur/production.rb
Overview
In a context-free grammar, a production is a rule in which its left-hand side (LHS) consists solely of a non-terminal symbol and the right-hand side (RHS) consists of a sequence of symbols. The symbols in RHS can be either terminal or non-terminal symbols. The rule stipulates that the LHS is equivalent to the RHS, in other words every occurrence of the LHS can be substituted to corresponding RHS. Implementation note: the object id of the production is taken as its LHS.
Instance Attribute Summary collapse
-
#digrams ⇒ Object
readonly
The sequence of digrams appearing in the RHS.
-
#refcount ⇒ Object
readonly
The reference count (= how times other productions reference this one).
-
#rhs ⇒ Object
readonly
The right-hand side (rhs) consists of a sequence of grammar symbols.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Identity testing.
-
#accept(aVisitor) ⇒ Object
Part of the 'visitee' role in Visitor design pattern.
-
#append_symbol(aSymbol) ⇒ Object
Add a (grammar) symbol at the end of the RHS.
-
#clear_rhs ⇒ Object
Clear the right-hand side.
-
#decr_refcount ⇒ Object
Decrement the reference count by one.
-
#derive_step(another) ⇒ Object
Replace every occurrence of 'another' production in self.rhs by the symbols in the rhs of 'another'.
-
#empty? ⇒ Boolean
Is the rhs empty? @ return true if the rhs has no members.
-
#incr_refcount ⇒ Object
Increment the reference count by one.
-
#initialize ⇒ Production
constructor
Constructor.
-
#last_digram ⇒ Digram
Retrieve the last digram appearing in the RHS (if any).
-
#positions_of(symb1, symb2) ⇒ Array
Find all the positions where the digram occurs in the rhs.
-
#recalc_digrams ⇒ Array
Enumerate the digrams appearing in the right-hand side (rhs).
-
#reduce_step(another) ⇒ Object
Given that the production P passed as argument has exactly 2 symbols in its rhs s1 s2, substitute in the rhs of self all occurrences of s1 s2 by a reference to P.
-
#references ⇒ Array of ProductionRef
Select the references to production appearing in the rhs.
-
#references_of(aProduction) ⇒ Array
Look in the rhs all the references to a production passed a argument.
-
#repeated_digram? ⇒ true/false
Detect whether the last digram occurs twice Assumption: when a digram occurs twice in a production then it must occur at the end of the rhs.
-
#single_digram? ⇒ true/false
Does the rhs have exactly one digram only (= 2 symbols)?.
-
#to_string ⇒ String
Emit a text representation of the production rule.
Constructor Details
#initialize ⇒ Production
Constructor. Build a production with an empty RHS.
27 28 29 30 31 |
# File 'lib/sequitur/production.rb', line 27 def initialize() clear_rhs @refcount = 0 @digrams = [] end |
Instance Attribute Details
#digrams ⇒ Object (readonly)
The sequence of digrams appearing in the RHS
23 24 25 |
# File 'lib/sequitur/production.rb', line 23 def digrams @digrams end |
#refcount ⇒ Object (readonly)
The reference count (= how times other productions reference this one)
20 21 22 |
# File 'lib/sequitur/production.rb', line 20 def refcount @refcount end |
#rhs ⇒ Object (readonly)
The right-hand side (rhs) consists of a sequence of grammar symbols
17 18 19 |
# File 'lib/sequitur/production.rb', line 17 def rhs @rhs end |
Instance Method Details
#==(other) ⇒ Object
Identity testing.
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/sequitur/production.rb', line 38 def ==(other) return true if object_id == other.object_id if other.is_a?(ProductionRef) result = (other == self) else result = false end return result end |
#accept(aVisitor) ⇒ Object
Part of the 'visitee' role in Visitor design pattern.
253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/sequitur/production.rb', line 253 def accept(aVisitor) aVisitor.start_visit_production(self) rhs.each do |a_symb| if a_symb.is_a?(ProductionRef) a_symb.accept(aVisitor) else aVisitor.visit_terminal(a_symb) end end aVisitor.end_visit_production(self) end |
#append_symbol(aSymbol) ⇒ Object
Add a (grammar) symbol at the end of the RHS.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/sequitur/production.rb', line 144 def append_symbol(aSymbol) case aSymbol when Production new_symb = ProductionRef.new(aSymbol) when ProductionRef if aSymbol.unbound? msg = 'Fail to append reference to nil production in ' msg << to_string fail StandardError, msg end new_symb = aSymbol.dup else new_symb = aSymbol end rhs << new_symb digrams << Digram.new(rhs[-2], rhs[-1], self) if rhs.size >= 2 end |
#clear_rhs ⇒ Object
Clear the right-hand side. Any referenced production has its reference counter decremented.
165 166 167 168 169 170 171 |
# File 'lib/sequitur/production.rb', line 165 def clear_rhs() if rhs refs = references refs.each(&:unbind) end @rhs = [] end |
#decr_refcount ⇒ Object
Decrement the reference count by one.
63 64 65 66 |
# File 'lib/sequitur/production.rb', line 63 def decr_refcount() fail StandardError, 'Internal error' if @refcount == 0 @refcount -= 1 end |
#derive_step(another) ⇒ Object
Replace every occurrence of 'another' production in self.rhs by the symbols in the rhs of 'another'.
Given the production p_A : a p_B b p_B c
And the production p_B : x y
Then...
p_A.derive_step(p_B)
Modifies p_A as into: p_A -> a x y b x y c
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/sequitur/production.rb', line 234 def derive_step(another) (0...rhs.size).to_a.reverse.each do |index| next unless rhs[index] == another # Avoid the aliasing of production reference other_rhs = another.rhs.map do |symb| symb.is_a?(ProductionRef) ? symb.dup : symb end rhs.insert(index + 1, *other_rhs) another.decr_refcount rhs.delete_at(index) end recalc_digrams end |
#empty? ⇒ Boolean
Is the rhs empty? @ return true if the rhs has no members.
53 54 55 |
# File 'lib/sequitur/production.rb', line 53 def empty? return rhs.empty? end |
#incr_refcount ⇒ Object
Increment the reference count by one.
58 59 60 |
# File 'lib/sequitur/production.rb', line 58 def incr_refcount() @refcount += 1 end |
#last_digram ⇒ Digram
Retrieve the last digram appearing in the RHS (if any).
120 121 122 123 |
# File 'lib/sequitur/production.rb', line 120 def last_digram() result = digrams.empty? ? nil : digrams.last return result end |
#positions_of(symb1, symb2) ⇒ Array
Find all the positions where the digram occurs in the rhs
185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/sequitur/production.rb', line 185 def positions_of(symb1, symb2) # Find the positions where the digram occur in rhs indices = [ -2 ] # Dummy index! (0...rhs.size).each do |i| next if i == indices.last + 1 indices << i if (rhs[i] == symb1) && (rhs[i + 1] == symb2) end indices.shift return indices end |
#recalc_digrams ⇒ Array
Enumerate the digrams appearing in the right-hand side (rhs)
86 87 88 89 90 91 92 93 |
# File 'lib/sequitur/production.rb', line 86 def recalc_digrams() return [] if rhs.size < 2 result = [] rhs.each_cons(2) { |couple| result << Digram.new(*couple, self) } @digrams = result end |
#reduce_step(another) ⇒ Object
Given that the production P passed as argument has exactly 2 symbols in its rhs s1 s2, substitute in the rhs of self all occurrences of s1 s2 by a reference to P.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/sequitur/production.rb', line 205 def reduce_step(another) (symb1, symb2) = another.rhs pos = positions_of(symb1, symb2).reverse # Replace the two symbol sequence by the production pos.each do |index| if rhs[index].is_a?(ProductionRef) rhs[index].bind_to(another) else rhs[index] = ProductionRef.new(another) end index1 = index + 1 rhs[index1].unbind if rhs[index1].is_a?(ProductionRef) rhs.delete_at(index1) end recalc_digrams end |
#references ⇒ Array of ProductionRef
Select the references to production appearing in the rhs.
71 72 73 |
# File 'lib/sequitur/production.rb', line 71 def references() return rhs.select { |symb| symb.is_a?(ProductionRef) } end |
#references_of(aProduction) ⇒ Array
Look in the rhs all the references to a production passed a argument. aProduction [aProduction or ProductionRef] The production to search for.
78 79 80 81 |
# File 'lib/sequitur/production.rb', line 78 def references_of(aProduction) refs = references return refs.select { |a_ref| a_ref == aProduction } end |
#repeated_digram? ⇒ true/false
Detect whether the last digram occurs twice Assumption: when a digram occurs twice in a production then it must occur at the end of the rhs
108 109 110 111 112 113 114 115 116 |
# File 'lib/sequitur/production.rb', line 108 def repeated_digram?() return false if rhs.size < 3 my_digrams = digrams all_keys = my_digrams.map(&:key) last_key = all_keys.pop same_key_found = all_keys.index(last_key) return !same_key_found.nil? end |
#single_digram? ⇒ true/false
Does the rhs have exactly one digram only (= 2 symbols)?
99 100 101 |
# File 'lib/sequitur/production.rb', line 99 def single_digram? return rhs.size == 2 end |
#to_string ⇒ String
Emit a text representation of the production rule. Text is of the form: object id of production : rhs as space-separated sequence of symbols.
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/sequitur/production.rb', line 131 def to_string() rhs_text = rhs.map do |elem| case elem when String then "'#{elem}'" else elem.to_s end end return "#{object_id} : #{rhs_text.join(' ')}." end |