Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
junk0612 committed Sep 4, 2024
1 parent 2b538b0 commit 604737d
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 138 deletions.
2 changes: 1 addition & 1 deletion lib/lrama/option_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def parse_by_option_parser(argv)
o.on('-S', '--skeleton=FILE', 'specify the skeleton to use') {|v| @options.skeleton = v }
o.on('-t', 'reserved, do nothing') { }
o.on('--debug', 'display debugging outputs of internal parser') {|v| @options.debug = true }
o.on('-D', '--define=NAME[=VALUE]', "similar to '%define NAME VALUE'") {|v| @options.define = v }
o.on('-D', '--define=NAME[=VALUE]', Array, "similar to '%define NAME VALUE'") {|v| @options.define = v }
o.separator ''
o.separator 'Output:'
o.on('-H', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v }
Expand Down
6 changes: 0 additions & 6 deletions lib/lrama/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,5 @@ def initialize
@y = STDIN
@debug = false
end

def define=(v)
v.split(',').each do |p_define|
@define.store *p_define.split('=')
end
end
end
end
142 changes: 135 additions & 7 deletions lib/lrama/state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
require_relative "state/resolved_conflict"
require_relative "state/shift"
require_relative "state/shift_reduce_conflict"
require_relative "state/inadequacy_annotation"

module Lrama
class State
attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
:default_reduction_rule, :closure, :items, :predecessors
attr_accessor :shifts, :reduces
attr_accessor :shifts, :reduces, :lalr_isocore

def initialize(id, accessing_symbol, kernels)
@id = id
Expand All @@ -24,6 +25,7 @@ def initialize(id, accessing_symbol, kernels)
@resolved_conflicts = []
@default_reduction_rule = nil
@predecessors = []
@lalr_isocore = self
end

def closure=(closure)
Expand Down Expand Up @@ -157,7 +159,7 @@ def internal_dependencies(shift, next_state)
nterm_transitions.select {|other_shift, _|
@items.find {|item| item.next_sym == shift.next_sym && item.lhs == other_shift.next_sym && item.symbols_after_dot.all?(&:nullable) }
}.reduce([[shift, next_state]]) {|result, transition|
result += internal_follows(*transition)
result += internal_dependencies(*transition)
}
end

Expand All @@ -169,16 +171,111 @@ def successor_dependencies(shift, next_state)
}
end

def inspect
"#{id} -> #{@kernels.map(&:to_s).join(', ')}"
end

def inadequacy_list
return @inadequacy_list if @inadequacy_list

list = shifts.to_h {|shift| [shift.next_sym, [[shift, nil]]] }
reduces.each do |reduce|
reduce_list = (reduce.look_ahead || []).to_h {|sym| [sym, [[reduce, reduce.item]]] }
list.merge!(reduce_list) {|_, list_value, reduce_value| list_value + reduce_value }
shift_contributions = shifts.to_h {|shift|
[shift.next_sym, [shift]]
}
reduce_contributions = reduces.map {|reduce|
(reduce.look_ahead || []).to_h {|sym|
[sym, [reduce]]
}
}.reduce(Hash.new([])) {|hash, cont|
hash.merge(cont) {|_, a, b| a.union(b) }
}

list = shift_contributions.merge(reduce_contributions) {|_, a, b| a.union(b) }
@inadequacy_list = list.select {|token, actions| token.term? && actions.size > 1 }
end

def annotate_manifestation
inadequacy_list.map {|token, actions|
actions.map {|action|
if action.is_a?(Shift)
[InadequacyAnnotation.new(token: token, action: action, item: nil, contributed: false)]
elsif action.is_a?(Reduce)
if action.rule.empty_rule?
lhs_contributions(action.rule.lhs, token).map {|kernel, contributed|
InadequacyAnnotation.new(token: token, action: action, item: kernel, contributed: contributed)
}
else
kernels.map {|kernel|
contributed = kernel.rule == action.rule && kernel.end_of_rule?
InadequacyAnnotation.new(token: token, action: action, item: kernel, contributed: contributed)
}
end
end
}
}
end

