lrama 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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