[Fixes #137] Improve reporting
This commit is contained in:
parent
3da3c2747f
commit
97d1a381e1
@ -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
|
||||||
|
39
libexec/racc
39
libexec/racc
@ -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
14
test/racc/assets/ifelse.y
Normal 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
|
||||||
|
;
|
||||||
|
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user