def annotate_predecessor(annotation_list)
annotation_list.reduce([]) {|annotation|
next [token, {}] if annotation.no_contributions? || actions.any? {|action, hash|
p action, hash
hash.keys.any? {|item| hash[item] && item.position == 1 && compute_lhs_contributions(state, item.lhs, token).empty? }
}
[
token, actions.to_h {|action, hash|
[
action, hash.to_h {|item, _|
kernel = state.kernels.find {|k| k.rule == item.rule && k.position == item.position - 1 }
[kernel,
hash[item] &&
(
!kernel.nil? && (state.item_lookahead_set[kernel].include?(token)) ||
(item.position == 1 && compute_lhs_contributions(state, item.lhs, token)[item])
)
]
}
]
}
]
}
end

def item_lookahead_set
@item_lookahead_set ||=
kernels.to_h {|item|
value =
if item.position > 1
prev_state, prev_item = predecessor_with_item(item)
prev_state.item_lookahead_set[prev_item]
elsif item.position == 1
prev_state = predecessors.find {|p| p.shifts.any? {|shift| shift.next_sym == item.lhs } }
shift, next_state = prev_state.nterm_transitions.find {|shift, _| shift.next_sym == item.lhs }
prev_state.goto_follows(shift, next_state)
else
[]
end
[item, value]
}
end

def item_lookahead_set=(k)
@item_lookahead_set = k
end

def predecessor_with_item(item)
predecessors.each do |state|
state.kernels.each do |kernel|
return [state, kernel] if kernel.rule == item.rule && kernel.position == item.position - 1
end
end
end

@inadequacy_list = {self => list.select {|_, actions| actions.size > 1 }}
def lhs_contributions(sym, token)
shift, next_state = nterm_transitions.find {|sh, _| sh.next_sym == sym }
if always_follows(shift, next_state).include?(token)
[]
else
kernels.map {|kernel| [kernel, follow_kernel?(kernel) && item_lookahead_set[kernel].include?(token)] }
end
end

def follow_kernel?(item)
Expand All @@ -189,8 +286,39 @@ def follow_kernel_items(shift, next_state, item)
internal_dependencies(shift, next_state).any? {|shift, _| shift.next_sym == item.next_sym } && item.symbols_after_dot.all?(&:nullable)
end

def next_terms
shifts.filter_map {|shift| shift.next_sym.term? && shift.next_sym }
end

def append_predecessor(prev_state)
@predecessors << prev_state
@predecessors.uniq!
end

def goto_follows(shift, next_state)
include_dependencies(shift, next_state).reduce([]) {|result, goto|
st, sh, next_st = goto
result.union(st.always_follows(sh, next_st))
}
end

def include_dependencies(shift, next_state)
internal = internal_dependencies(shift, next_state).map {|sh, next_st| [self, sh, next_st] }
pred = predecessor_dependencies(shift, next_state)

return internal if pred.empty?
dependency = internal.union(pred)

dependency.reduce(dependency) {|result, goto| result.union(compute_include_dependencies(*goto)) }
end

def predecessor_dependencies(shift, next_state)
item = kernels.find {|kernel| kernel.next_sym == shift.next_sym }
return [] unless item.symbols_after_transition.all?(&:nullable)

st = @predecessors.find {|p| p.items.find {|i| i.rule == item.rule && i.position == item.position - 1 } }
sh, next_st = s.nterm_transitions.find {|shift, _| shift.next_token == item.lhs }
[[s, sh, next_st]]
end
end
end
9 changes: 9 additions & 0 deletions lib/lrama/state/inadequacy_annotation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Lrama
class State
class InadequacyAnnotation < Struct.new(:token, :action, :item, :contributed, keyword_init: true)
def no_contributions?
item.nil? && !contributed
end
end
end
end
Loading

0 comments on commit 604737d

Please sign in to comment.