lib/antelope/generation/tableizer.rb in antelope-0.1.8 vs lib/antelope/generation/tableizer.rb in antelope-0.1.9
- old
+ new
@@ -36,10 +36,11 @@
# @see #tablize
# @see #conflictize
def call
tablize
conflictize
+ defaultize
end
# Construct a table based on the grammar. The table itself is
# an array whose elements are hashes; the index of the array
# corresponds to the state ID, and the keys of the hashes
@@ -65,11 +66,12 @@
table[state.id][look.name] <<
[:reduce, rule.production.id]
end
if rule.production.id.zero?
- table[state.id][:"$"] = [[:accept, rule.production.id]]
+ table[state.id][:$end] =
+ [[:accept, rule.production.id]]
end
end
end
end
@@ -92,11 +94,11 @@
next
end
terminal = grammar.precedence_for(on)
- rule_part, other_part = data.sort_by { |(t, d)| t }
+ rule_part, other_part = data.sort_by { |(t, _)| t }
unless other_part[0] == :state
$stderr.puts \
"Could not determine move for #{on} in state " \
"#{state} (reduce/reduce conflict)"
@@ -115,9 +117,35 @@
"#{state} (shift/reduce conflict)"
when 1
@table[state][on] = rule_part
when -1
@table[state][on] = other_part
+ end
+ end
+ end
+ end
+
+ # Reduce many transitions into a single `$default` transition.
+ # This only works if there is no `$empty` transition; if there
+ # is an `$empty` transition, then the `$default` transition is
+ # set to be the `$empty` transition.
+ #
+ # @return [void]
+ def defaultize
+ max = @table.map { |s| s.keys.size }.max
+ @table.each_with_index do |state|
+ if state.key?(:$empty)
+ state[:$default] = state[:$empty]
+ else
+ common = state.group_by { |k, v| v }.values.
+ sort_by(&:size).first
+
+ if common.size > (max / 2)
+ action = common[0][1]
+
+ keys = common.map(&:first)
+ state.delete_if { |k, _| keys.include?(k) }
+ state[:$default] = action
end
end
end
end
end