[Fixes #137] Improve reporting

This commit is contained in:
Marc-Andre Lafortune 2020-08-13 21:50:16 -04:00 committed by Hiroshi SHIBATA
parent 3da3c2747f
commit 97d1a381e1
No known key found for this signature in database
GPG Key ID: F9CF13417264FAC2
4 changed files with 77 additions and 25 deletions

View File

@ -86,14 +86,15 @@ module Racc
end end
def n_useless_nonterminals def n_useless_nonterminals
@n_useless_nonterminals ||= @n_useless_nonterminals ||= each_useless_nonterminal.count
begin end
n = 0
@symboltable.each_nonterminal do |sym| def each_useless_nonterminal
n += 1 if sym.useless? return to_enum __method__ unless block_given?
end
n @symboltable.each_nonterminal do |sym|
end yield sym if sym.useless?
end
end end
def useless_rule_exist? def useless_rule_exist?
@ -101,14 +102,15 @@ module Racc
end end
def n_useless_rules def n_useless_rules
@n_useless_rules ||= @n_useless_rules ||= each_useless_rule.count
begin end
n = 0
each do |r| def each_useless_rule
n += 1 if r.useless? return to_enum __method__ unless block_given?
end
n each do |r|
end yield r if r.useless?
end
end end
def nfa def nfa

View File

@ -1,6 +1,6 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# #
# $Id$ #
# #
# Copyright (c) 1999-2006 Minero Aoki # Copyright (c) 1999-2006 Minero Aoki
# #
@ -184,8 +184,12 @@ def main
log_useless states.grammar log_useless states.grammar
log_conflict states log_conflict states
else else
report_useless states.grammar has_useless = report_useless states.grammar
report_conflict states has_conflicts = report_conflict states
if has_useless || has_conflicts
preamble = make_logfile ? 'C' : 'Turn on logging with "-v" and c'
$stderr.puts %Q{#{preamble}heck ".output" file for details}
end
end end
profiler.report profiler.report
@ -201,13 +205,29 @@ def make_filename(path, suffix)
path.sub(/(?:\..*?)?\z/, suffix) path.sub(/(?:\..*?)?\z/, suffix)
end 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) def report_conflict(states)
if states.should_report_srconflict? if states.should_report_srconflict?
reported = true
$stderr.puts "#{states.n_srconflicts} shift/reduce conflicts" $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
end end
if states.rrconflict_exist? if states.rrconflict_exist?
reported = true
$stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts" $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
end end
reported
end end
def log_conflict(states) def log_conflict(states)
@ -222,16 +242,17 @@ def log_conflict(states)
} }
end end
# @return [Boolean] if anything was reported
def report_useless(grammar) def report_useless(grammar)
if grammar.useless_nonterminal_exist? reported = report_list(grammar.each_useless_nonterminal, 'useless nonterminals', &:to_s)
$stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals"
end reported ||= report_list(grammar.each_useless_rule, 'useless rules') { |r| "##{r.ident} (#{r.target})" }
if grammar.useless_rule_exist?
$stderr.puts "#{grammar.n_useless_rules} useless rules"
end
if grammar.start.useless? if grammar.start.useless?
$stderr.puts 'fatal: start symbol does not derive any sentence' $stderr.puts 'fatal: start symbol does not derive any sentence'
reported = true
end end
reported
end end
def log_useless(grammar) def log_useless(grammar)

14
test/racc/assets/ifelse.y Normal file
View File

@ -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
;

View File

@ -318,5 +318,20 @@ module Racc
assert_debugfile 'tp_plus.y', [21, 0, 0, 0] assert_debugfile 'tp_plus.y', [21, 0, 0, 0]
assert_output_unchanged 'tp_plus.y' assert_output_unchanged 'tp_plus.y'
end end
def test_ifelse
stderr = nil
racc "-o#{@TAB_DIR}/ifelse", "#{ASSET_DIR}/ifelse.y", stdout_filter: ->(s) { stderr = s }
stderr = stderr.lines[1..-1].join if RUBY_PLATFORM.match? /java/
assert_equal(<<~STDERR, stderr)
1 useless nonterminals:
dummy
2 useless rules:
#4 (dummy)
#5 (dummy)
1 shift/reduce conflicts
Turn on logging with "-v" and check ".output" file for details
STDERR
end
end end
end end