# 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 lib/racc/state.rb, line 25
    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 lib/racc/state.rb, line 51
    def [](i)
      @states[i]
    end

dfa() click to toggle source

DFA (Deterministic Finite Automaton) Generation

    # File lib/racc/state.rb, line 196
    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 lib/racc/state.rb, line 61
    def each_index(&block)
      @states.each_index(&block)
    end

each_state(&block) click to toggle source

    # File lib/racc/state.rb, line 55
    def each_state(&block)
      @states.each(&block)
    end

Also aliased as: each
inspect() click to toggle source

    # File lib/racc/state.rb, line 45
    def inspect
      '#<state table>'
    end

Also aliased as: to_s
n_rrconflicts() click to toggle source

    # File lib/racc/state.rb, line 88
    def n_rrconflicts
      @n_rrconflicts ||= inject(0) {|sum, st| sum + st.n_rrconflicts }
    end

n_srconflicts() click to toggle source

    # File lib/racc/state.rb, line 80
    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 lib/racc/state.rb, line 102
    def nfa
      return self if @nfa_computed
      compute_nfa
      @nfa_computed = true
      self
    end

rrconflict_exist?() click to toggle source

    # File lib/racc/state.rb, line 84
    def rrconflict_exist?
      n_rrconflicts() != 0
    end

should_report_srconflict?() click to toggle source

    # File lib/racc/state.rb, line 71
    def should_report_srconflict?
      srconflict_exist? and
          (n_srconflicts() != @grammar.n_expected_srconflicts)
    end

size() click to toggle source

    # File lib/racc/state.rb, line 41
    def size
      @states.size
    end

srconflict_exist?() click to toggle source

    # File lib/racc/state.rb, line 76
    def srconflict_exist?
      n_srconflicts() != 0
    end

state_transition_table() click to toggle source

    # File lib/racc/state.rb, line 92
    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 lib/racc/state.rb, line 317
    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 lib/racc/state.rb, line 154
    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 lib/racc/state.rb, line 586
    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 lib/racc/state.rb, line 206
    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 lib/racc/state.rb, line 111
    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 lib/racc/state.rb, line 161
    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 lib/racc/state.rb, line 313
    def create_tmap(size)
      Array.new(size, 0)   # use Integer as bitmap
    end

digraph(map, relation) click to toggle source

    # File lib/racc/state.rb, line 348
    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 lib/racc/state.rb, line 523
    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 lib/racc/state.rb, line 422
    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 lib/racc/state.rb, line 186
    def fingerprint(arr)
      arr.map {|i| i.ident }.pack('L*')
    end

generate_states(state) click to toggle source

    # File lib/racc/state.rb, line 125
    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 lib/racc/state.rb, line 219
    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 lib/racc/state.rb, line 564
    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

    # File lib/racc/state.rb, line 390
    def print_atab(idx, tab)
      tab.each_with_index do |i,ii|
        printf '%-20s', idx[ii].inspect
        p i
      end
    end

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

    # File lib/racc/state.rb, line 397
    def print_tab(idx, rel, tab)
      tab.each_with_index do |bin,i|
        print i, ' ', idx[i].inspect, ' << '; p rel[i]
        print '  '
        each_t(@symboltable, bin) {|t| print ' ', t }
        puts
      end
    end

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

for debug

    # File lib/racc/state.rb, line 407
    def print_tab_i(idx, rel, tab, i)
      bin = tab[i]
      print i, ' ', idx[i].inspect, ' << '; p rel[i]
      print '  '
      each_t(@symboltable, bin) {|t| print ' ', t }
    end

printb(i) click to toggle source

for debug

    # File lib/racc/state.rb, line 415
    def printb(i)
      each_t(@symboltable, i) do |t|
        print t, ' '
      end
      puts
    end

record_path(begst, rule) click to toggle source

    # File lib/racc/state.rb, line 325
    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 lib/racc/state.rb, line 436
    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 lib/racc/state.rb, line 453
    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 lib/racc/state.rb, line 472
    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 lib/racc/state.rb, line 553
    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 lib/racc/state.rb, line 336
    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 lib/racc/state.rb, line 361
    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