lrama 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,184 @@
1
+ require "lrama/state/reduce"
2
+ require "lrama/state/shift"
3
+
4
+ module Lrama
5
+ class State
6
+ # * symbol: A symbol under discussion
7
+ # * reduce: A reduce under discussion
8
+ # * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative)
9
+ ResolvedConflict = Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) do
10
+ def report_message
11
+ s = symbol.display_name
12
+ r = reduce.rule.precedence_sym.display_name
13
+ case
14
+ when which == :shift && same_prec
15
+ msg = "resolved as #{which} (%right #{s})"
16
+ when which == :shift
17
+ msg = "resolved as #{which} (#{r} < #{s})"
18
+ when which == :reduce && same_prec
19
+ msg = "resolved as #{which} (%left #{s})"
20
+ when which == :reduce
21
+ msg = "resolved as #{which} (#{s} < #{r})"
22
+ when which == :error
23
+ msg = "resolved as an #{which} (%nonassoc #{s})"
24
+ else
25
+ raise "Unknown direction. #{self}"
26
+ end
27
+
28
+ "Conflict between rule #{reduce.rule.id} and token #{s} #{msg}."
29
+ end
30
+ end
31
+
32
+ Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
33
+
34
+ attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
35
+ :default_reduction_rule, :closure, :items
36
+ attr_accessor :shifts, :reduces
37
+
38
+ def initialize(id, accessing_symbol, kernels)
39
+ @id = id
40
+ @accessing_symbol = accessing_symbol
41
+ @kernels = kernels.freeze
42
+ @items = @kernels
43
+ # Manage relationships between items to state
44
+ # to resolve next state
45
+ @items_to_state = {}
46
+ @conflicts = []
47
+ @resolved_conflicts = []
48
+ @default_reduction_rule = nil
49
+ end
50
+
51
+ def closure=(closure)
52
+ @closure = closure
53
+ @items = @kernels + @closure
54
+ end
55
+
56
+ def non_default_reduces
57
+ reduces.select do |reduce|
58
+ reduce.rule != @default_reduction_rule
59
+ end
60
+ end
61
+
62
+ def compute_shifts_reduces
63
+ _shifts = {}
64
+ reduces = []
65
+ items.each do |item|
66
+ # TODO: Consider what should be pushed
67
+ if item.end_of_rule?
68
+ reduces << Reduce.new(item)
69
+ else
70
+ key = item.next_sym
71
+ _shifts[key] ||= []
72
+ _shifts[key] << item.new_by_next_position
73
+ end
74
+ end
75
+
76
+ # It seems Bison 3.8.2 iterates transitions order by symbol number
77
+ shifts = _shifts.sort_by do |next_sym, new_items|
78
+ next_sym.number
79
+ end.map do |next_sym, new_items|
80
+ Shift.new(next_sym, new_items.flatten)
81
+ end
82
+ self.shifts = shifts.freeze
83
+ self.reduces = reduces.freeze
84
+ end
85
+
86
+ def set_items_to_state(items, next_state)
87
+ @items_to_state[items] = next_state
88
+ end
89
+
90
+ #
91
+ def set_look_ahead(rule, look_ahead)
92
+ reduce = reduces.find do |r|
93
+ r.rule == rule
94
+ end
95
+
96
+ reduce.look_ahead = look_ahead
97
+ end
98
+
99
+ # Returns array of [nterm, next_state]
100
+ def nterm_transitions
101
+ return @nterm_transitions if @nterm_transitions
102
+
103
+ @nterm_transitions = []
104
+
105
+ shifts.each do |shift|
106
+ next if shift.next_sym.term?
107
+
108
+ @nterm_transitions << [shift, @items_to_state[shift.next_items]]
109
+ end
110
+
111
+ @nterm_transitions
112
+ end
113
+
114
+ # Returns array of [term, next_state]
115
+ def term_transitions
116
+ return @term_transitions if @term_transitions
117
+
118
+ @term_transitions = []
119
+
120
+ shifts.each do |shift|
121
+ next if shift.next_sym.nterm?
122
+
123
+ @term_transitions << [shift, @items_to_state[shift.next_items]]
124
+ end
125
+
126
+ @term_transitions
127
+ end
128
+
129
+ def selected_term_transitions
130
+ term_transitions.select do |shift, next_state|
131
+ !shift.not_selected
132
+ end
133
+ end
134
+
135
+ # Move to next state by sym
136
+ def transition(sym)
137
+ result = nil
138
+
139
+ if sym.term?
140
+ term_transitions.each do |shift, next_state|
141
+ term = shift.next_sym
142
+ result = next_state if term == sym
143
+ end
144
+ else
145
+ nterm_transitions.each do |shift, next_state|
146
+ nterm = shift.next_sym
147
+ result = next_state if nterm == sym
148
+ end
149
+ end
150
+
151
+ raise "Can not transit by #{sym} #{self}" if result.nil?
152
+
153
+ result
154
+ end
155
+
156
+ def find_reduce_by_item!(item)
157
+ reduces.find do |r|
158
+ r.item == item
159
+ end || (raise "reduce is not found. #{item}")
160
+ end
161
+
162
+ def default_reduction_rule=(default_reduction_rule)
163
+ @default_reduction_rule = default_reduction_rule
164
+
165
+ reduces.each do |r|
166
+ if r.rule == default_reduction_rule
167
+ r.default_reduction = true
168
+ end
169
+ end
170
+ end
171
+
172
+ def sr_conflicts
173
+ @conflicts.select do |conflict|
174
+ conflict.type == :shift_reduce
175
+ end
176
+ end
177
+
178
+ def rr_conflicts
179
+ @conflicts.select do |conflict|
180
+ conflict.type == :reduce_reduce
181
+ end
182
+ end
183
+ end
184
+ end
data/lib/lrama/states.rb CHANGED
@@ -2,228 +2,6 @@ require "forwardable"
2
2
  require "lrama/report"
