diff --git a/lib/propane/parser.rb b/lib/propane/parser.rb index 28617b0..cb7d8ef 100644 --- a/lib/propane/parser.rb +++ b/lib/propane/parser.rb @@ -134,7 +134,7 @@ class Propane # possible following tokens, we will only look in the item sets leading # up to this one. This restriction gives us a more precise lookahead set, # and allows us to parse LALR grammars. - item_sets = item_set.leading_item_sets + item_sets = Set[item_set] + item_set.leading_item_sets reduce_rules.reduce({}) do |reduce_actions, reduce_rule| lookahead_tokens_for_rule = build_lookahead_tokens_to_reduce(reduce_rule, item_sets) lookahead_tokens_for_rule.each do |lookahead_token| diff --git a/lib/propane/parser/item_set.rb b/lib/propane/parser/item_set.rb index 661f58b..980d4a6 100644 --- a/lib/propane/parser/item_set.rb +++ b/lib/propane/parser/item_set.rb @@ -87,14 +87,24 @@ class Propane # Set of ItemSets that lead to this ItemSet. # - # This set includes this ItemSet. - # # @return [Set] # Set of all ItemSets that lead up to this ItemSet. def leading_item_sets - @in_sets.reduce(Set[self]) do |result, item_set| - result + item_set.leading_item_sets + result = Set.new + eval_sets = Set[self] + evaled = Set.new + while eval_sets.size > 0 + eval_set = eval_sets.first + eval_sets.delete(eval_set) + evaled << eval_set + eval_set.in_sets.each do |in_set| + result << in_set + unless evaled.include?(in_set) + eval_sets << in_set + end + end end + result end # Represent the ItemSet as a String. diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index bd365bf..441571c 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -851,6 +851,20 @@ EOF "R", ]) end + + it "handles when an item set leads to itself" do + write_grammar < Opt one Start; +Start -> ; + +Opt -> two; +Opt -> ; +EOF + build_parser(language: language) + end end end end