class Racc::States

A table of LALR states.

Constants

ASSOC

Attributes

actions[R]
grammar[R]

Public Class Methods

new(grammar, debug_flags = DebugFlags.new) click to toggle source
# File racc/state.rb, line 22
def initialize(grammar, debug_flags = DebugFlags.new)
  @grammar = grammar
  @symboltable = grammar.symboltable
  @d_state = debug_flags.state
  @d_la    = debug_flags.la
  @d_prec  = debug_flags.prec
  @states = []
  @statecache = {}
  @actions = ActionTable.new(@grammar, self)
  @nfa_computed = false
  @dfa_computed = false
end

Public Instance Methods

[](i) click to toggle source
# File racc/state.rb, line 48
def [](i)
  @states[i]
end
dfa() click to toggle source

DFA (Deterministic Finite Automaton) Generation

# File racc/state.rb, line 193
def dfa
  return self if @dfa_computed
  nfa
  compute_dfa
  @dfa_computed = true
  self
end
each(&block)
Alias for: each_state
each_index(&block) click to toggle source
# File racc/state.rb, line 58
def each_index(&block)
  @states.each_index(&block)
end
each_state(&block) click to toggle source
# File racc/state.rb, line 52
def each_state(&block)
  @states.each(&block)
end
Also aliased as: each
inspect() click to toggle source
# File racc/state.rb, line 42
def inspect
  '#<state table>'
end
Also aliased as: to_s
n_rrconflicts() click to toggle source
# File racc/state.rb, line 85
def n_rrconflicts
  @n_rrconflicts ||= inject(0) {|sum, st| sum + st.n_rrconflicts }
end
n_srconflicts() click to toggle source
# File racc/state.rb, line 77
def n_srconflicts
  @n_srconflicts ||= inject(0) {|sum, st| sum + st.n_srconflicts }
end
nfa() click to toggle source

NFA (Non-deterministic Finite Automaton) Computation

# File racc/state.rb, line 99
def nfa
  return self if @nfa_computed
  compute_nfa
  @nfa_computed = true
  self
end
rrconflict_exist?() click to toggle source
# File racc/state.rb, line 81
def rrconflict_exist?
  n_rrconflicts() != 0
end
should_report_srconflict?() click to toggle source
# File racc/state.rb, line 68
def should_report_srconflict?
  srconflict_exist? and
      (n_srconflicts() != @grammar.n_expected_srconflicts)
end
size() click to toggle source
# File racc/state.rb, line 38
def size
  @states.size
end
srconflict_exist?() click to toggle source
# File racc/state.rb, line 73
def srconflict_exist?
  n_srconflicts() != 0
end
state_transition_table() click to toggle source
# File racc/state.rb, line 89
def state_transition_table
  @state_transition_table ||= StateTransitionTable.generate(self.dfa)
end
to_s()
Alias for: inspect

Private Instance Methods

addrel(tbl, i, item) click to toggle source
# File racc/state.rb, line 314
def addrel(tbl, i, item)
  if a = tbl[i]
    a.push item
  else
    tbl[i] = [item]
  end
end
addsym(table, sym, ptr) click to toggle source
# File racc/state.rb, line 151
def addsym(table, sym, ptr)
  unless s = table[sym]
    table[sym] = s = ISet.new
  end
  s.add ptr
end
check_useless() click to toggle source
# File racc/state.rb, line 583
def check_useless
  used = []
  @actions.each_reduce do |act|
    if not act or act.refn == 0
      act.rule.useless = true
    else
      t = act.rule.target
      used[t.ident] = t
    end
  end
  @symboltable.nt_base.upto(@symboltable.nt_max - 1) do |n|
    unless used[n]
      @symboltable[n].useless = true
    end
  end
end
compute_dfa() click to toggle source
# File racc/state.rb, line 203
def compute_dfa
  la = lookahead()
  @states.each do |state|
    state.la = la
    resolve state
  end
  set_accept
  @states.each do |state|
    pack state
  end
  check_useless
end
compute_nfa() click to toggle source
# File racc/state.rb, line 108
def compute_nfa
  @grammar.init
  # add state 0
  core_to_state  [ @grammar[0].ptrs[0] ]
  # generate LALR states
  cur = 0
  @gotos = []
  while cur < @states.size
    generate_states @states[cur]   # state is added here
    cur += 1
  end
  @actions.init
end
core_to_state(core) click to toggle source
# File racc/state.rb, line 158
def core_to_state(core)
  #
  # convert CORE to a State object.
  # If matching state does not exist, create it and add to the table.
  #

  k = fingerprint(core)
  unless dest = @statecache[k]
    # not registered yet
    dest = State.new(@states.size, core)
    @states.push dest

    @statecache[k] = dest

    puts "core_to_state: create state   ID #{dest.ident}" if @d_state
  else
    if @d_state
      puts "core_to_state: dest is cached ID #{dest.ident}"
      puts "core_to_state: dest core #{dest.core.join(' ')}"
    end
  end

  dest
