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(a_prod) ⇒ 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.
28 29 30 31 32 |
# File 'lib/sequitur/production.rb', line 28 def initialize @rhs = SymbolSequence.new @refcount = 0 @digrams = [] end |
Instance Attribute Details
#digrams ⇒ Object (readonly)
The sequence of digrams appearing in the RHS
24 25 26 |
# File 'lib/sequitur/production.rb', line 24 def digrams @digrams end |
#refcount ⇒ Object (readonly)
The reference count (= how times other productions reference this one)
21 22 23 |
# File 'lib/sequitur/production.rb', line 21 def refcount @refcount end |
#rhs ⇒ Object (readonly)
The right-hand side (rhs) consists of a sequence of grammar symbols
18 19 20 |
# File 'lib/sequitur/production.rb', line 18 def rhs @rhs end |
Instance Method Details
#==(other) ⇒ Object
Identity testing.
37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/sequitur/production.rb', line 37 def ==(other) return true if object_id == other.object_id result = if other.is_a?(ProductionRef) (other == self) else false end return result end |
#accept(aVisitor) ⇒ Object
Part of the 'visitee' role in Visitor design pattern.
218 219 220 221 222 223 224 |
# 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 ⇒ Object
Decrement the reference count by one.
61 62 63 64 65 |
# File 'lib/sequitur/production.rb', line 61 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? ⇒ Boolean
Is the rhs empty? @ return true if the rhs has no members.
51 52 53 |
# File 'lib/sequitur/production.rb', line 51 def empty? return rhs.empty? end |
#incr_refcount ⇒ Object
Increment the reference count by one.
56 57 58 |
# File 'lib/sequitur/production.rb', line 56 def incr_refcount @refcount += 1 end |
#last_digram ⇒ Digram
Retrieve the last digram appearing in the RHS (if any).
113 114 115 116 |
# File 'lib/sequitur/production.rb', line 113 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
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 return indices end |
#recalc_digrams ⇒ Array
Enumerate the digrams appearing in the right-hand side (rhs)
83 84 85 86 87 88 89 |
# File 'lib/sequitur/production.rb', line 83 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 of ProductionRef
Select the references to production appearing in the rhs.
69 70 71 |
# File 'lib/sequitur/production.rb', line 69 def references return rhs.references end |
#references_of(a_prod) ⇒ Array
Look in the rhs all the references to a production passed a argument. aProduction [aProduction or ProductionRef] The production to search for.
76 77 78 79 |
# File 'lib/sequitur/production.rb', line 76 def references_of(a_prod) real_prod = a_prod.is_a?(ProductionRef) ? a_prod.production : a_prod return rhs.references_of(real_prod) 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
101 102 103 104 105 106 107 108 109 |
# File 'lib/sequitur/production.rb', line 101 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)?
93 94 95 |
# File 'lib/sequitur/production.rb', line 93 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.
122 123 124 |
# File 'lib/sequitur/production.rb', line 122 def to_string return "#{object_id} : #{rhs.to_string}." end |