summaryrefslogtreecommitdiff
path: root/lib/racc/logfilegenerator.rb
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2019-05-13 21:25:22 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2019-06-19 18:17:25 +0900
commit1a2546c2be839baa7d0a50dc056d4d6987d26852 (patch)
tree19fef5d8b8d96452a51ab68e8093ea895192ca27 /lib/racc/logfilegenerator.rb
parentcbe06cd3501fdadd0e6e63094da2973484d70b0b (diff)
Backport racc-1.4.15 from upstream.
Diffstat (limited to 'lib/racc/logfilegenerator.rb')
-rw-r--r--lib/racc/logfilegenerator.rb211
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/racc/logfilegenerator.rb b/lib/racc/logfilegenerator.rb
new file mode 100644
index 0000000000..b95b1afaa2
--- /dev/null
+++ b/lib/racc/logfilegenerator.rb
@@ -0,0 +1,211 @@
+#
+# $Id: a7e9663605afdda065d305b250a9805e3bd3fa70 $
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+# For details of the GNU LGPL, see the file "COPYING".
+#
+
+module Racc
+
+ class LogFileGenerator
+
+ def initialize(states, debug_flags = DebugFlags.new)
+ @states = states
+ @grammar = states.grammar
+ @debug_flags = debug_flags
+ end
+
+ def output(out)
+ output_conflict out; out.puts
+ output_useless out; out.puts
+ output_rule out; out.puts
+ output_token out; out.puts
+ output_state out
+ end
+
+ #
+ # Warnings
+ #
+
+ def output_conflict(out)
+ @states.each do |state|
+ if state.srconf
+ out.printf "state %d contains %d shift/reduce conflicts\n",
+ state.stateid, state.srconf.size
+ end
+ if state.rrconf
+ out.printf "state %d contains %d reduce/reduce conflicts\n",
+ state.stateid, state.rrconf.size
+ end
+ end
+ end
+
+ def output_useless(out)
+ @grammar.each do |rl|
+ if rl.useless?
+ out.printf "rule %d (%s) never reduced\n",
+ rl.ident, rl.target.to_s
+ end
+ end
+ @grammar.each_nonterminal do |t|
+ if t.useless?
+ out.printf "useless nonterminal %s\n", t.to_s
+ end
+ end
+ end
+
+ #
+ # States
+ #
+
+ def output_state(out)
+ out << "--------- State ---------\n"
+
+ showall = @debug_flags.la || @debug_flags.state
+ @states.each do |state|
+ out << "\nstate #{state.ident}\n\n"
+
+ (showall ? state.closure : state.core).each do |ptr|
+ pointer_out(out, ptr) if ptr.rule.ident != 0 or showall
+ end
+ out << "\n"
+
+ action_out out, state
+ end
+ end
+
+ def pointer_out(out, ptr)
+ buf = sprintf("%4d) %s :", ptr.rule.ident, ptr.rule.target.to_s)
+ ptr.rule.symbols.each_with_index do |tok, idx|
+ buf << ' _' if idx == ptr.index
+ buf << ' ' << tok.to_s
+ end
+ buf << ' _' if ptr.reduce?
+ out.puts buf
+ end
+
+ def action_out(f, state)
+ sr = state.srconf && state.srconf.dup
+ rr = state.rrconf && state.rrconf.dup
+ acts = state.action
+ keys = acts.keys
+ keys.sort! {|a,b| a.ident <=> b.ident }
+
+ [ Shift, Reduce, Error, Accept ].each do |klass|
+ keys.delete_if do |tok|
+ act = acts[tok]
+ if act.kind_of?(klass)
+ outact f, tok, act
+ if sr and c = sr.delete(tok)
+ outsrconf f, c
+ end
+ if rr and c = rr.delete(tok)
+ outrrconf f, c
+ end
+
+ true
+ else
+ false
+ end
+ end
+ end
+ sr.each {|tok, c| outsrconf f, c } if sr
+ rr.each {|tok, c| outrrconf f, c } if rr
+
+ act = state.defact
+ if not act.kind_of?(Error) or @debug_flags.any?
+ outact f, '$default', act
+ end
+
+ f.puts
+ state.goto_table.each do |t, st|
+ if t.nonterminal?
+ f.printf " %-12s go to state %d\n", t.to_s, st.ident
+ end
+ end
+ end
+
+ def outact(f, t, act)
+ case act
+ when Shift
+ f.printf " %-12s shift, and go to state %d\n",
+ t.to_s, act.goto_id
+ when Reduce
+ f.printf " %-12s reduce using rule %d (%s)\n",
+ t.to_s, act.ruleid, act.rule.target.to_s
+ when Accept
+ f.printf " %-12s accept\n", t.to_s
+ when Error
+ f.printf " %-12s error\n", t.to_s
+ else
+ raise "racc: fatal: wrong act for outact: act=#{act}(#{act.class})"
+ end
+ end
+
+ def outsrconf(f, confs)
+ confs.each do |c|
+ r = c.reduce
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.shift.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ def outrrconf(f, confs)
+ confs.each do |c|
+ r = c.low_prec
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.token.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ #
+ # Rules
+ #
+
+ def output_rule(out)
+ out.print "-------- Grammar --------\n\n"
+ @grammar.each do |rl|
+ if @debug_flags.any? or rl.ident != 0
+ out.printf "rule %d %s: %s\n",
+ rl.ident, rl.target.to_s, rl.symbols.join(' ')
+ end
+ end
+ end
+
+ #
+ # Tokens
+ #
+
+ def output_token(out)
+ out.print "------- Symbols -------\n\n"
+
+ out.print "**Nonterminals, with rules where they appear\n\n"
+ @grammar.each_nonterminal do |t|
+ tmp = <<SRC
+ %s (%d)
+ on right: %s
+ on left : %s
+SRC
+ out.printf tmp, t.to_s, t.ident,
+ symbol_locations(t.locate).join(' '),
+ symbol_locations(t.heads).join(' ')
+ end
+
+ out.print "\n**Terminals, with rules where they appear\n\n"
+ @grammar.each_terminal do |t|
+ out.printf " %s (%d) %s\n",
+ t.to_s, t.ident, symbol_locations(t.locate).join(' ')
+ end
+ end
+
+ def symbol_locations(locs)
+ locs.map {|loc| loc.rule.ident }.reject {|n| n == 0 }.uniq
+ end
+
+ end
+
+end # module Racc