end
create_tmap(size) click to toggle source
# File racc/state.rb, line 310
def create_tmap(size)
  Array.new(size, 0)   # use Integer as bitmap
end
digraph(map, relation) click to toggle source
# File racc/state.rb, line 345
def digraph(map, relation)
  n = relation.size
  index    = Array.new(n, nil)
  vertices = []
  @infinity = n + 2

  index.each_index do |i|
    if not index[i] and relation[i]
      traverse i, index, vertices, map, relation
    end
  end
end
do_resolve_sr(stok, rtok) click to toggle source
# File racc/state.rb, line 520
def do_resolve_sr(stok, rtok)
  puts "resolve_sr: s/r conflict: rtok=#{rtok}, stok=#{stok}" if @d_prec

  unless rtok and rtok.precedence
    puts "resolve_sr: no prec for #{rtok}(R)" if @d_prec
    return :CantResolve
  end
  rprec = rtok.precedence

  unless stok and stok.precedence
    puts "resolve_sr: no prec for #{stok}(S)" if @d_prec
    return :CantResolve
  end
  sprec = stok.precedence

  ret = if rprec == sprec
          ASSOC[rtok.assoc] or
              raise "racc: fatal: #{rtok}.assoc is not Left/Right/Nonassoc"
        else
          (rprec > sprec) ? (:Reduce) : (:Shift)
        end

  puts "resolve_sr: resolved as #{ret.id2name}" if @d_prec
  ret
end
each_t(tbl, set) { |tbl| ... } click to toggle source
# File racc/state.rb, line 419
def each_t(tbl, set)
  0.upto( set.size ) do |i|
    (0..7).each do |ii|
      if set[idx = i * 8 + ii] == 1
        yield tbl[idx]
      end
    end
  end
end
fingerprint(arr) click to toggle source
# File racc/state.rb, line 183
def fingerprint(arr)
  arr.map {|i| i.ident }.pack('L*')
end
generate_states(state) click to toggle source
# File racc/state.rb, line 122
def generate_states(state)
  puts "dstate: #{state}" if @d_state

  table = {}
  state.closure.each do |ptr|
    if sym = ptr.dereference
      addsym table, sym, ptr.next
    end
  end
  table.each do |sym, core|
    puts "dstate: sym=#{sym} ncore=#{core}" if @d_state

    dest = core_to_state(core.to_a)
    state.goto_table[sym] = dest
    id = sym.nonterminal?() ? @gotos.size : nil
    g = Goto.new(id, sym, state, dest)
    @gotos.push g if sym.nonterminal?
    state.gotos[sym] = g
    puts "dstate: #{state.ident} --#{sym}--> #{dest.ident}" if @d_state

    # check infinite recursion
    if state.ident == dest.ident and state.closure.size == 1
      raise CompileError,
          sprintf("Infinite recursion: state %d, with rule %d",
                  state.ident, state.ptrs[0].rule.ident)
    end
  end
end
lookahead() click to toggle source
# File racc/state.rb, line 216
def lookahead
  #
  # lookahead algorithm ver.3 -- from bison 1.26
  #

  gotos = @gotos
  if @d_la
    puts "\n--- goto ---"
    gotos.each_with_index {|g, i| print i, ' '; p g }
  end

  ### initialize_LA()
  ### set_goto_map()
  la_rules = []
  @states.each do |state|
    state.check_la la_rules
  end

  ### initialize_F()
  f     = create_tmap(gotos.size)
  reads = []
  edge  = []
  gotos.each do |goto|
    goto.to_state.goto_table.each do |t, st|
      if t.terminal?
        f[goto.ident] |= (1 << t.ident)
      elsif t.nullable?
        edge.push goto.to_state.gotos[t].ident
      end
    end
    if edge.empty?
      reads.push nil
    else
      reads.push edge
      edge = []
    end
  end
  digraph f, reads
  if @d_la
    puts "\n--- F1 (reads) ---"
    print_tab gotos, reads, f
  end

  ### build_relations()
  ### compute_FOLLOWS
  path = nil
  edge = []
  lookback = Array.new(la_rules.size, nil)
  includes = []
  gotos.each do |goto|
    goto.symbol.heads.each do |ptr|
      path = record_path(goto.from_state, ptr.rule)
      lastgoto = path.last
      st = lastgoto ? lastgoto.to_state : goto.from_state
      if st.conflict?
        addrel lookback, st.rruleid(ptr.rule), goto
      end
      path.reverse_each do |g|
        break if     g.symbol.terminal?
        edge.push    g.ident
        break unless g.symbol.nullable?
      end
    end
    if edge.empty?
      includes.push nil
    else
      includes.push edge
      edge = []
    end
  end
  includes = transpose(includes)
  digraph f, includes
  if @d_la
    puts "\n--- F2 (includes) ---"
    print_tab gotos, includes, f
  end

  ### compute_lookaheads
  la = create_tmap(la_rules.size)
  lookback.each_with_index do |arr, i|
    if arr
      arr.each do |g|
        la[i] |= f[g.ident]
      end
    end
  end
  if @d_la
    puts "\n--- LA (lookback) ---"
    print_tab la_rules, lookback, la
  end

  la
