summaryrefslogtreecommitdiff
path: root/algorithms/shift_reduce_parser.rb
blob: 948d8c1077ed42d6468d0b51887c2369b3aa1ac4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env ruby


class Item
  attr_accessor :word, :type, :link
  def initialize word, type
    @word = word
    @type = type
    @link = nil
  end
end

class MockShiftReduceParser
  attr_accessor :state

  def initialize
    @state = nil
    
    @a = {}
    @a[nil] = {}
    @a[nil][nil] = 'S'
    @a[nil]['f'] = 'S'
    @a[nil]['l'] = 'S'
    @a[nil]['r'] = 'illegal'

    @a['f'] = {}
    @a['f']['f'] = 'S' # FIXME conflict
    @a['f']['l'] = 'S'
    @a['f']['r'] = 'R'

    @a['l'] = {}
    @a['l']['f'] = 'L'
    @a['l']['l'] = 'S'
    @a['l']['r'] = 'illegal'

    @a['r'] = {}
    @a['r']['f'] = 'illegal'
    @a['r']['l'] = 'illegal'
    @a['r']['r'] = 'illegal'
  end

  def advance type
    if    !@state 
      @state = type
      puts "-/- -> S -> #{@state}"
      return
    end
    action = @a[@state][type]
    prev_state = @state
    if action == 'S'
      @state = type
    elsif action == 'L' or action == 'R'
      @state = 'f'
    end
    puts "#{prev_state}/#{type} -> #{action} -> #{@state}"

    return action
  end
end


parser = MockShiftReduceParser.new

items = []
head = nil
stack = []

while line = STDIN.gets
  word, type = line.split
  item = Item.new word, type
  items << item
  stack << item

  head = item if !head

  action = parser.advance item.type
  if action == "S"
    head = item
  elsif action == "R"
    _ = stack.pop
    _.link = head
  elsif action == "L"
    head = item
    puts stack.size
    del = []
    stack.each_with_index { |i,j|
      if i.type == 'l'
        i.link = head
        del << j
      end
    }
    del.reverse.each { |d| stack.delete_at(d) }
    puts stack.size
  end
end

stack.each { |i| i.link = head }

puts "---"
items.each { |j| if j.link then puts "#{j.word} #{j.link.word}" else puts "#{j.word} ?" end }