3
3
 
4
4
  module Lrama
5
- class State
6
- class Reduce
7
- # https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html
8
- attr_reader :item, :look_ahead, :not_selected_symbols
9
- attr_accessor :default_reduction
10
-
11
- def initialize(item)
12
- @item = item
13
- @look_ahead = nil
14
- @not_selected_symbols = []
15
- end
16
-
17
- def rule
18
- @item.rule
19
- end
20
-
21
- def look_ahead=(look_ahead)
22
- @look_ahead = look_ahead.freeze
23
- end
24
-
25
- def add_not_selected_symbol(sym)
26
- @not_selected_symbols << sym
27
- end
28
-
29
- def selected_look_ahead
30
- if @look_ahead
31
- @look_ahead - @not_selected_symbols
32
- else
33
- []
34
- end
35
- end
36
- end
37
-
38
- class Shift
39
- attr_reader :next_sym, :next_items
40
- attr_accessor :not_selected
41
-
42
- def initialize(next_sym, next_items)
43
- @next_sym = next_sym
44
- @next_items = next_items
45
- end
46
- end
47
-
48
- # * symbol: A symbol under discussion
49
- # * reduce: A reduce under discussion
50
- # * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative)
51
- ResolvedConflict = Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) do
52
- def report_message
53
- s = symbol.display_name
54
- r = reduce.rule.precedence_sym.display_name
55
- case
56
- when which == :shift && same_prec
57
- msg = "resolved as #{which} (%right #{s})"
58
- when which == :shift
59
- msg = "resolved as #{which} (#{r} < #{s})"
60
- when which == :reduce && same_prec
61
- msg = "resolved as #{which} (%left #{s})"
62
- when which == :reduce
63
- msg = "resolved as #{which} (#{s} < #{r})"
64
- when which == :error
65
- msg = "resolved as an #{which} (%nonassoc #{s})"
66
- else
67
- raise "Unknown direction. #{self}"
68
- end
69
-
70
- "Conflict between rule #{reduce.rule.id} and token #{s} #{msg}."
71
- end
72
- end
73
-
74
- Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
75
-
76
- attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
77
- :default_reduction_rule, :closure, :items
78
- attr_accessor :shifts, :reduces
79
-
80
- def initialize(id, accessing_symbol, kernels)
81
- @id = id
82
- @accessing_symbol = accessing_symbol
83
- @kernels = kernels.freeze
84
- @items = @kernels
85
- # Manage relationships between items to state
86
- # to resolve next state
87
- @items_to_state = {}
88
- @conflicts = []
89
- @resolved_conflicts = []
90
- @default_reduction_rule = nil
91
- end
92
-
93
- def closure=(closure)
94
- @closure = closure
95
- @items = @kernels + @closure
96
- end
97
-
98
- def non_default_reduces
99
- reduces.select do |reduce|
100
- reduce.rule != @default_reduction_rule
101
- end
102
- end
103
-
104
- def compute_shifts_reduces
105
- _shifts = {}
106
- reduces = []
107
- items.each do |item|
108
- # TODO: Consider what should be pushed
109
- if item.end_of_rule?
110
- reduces << Reduce.new(item)
111
- else
112
- key = item.next_sym
113
- _shifts[key] ||= []
114
- _shifts[key] << item.new_by_next_position
115
- end
116
- end
117
-
118
- # It seems Bison 3.8.2 iterates transitions order by symbol number
119
- shifts = _shifts.sort_by do |next_sym, new_items|
120
- next_sym.number
121
- end.map do |next_sym, new_items|
122
- Shift.new(next_sym, new_items.flatten)
123
- end
124
- self.shifts = shifts.freeze
125
- self.reduces = reduces.freeze
126
- end
127
-
128
- def set_items_to_state(items, next_state)
129
- @items_to_state[items] = next_state
130
- end
131
-
132
- #
133
- def set_look_ahead(rule, look_ahead)
134
- reduce = reduces.find do |r|
135
- r.rule == rule
136
- end
137
-
138
- reduce.look_ahead = look_ahead
139
- end
140
-
141
- # Returns array of [nterm, next_state]
142
- def nterm_transitions
143
- return @nterm_transitions if @nterm_transitions
144
-
145
- @nterm_transitions = []
146
-
147
- shifts.each do |shift|
148
- next if shift.next_sym.term?
149
-
150
- @nterm_transitions << [shift, @items_to_state[shift.next_items]]
151
- end
152
-
153
- @nterm_transitions
154
- end
155
-
156
- # Returns array of [term, next_state]
157
- def term_transitions
158
- return @term_transitions if @term_transitions
159
-
160
- @term_transitions = []
161
-
162
- shifts.each do |shift|
163
- next if shift.next_sym.nterm?
164
-
165
- @term_transitions << [shift, @items_to_state[shift.next_items]]
166
- end
167
-
168
- @term_transitions
169
- end
170
-
171
- def selected_term_transitions
172
- term_transitions.select do |shift, next_state|
173
- !shift.not_selected
174
- end
175
- end
176
-
177
- # Move to next state by sym
178
- def transition(sym)
179
- result = nil
180
-
181
- if sym.term?
182
- term_transitions.each do |shift, next_state|
183
- term = shift.next_sym
184
- result = next_state if term == sym
185
- end
186
- else
187
- nterm_transitions.each do |shift, next_state|
188
- nterm = shift.next_sym
189
- result = next_state if nterm == sym
190
- end
191
- end
192
-
193
- raise "Can not transit by #{sym} #{self}" if result.nil?
194
-
195
- result
196
- end
197
-
198
- def find_reduce_by_item!(item)
199
- reduces.find do |r|
200
- r.item == item
201
- end || (raise "reduce is not found. #{item}, #{state}")
202
- end
203
-
204
- def default_reduction_rule=(default_reduction_rule)
205
- @default_reduction_rule = default_reduction_rule
206
-
207
- reduces.each do |r|
208
- if r.rule == default_reduction_rule
209
- r.default_reduction = true
210
- end
211
- end
212
- end
213
-
214
- def sr_conflicts
215
- @conflicts.select do |conflict|
216
- conflict.type == :shift_reduce
217
- end
218
- end
219
-
220
- def rr_conflicts
221
- @conflicts.select do |conflict|
222
- conflict.type == :reduce_reduce
223
- end
224
- end
225
- end
226
-
227
5
  # States is passed to a template file
