Skip to content

Commit

Permalink
[Fixes ruby#137] Improve reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
marcandre committed Aug 14, 2020
1 parent 5c49077 commit 1525bba
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 31 deletions.
47 changes: 34 additions & 13 deletions bin/racc
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ def main
generator.generate_parser_file(output || make_filename(input, '.tab.rb'))
}

if debug_flags.status_logging
log_useless states.grammar
log_conflict states
else
has_useless = report_useless states.grammar
has_conflicts = report_conflict states
if has_useless || has_conflicts
make_logfile ||= true
$stderr.puts 'Check ".output" log file for details'
end
end
if make_logfile
profiler.section('logging') {
$stderr.puts 'Creating log file...' if verbose
Expand All @@ -180,13 +191,6 @@ def main
}
}
end
if debug_flags.status_logging
log_useless states.grammar
log_conflict states
else
report_useless states.grammar
report_conflict states
end

profiler.report
rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err
Expand All @@ -201,13 +205,29 @@ def make_filename(path, suffix)
path.sub(/(?:\..*?)?\z/, suffix)
end

LIST_LIMIT = 10
def report_list(enum, label)
c = enum.count
if c > 0
$stderr.puts "#{c} #{label}:"
enum.first(LIST_LIMIT).each do |item|
$stderr.puts " #{yield item}"
end
$stderr.puts " ..." if c > LIST_LIMIT
end
end

# @return [Boolean] if anything was reported
def report_conflict(states)
if states.should_report_srconflict?
reported = true
$stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
end
if states.rrconflict_exist?
reported = true
$stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
end
reported
end

def log_conflict(states)
Expand All @@ -222,16 +242,17 @@ def log_conflict(states)
}
end

# @return [Boolean] if anything was reported
def report_useless(grammar)
if grammar.useless_nonterminal_exist?
$stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals"
end
if grammar.useless_rule_exist?
$stderr.puts "#{grammar.n_useless_rules} useless rules"
end
reported = report_list(grammar.each_useless_nonterminal, 'useless nonterminals', &:to_s)

reported ||= report_list(grammar.each_useless_rule, 'useless rules') { |r| "##{r.ident} (#{r.target})" }

if grammar.start.useless?
$stderr.puts 'fatal: start symbol does not derive any sentence'
return true
end
reported
end

def log_useless(grammar)
Expand Down
38 changes: 20 additions & 18 deletions lib/racc/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,33 +82,35 @@ def nonterminal_base
end

def useless_nonterminal_exist?
n_useless_nonterminals() != 0
each_useless_nonterminal.any?
end

def n_useless_nonterminals
@n_useless_nonterminals ||=
begin
n = 0
@symboltable.each_nonterminal do |sym|
n += 1 if sym.useless?
end
n
end
@n_useless_nonterminals ||= each_useless_nonterminal.count
end

def each_useless_nonterminal
return to_enum __method__ unless block_given?

@symboltable.each_nonterminal do |sym|
yield sym if sym.useless?
end
end

def useless_rule_exist?
n_useless_rules() != 0
each_useless_rule.any?
end

def n_useless_rules
@n_useless_rules ||=
begin
n = 0
each do |r|
n += 1 if r.useless?
end
n
end
@n_useless_rules ||= each_useless_rule.count
end

def each_useless_rule
return to_enum __method__ unless block_given?

each do |r|
yield r if r.useless?
end
end

def nfa
Expand Down
14 changes: 14 additions & 0 deletions test/assets/ifelse.y
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class C::Parser
token tSOMETHING
rule
statement
: tSOMETHING
| 'if' statement 'then' statement
| 'if' statement 'then' statement 'else' statement
;

dummy
: tSOMETHING '+' tSOMETHING
| tSOMETHING '-' tSOMETHING
;

14 changes: 14 additions & 0 deletions test/test_racc_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,5 +318,19 @@ def test_tp_plus
assert_debugfile 'tp_plus.y', [21, 0, 0, 0]
assert_output_unchanged 'tp_plus.y'
end

def test_ifelse
stderr = nil
racc "-o#{@TAB_DIR}/ifelse", "#{ASSET_DIR}/ifelse.y", stdout_filter: ->(s) { stderr = s }
assert_equal(<<~STDERR, stderr)
1 useless nonterminals:
dummy
2 useless rules:
#4 (dummy)
#5 (dummy)
1 shift/reduce conflicts
Check ".output" log file for details
STDERR
end
end
end

0 comments on commit 1525bba

Please sign in to comment.