end
pack(state) click to toggle source
# File racc/state.rb, line 561
def pack(state)
  ### find most frequently used reduce rule
  act = state.action
  arr = Array.new(@grammar.size, 0)
  act.each do |t, a|
    arr[a.ruleid] += 1  if a.kind_of?(Reduce)
  end
  i = arr.max
  s = (i > 0) ? arr.index(i) : nil

  ### set & delete default action
  if s
    r = @actions.reduce(s)
    if not state.defact or state.defact == r
      act.delete_if {|t, a| a == r }
      state.defact = r
    end
  else
    state.defact ||= @actions.error
  end
end
print_atab(idx, tab) click to toggle source

for debug

print_tab(idx, rel, tab) click to toggle source
print_tab_i(idx, rel, tab, i) click to toggle source

for debug

printb(i) click to toggle source

for debug

# File racc/state.rb, line 412
def printb(i)
  each_t(@symboltable, i) do |t|
    print t, ' '
  end
  puts
end
record_path(begst, rule) click to toggle source
# File racc/state.rb, line 322
def record_path(begst, rule)
  st = begst
  path = []
  rule.symbols.each do |t|
    goto = st.gotos[t]
    path.push goto
    st = goto.to_state
  end
  path
end
resolve(state) click to toggle source

resolve

# File racc/state.rb, line 433
def resolve(state)
  if state.conflict?
    resolve_rr state, state.ritems
    resolve_sr state, state.stokens
  else
    if state.rrules.empty?
      # shift
      state.stokens.each do |t|
        state.action[t] = @actions.shift(state.goto_table[t])
      end
    else
      # reduce
      state.defact = @actions.reduce(state.rrules[0])
    end
  end
end
resolve_rr(state, r) click to toggle source
# File racc/state.rb, line 450
def resolve_rr(state, r)
  r.each do |item|
    item.each_la(@symboltable) do |t|
      act = state.action[t]
      if act
        unless act.kind_of?(Reduce)
          raise "racc: fatal: #{act.class} in action table"
        end
        # Cannot resolve R/R conflict (on t).
        # Reduce with upper rule as default.
        state.rr_conflict act.rule, item.rule, t
      else
        # No conflict.
        state.action[t] = @actions.reduce(item.rule)
      end
    end
  end
end
resolve_sr(state, s) click to toggle source
# File racc/state.rb, line 469
def resolve_sr(state, s)
  s.each do |stok|
    goto = state.goto_table[stok]
    act = state.action[stok]

    unless act
      # no conflict
      state.action[stok] = @actions.shift(goto)
    else
      unless act.kind_of?(Reduce)
        puts 'DEBUG -------------------------------'
        p stok
        p act
        state.action.each do |k,v|
          print k.inspect, ' ', v.inspect, "\n"
        end
        raise "racc: fatal: #{act.class} in action table"
      end

      # conflict on stok

      rtok = act.rule.precedence
      case do_resolve_sr(stok, rtok)
      when :Reduce
        # action is already set

      when :Shift
        # overwrite
        act.decref
        state.action[stok] = @actions.shift(goto)

      when :Error
        act.decref
        state.action[stok] = @actions.error

      when :CantResolve
        # shift as default
        act.decref
        state.action[stok] = @actions.shift(goto)
        state.sr_conflict stok, act.rule
      end
    end
  end
end
set_accept() click to toggle source

complete

# File racc/state.rb, line 550
def set_accept
  anch = @symboltable.anchor
  init_state = @states[0].goto_table[@grammar.start]
  targ_state = init_state.action[anch].goto_state
  acc_state  = targ_state.action[anch].goto_state

  acc_state.action.clear
  acc_state.goto_table.clear
  acc_state.defact = @actions.accept
end
transpose(rel) click to toggle source
# File racc/state.rb, line 333
def transpose(rel)
  new = Array.new(rel.size, nil)
  rel.each_with_index do |arr, idx|
    if arr
      arr.each do |i|
        addrel new, i, idx
      end
    end
  end
  new
end
traverse(i, index, vertices, map, relation) click to toggle source
# File racc/state.rb, line 358
def traverse(i, index, vertices, map, relation)
  vertices.push i
  index[i] = height = vertices.size

  if rp = relation[i]
    rp.each do |proci|
      unless index[proci]
        traverse proci, index, vertices, map, relation
      end
      if index[i] > index[proci]
        # circulative recursion !!!
        index[i] = index[proci]
      end
      map[i] |= map[proci]
    end
  end

  if index[i] == height
    while true
      proci = vertices.pop
      index[proci] = @infinity
      break if i == proci

      map[proci] |= map[i]
    end
  end
end