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 ⇒ Array<Sequitur::Digram>
readonly
The sequence of digrams appearing in the RHS.
-
#refcount ⇒ Integer
readonly
The reference count (= how times other productions reference this one).
-
#rhs ⇒ Sequitur::SymbolSequence
readonly
The right-hand side (rhs) consists of a sequence of grammar symbols.
Instance Method Summary collapse
-
#==(other) ⇒ TrueClass, FalseClass
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 ⇒ Integer
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? ⇒ TrueClass, FalseClass
Is the rhs empty?.
-
#incr_refcount ⇒ Integer
Increment the reference count by one.
-
#initialize ⇒ Production
constructor
Constructor.
-
#last_digram ⇒ Sequitur::Digram, NilClass
Retrieve the last digram appearing in the RHS (if any).
-
#positions_of(symb1, symb2) ⇒ Array<Integer>
Find all the positions where the digram occurs in the rhs.
-
#recalc_digrams ⇒ Array<Sequitur::Digram>
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<ProductionRef>
Select the references to production appearing in the rhs.
-
#references_of(a_prod) ⇒ Array<ProductionRef>
Look in the rhs all the references to a production passed a argument.
-
#repeated_digram? ⇒ TrueClass, FalseClass
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? ⇒ TrueClass, FalseClass
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.
29 30 31 32 33 |
# File 'lib/sequitur/production.rb', line 29 def initialize @rhs = SymbolSequence.new @refcount = 0 @digrams = [] end |
Instance Attribute Details
#digrams ⇒ Array<Sequitur::Digram> (readonly)
Returns The sequence of digrams appearing in the RHS.
25 26 27 |
# File 'lib/sequitur/production.rb', line 25 def digrams @digrams end |
#refcount ⇒ Integer (readonly)
Returns The reference count (= how times other productions reference this one).
22 23 24 |
# File 'lib/sequitur/production.rb', line 22 def refcount @refcount end |
#rhs ⇒ Sequitur::SymbolSequence (readonly)
Returns The right-hand side (rhs) consists of a sequence of grammar symbols.
19 20 21 |
# File 'lib/sequitur/production.rb', line 19 def rhs @rhs end |
Instance Method Details
#==(other) ⇒ TrueClass, FalseClass
Identity testing.
38 39 40 41 42 43 44 45 46 |
# File 'lib/sequitur/production.rb', line 38 def ==(other) return true if object_id == other.object_id if other.is_a?(ProductionRef) (other == self) else false end end |
#accept(aVisitor) ⇒ Object
Part of the 'visitee' role in Visitor design pattern.
218 219 220 221 222 |
# File 'lib/sequitur/production.rb', line 218 def accept(aVisitor) aVisitor.start_visit_production(self) rhs.accept(aVisitor) aVisitor.end_visit_production(self) end |
#append_symbol(aSymbol) ⇒ Object
Add a (grammar) symbol at the end of the RHS.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/sequitur/production.rb', line 128 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 raise 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.
149 150 151 |
# File 'lib/sequitur/production.rb', line 149 def clear_rhs rhs.clear end |
#decr_refcount ⇒ Integer
Decrement the reference count by one.
62 63 64 65 66 |
# File 'lib/sequitur/production.rb', line 62 def decr_refcount raise StandardError, 'Internal error' if @refcount.zero? @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
204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/sequitur/production.rb', line 204 def derive_step(another) (0...rhs.size).to_a.reverse_each do |index| next unless rhs[index] == another rhs.insert_at(index + 1, another.rhs) another.decr_refcount rhs.delete_at(index) end recalc_digrams end |
#empty? ⇒ TrueClass, FalseClass
Is the rhs empty?
50 51 52 |
# File 'lib/sequitur/production.rb', line 50 def empty? rhs.empty? end |
#incr_refcount ⇒ Integer
Increment the reference count by one.
56 57 58 |
# File 'lib/sequitur/production.rb', line 56 def incr_refcount @refcount += 1 end |
#last_digram ⇒ Sequitur::Digram, NilClass
Retrieve the last digram appearing in the RHS (if any).
114 115 116 |
# File 'lib/sequitur/production.rb', line 114 def last_digram digrams.empty? ? nil : digrams.last end |
#positions_of(symb1, symb2) ⇒ Array<Integer>
Find all the positions where the digram occurs in the rhs
165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/sequitur/production.rb', line 165 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 indices end |
#recalc_digrams ⇒ Array<Sequitur::Digram>
Enumerate the digrams appearing in the right-hand side (rhs)
84 85 86 87 88 89 90 |
# File 'lib/sequitur/production.rb', line 84 def recalc_digrams return [] if rhs.size < 2 result = [] rhs.symbols.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.
184 185 186 187 188 189 190 191 192 |
# File 'lib/sequitur/production.rb', line 184 def reduce_step(another) (symb1, symb2) = another.rhs.symbols pos = positions_of(symb1, symb2).reverse # Replace the two symbol sequence by the production pos.each { |index| rhs.reduce_step(index, another) } recalc_digrams end |
#references ⇒ Array<ProductionRef>
Select the references to production appearing in the rhs.
70 71 72 |
# File 'lib/sequitur/production.rb', line 70 def references rhs.references end |
#references_of(a_prod) ⇒ Array<ProductionRef>
Look in the rhs all the references to a production passed a argument.
77 78 79 80 |
# File 'lib/sequitur/production.rb', line 77 def references_of(a_prod) real_prod = a_prod.is_a?(ProductionRef) ? a_prod.production : a_prod rhs.references_of(real_prod) end |
#repeated_digram? ⇒ TrueClass, FalseClass
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
102 103 104 105 106 107 108 109 110 |
# File 'lib/sequitur/production.rb', line 102 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) !same_key_found.nil? end |
#single_digram? ⇒ TrueClass, FalseClass
Does the rhs have exactly one digram only (= 2 symbols)?
94 95 96 |
# File 'lib/sequitur/production.rb', line 94 def single_digram? 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.
122 123 124 |
# File 'lib/sequitur/production.rb', line 122 def to_string "#{object_id} : #{rhs.to_string}." end |