228
6
  #
229
7
  # "Efficient Computation of LALR(1) Look-Ahead Sets"
@@ -411,23 +189,13 @@ module Lrama
411
189
  @states.flat_map(&:rr_conflicts)
412
190
  end
413
191
 
414
- def initial_attrs
415
- h = {}
416
-
417
- attrs.each do |attr|
418
- h[attr.id] = false
419
- end
420
-
421
- h
422
- end
423
-
424
192
  def trace_state
425
193
  if @trace_state
426
194
  yield STDERR
427
195
  end
428
196
  end
429
197
 
430
- def create_state(accessing_symbol, kernels, states_creted)
198
+ def create_state(accessing_symbol, kernels, states_created)
431
199
  # A item can appear in some states,
432
200
  # so need to use `kernels` (not `kernels.first`) as a key.
433
201
  #
@@ -464,11 +232,11 @@ module Lrama
464
232
  # string_1: string •
465
233
  # string_2: string • '+'
466
234
  #
467
- return [states_creted[kernels], false] if states_creted[kernels]
235
+ return [states_created[kernels], false] if states_created[kernels]
468
236
 
469
237
  state = State.new(@states.count, accessing_symbol, kernels)
470
238
  @states << state
471
- states_creted[kernels] = state
239
+ states_created[kernels] = state
472
240
 
473
241
  return [state, true]
474
242
  end
@@ -532,9 +300,9 @@ module Lrama
532
300
  def compute_lr0_states
533
301
  # State queue
534
302
  states = []
535
- states_creted = {}
303
+ states_created = {}
536
304
 
537
- state, _ = create_state(symbols.first, [Item.new(rule: @grammar.rules.first, position: 0)], states_creted)
305
+ state, _ = create_state(symbols.first, [Item.new(rule: @grammar.rules.first, position: 0)], states_created)
538
306
  enqueue_state(states, state)
