diff --git a/assets/parser.c.erb b/assets/parser.c.erb index a23ed7f..6928e54 100644 --- a/assets/parser.c.erb +++ b/assets/parser.c.erb @@ -669,7 +669,7 @@ typedef struct /** Parser shift table. */ static const shift_t parser_shift_table[] = { <% @parser.shift_table.each do |shift| %> - {<%= shift[:symbol_id] %>u, <%= shift[:state_id] %>u}, + {<%= shift[:symbol].id %>u, <%= shift[:state_id] %>u}, <% end %> }; diff --git a/assets/parser.d.erb b/assets/parser.d.erb index 7fe35c1..41e6297 100644 --- a/assets/parser.d.erb +++ b/assets/parser.d.erb @@ -817,7 +817,7 @@ private struct state_value_t /** Parser shift table. */ private immutable shift_t[] parser_shift_table = [ <% @parser.shift_table.each do |shift| %> - shift_t(<%= shift[:symbol_id] %>u, <%= shift[:state_id] %>u), + shift_t(<%= shift[:symbol].id %>u, <%= shift[:state_id] %>u), <% end %> ]; diff --git a/lib/propane/parser.rb b/lib/propane/parser.rb index 5f1f25a..0874a52 100644 --- a/lib/propane/parser.rb +++ b/lib/propane/parser.rb @@ -13,6 +13,7 @@ class Propane @log = log @item_sets = [] @item_sets_set = {} + @sr_conflicts = Set.new start_item = Item.new(grammar.rules.first, 0) eval_item_sets = Set[ItemSet.new([start_item])] @@ -38,8 +39,8 @@ class Propane build_reduce_actions! build_follow_sets! - write_log! build_tables! + write_log! end private @@ -57,10 +58,17 @@ class Propane item_set.next_item_set[next_symbol].id end { - symbol_id: next_symbol.id, + symbol: next_symbol, state_id: state_id, } end + if item_set.reduce_actions + shift_entries.each do |shift_entry| + if item_set.reduce_actions.include?(shift_entry[:symbol]) + @sr_conflicts << [shift_entry[:symbol], item_set.reduce_actions[shift_entry[:symbol]]] + end + end + end reduce_entries = if rule = item_set.reduce_rule [{token_id: @grammar.invalid_token_id, rule_id: rule.id, rule: rule, @@ -310,6 +318,13 @@ class Propane end end end + if @sr_conflicts.size > 0 + @log.puts + @log.puts "Shift/Reduce Conflicts:" + @sr_conflicts.each do |sr_conflict| + @log.puts " Shift/Reduce conflict between #{sr_conflict[0].name} and #{sr_conflict[1].name}" + end + end end end diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 331b20a..f26b482 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -184,6 +184,20 @@ EOF expect(results.status).to_not eq 0 end + it "warns on shift/reduce conflicts" do + write_grammar < As? b?; +As -> a As2?; +As2 -> b a As2?; +EOF + results = run_propane(capture: true) + expect(results.stderr).to eq "" + expect(results.status).to eq 0 + expect(File.binread("spec/run/testparser.log")).to match %r{Shift/Reduce conflict between b and As2} + end + %w[d c].each do |language| context "#{language.upcase} language" do