diff --git a/lib/lrama/option_parser.rb b/lib/lrama/option_parser.rb index 24ee3792..90535fe5 100644 --- a/lib/lrama/option_parser.rb +++ b/lib/lrama/option_parser.rb @@ -91,7 +91,7 @@ def parse_by_option_parser(argv) end end - BISON_REPORTS = %w[states itemsets lookaheads solved counterexamples cex all none] + BISON_REPORTS = %w[terms states itemsets lookaheads solved counterexamples cex all none] OTHER_REPORTS = %w[verbose] NOT_SUPPORTED_REPORTS = %w[cex none] VALID_REPORTS = BISON_REPORTS + OTHER_REPORTS - NOT_SUPPORTED_REPORTS diff --git a/lib/lrama/states_reporter.rb b/lib/lrama/states_reporter.rb index a2dacba2..d05c48c9 100644 --- a/lib/lrama/states_reporter.rb +++ b/lib/lrama/states_reporter.rb @@ -16,15 +16,53 @@ def report(io, **options) private - def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false) - # TODO: Unused terms + def _report(io, grammar: false, terms: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false) # TODO: Unused rules + report_unused_terms(io) if terms report_conflicts(io) report_grammar(io) if grammar report_states(io, itemsets, lookaheads, solved, counterexamples, verbose) end + def report_unused_terms(io) + io << "Unused Terms\n\n" + + results = [] + terms = [] + used_symbols = [] + + terms = @states.symbols.select(&:term?) + + @states.states.select do |state| + state.shifts.map(&:next_sym) + end + + @states.states.each do |state| + state.reduces.select do |reduce| + used_symbols << reduce.look_ahead.flatten if !reduce.look_ahead.nil? + end + end + + @states.states.each do |state| + used_symbols << state.shifts.map(&:next_sym).select(&:term?).flatten + end + + used_symbols = used_symbols.flatten + + results = terms.select do |term| + !used_symbols.include?(term) + end + + results.each_with_index do |term, index| + io << sprintf("%5d %s\n", index, term.id.s_value) + end + + if !results.empty? + io << "\n\n" + end + end + def report_conflicts(io) has_conflict = false diff --git a/spec/lrama/option_parser_spec.rb b/spec/lrama/option_parser_spec.rb index ef629a72..7f2d40de 100644 --- a/spec/lrama/option_parser_spec.rb +++ b/spec/lrama/option_parser_spec.rb @@ -68,7 +68,7 @@ -h, --help display this help and exit Valid Reports: - states itemsets lookaheads solved counterexamples all verbose + terms states itemsets lookaheads solved counterexamples all verbose Valid Traces: none locations scan parse automaton bitsets closure grammar rules actions resource sets muscles tools m4-early m4 skeleton time ielr cex all @@ -91,7 +91,7 @@ it "returns option hash all flags enabled" do opts = option_parser.send(:validate_report, ["all"]) expect(opts).to eq({ - grammar: true, states: true, itemsets: true, + grammar: true, terms: true, states: true, itemsets: true, lookaheads: true, solved: true, counterexamples: true, }) end diff --git a/spec/lrama/states_spec.rb b/spec/lrama/states_spec.rb index 9dc2db71..6b924e69 100644 --- a/spec/lrama/states_spec.rb +++ b/spec/lrama/states_spec.rb @@ -15,9 +15,24 @@ states.compute io = StringIO.new - states.reporter.report(io, grammar: true, states: true, itemsets: true, lookaheads: true) + states.reporter.report(io, grammar: true, terms: true, states: true, itemsets: true, lookaheads: true) expect(io.string).to eq(<<~STR) + Unused Terms + + 0 YYerror + 1 YYUNDEF + 2 '\\\\' + 3 '\\13' + 4 keyword_class2 + 5 tNUMBER + 6 tPLUS + 7 tMINUS + 8 tEQ + 9 tEQEQ + 10 '>' + + State 1 conflicts: 2 shift/reduce, 1 reduce/reduce