539
307
 
540
308
  while (state = states.shift) do
@@ -550,7 +318,7 @@ module Lrama
550
318
  setup_state(state)
551
319
 
552
320
  state.shifts.each do |shift|
553
- new_state, created = create_state(shift.next_sym, shift.next_items, states_creted)
321
+ new_state, created = create_state(shift.next_sym, shift.next_items, states_created)
554
322
  state.set_items_to_state(shift.next_items, new_state)
555
323
  enqueue_state(states, new_state) if created
556
324
  end
@@ -210,7 +210,7 @@ module Lrama
210
210
  io << "\n"
211
211
 
212
212
 
213
- # Reprot reads_relation
213
+ # Report reads_relation
214
214
  io << " [Reads Relation]\n"
215
215
  @states.nterms.each do |nterm|
216
216
  a = @states.reads_relation[[state.id, nterm.token_id]]
@@ -224,7 +224,7 @@ module Lrama
224
224
  io << "\n"
225
225
 
226
226
 
227
- # Reprot read_sets
227
+ # Report read_sets
228
228
  io << " [Read sets]\n"
229
229
  read_sets = @states.read_sets
230
230
  @states.nterms.each do |nterm|
@@ -239,7 +239,7 @@ module Lrama
239
239
  io << "\n"
240
240
 
241
241
 
242
- # Reprot includes_relation
242
+ # Report includes_relation
243
243
  io << " [Includes Relation]\n"
244
244
  @states.nterms.each do |nterm|
245
245
  a = @states.includes_relation[[state.id, nterm.token_id]]
@@ -267,7 +267,7 @@ module Lrama
267
267
  io << "\n"
268
268
 
269
269
 
270
- # Reprot follow_sets
270
+ # Report follow_sets
271
271
  io << " [Follow sets]\n"
272
272
  follow_sets = @states.follow_sets
273
273
  @states.nterms.each do |nterm|
data/lib/lrama/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lrama
2
- VERSION = "0.5.0".freeze
2
+ VERSION = "0.5.2".freeze
3
3
  end
data/lib/lrama.rb CHANGED
@@ -7,6 +7,7 @@ require "lrama/lexer"
7
7
  require "lrama/output"
8
8
  require "lrama/parser"
9
9
  require "lrama/report"
10
+ require "lrama/state"
10
11
  require "lrama/states"
11
12
  require "lrama/states_reporter"
12
13
  require "lrama/version"
data/lrama.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
 
9
9
  spec.summary = "LALR (1) parser generator written by Ruby"
10
10
  spec.description = "LALR (1) parser generator written by Ruby"
11
- spec.homepage = "https://github.com/yui-knk/lrama"
11
+ spec.homepage = "https://github.com/ruby/lrama"
12
12
  # See LEGAL.md file for detail
13
13
  spec.license = "GNU GPLv3"
14
14
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
@@ -0,0 +1,26 @@
1
+ ---
2
+ sources:
3
+ - type: git
4
+ name: ruby/gem_rbs_collection
5
+ revision: 28208148c7e64a25e9b86b9723b4c3a2cef14e81
6
+ remote: https://github.com/ruby/gem_rbs_collection.git
7
+ repo_dir: gems
8
+ path: ".gem_rbs_collection"
9
+ gems:
10
+ - name: erb
11
+ version: '0'
12
+ source:
13
+ type: stdlib
14
+ - name: stackprof
15
+ version: '0.2'
16
+ source:
17
+ type: git
18
+ name: ruby/gem_rbs_collection
19
+ revision: 28208148c7e64a25e9b86b9723b4c3a2cef14e81
20
+ remote: https://github.com/ruby/gem_rbs_collection.git
21
+ repo_dir: gems
22
+ - name: strscan
23
+ version: '0'
24
+ source:
25
+ type: stdlib
26
+ gemfile_lock_path: Gemfile.lock
@@ -0,0 +1,22 @@
1
+ # Download sources
2
+ sources:
3
+ - type: git
4
+ name: ruby/gem_rbs_collection
5
+ remote: https://github.com/ruby/gem_rbs_collection.git
6
+ revision: main
7
+ repo_dir: gems
8
+
9
+ # You can specify local directories as sources also.
10
+ # - type: local
11
+ # path: path/to/your/local/repository
12
+
13
+ # A directory to install the downloaded RBSs
14
+ path: .gem_rbs_collection
15
+
16
+ gems:
17
+ - name: erb
18
+ - name: strscan
19
+ # Skip loading rbs gem's RBS.
20
+ # It's unnecessary if you don't use rbs as a library.
21
+ - name: rbs
22
+ ignore: true