lrama 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ module Lrama
2
+ class Grammar
3
+ # Grammar file information not used by States but by Output
4
+ class Auxiliary < Struct.new(:prologue_first_lineno, :prologue, :epilogue_first_lineno, :epilogue, keyword_init: true)
5
+ end
6
+ end
7
+ end
@@ -17,6 +17,12 @@ module Lrama
17
17
  "#{l}: #{r}"
18
18
  end
19
19
 
20
+ # opt_nl: ε <-- empty_rule
21
+ # | '\n' <-- not empty_rule
22
+ def empty_rule?
23
+ rhs.empty?
24
+ end
25
+
20
26
  def precedence
21
27
  precedence_sym&.precedence
22
28
  end
@@ -7,6 +7,7 @@
7
7
  module Lrama
8
8
  class Grammar
9
9
  class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, :error_token, keyword_init: true)
10
+ attr_accessor :first_set, :first_set_bitmap
10
11
  attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
11
12
 
12
13
  def term?
@@ -34,11 +35,7 @@ module Lrama
34
35
  end
35
36
 
36
37
  def display_name
37
- if alias_name
38
- alias_name
39
- else
40
- id.s_value
41
- end
38
+ alias_name || id.s_value
42
39
  end
43
40
 
44
41
  # name for yysymbol_kind_t
@@ -51,11 +48,7 @@ module Lrama
51
48
  when eof_symbol?
52
49
  name = "YYEOF"
53
50
  when term? && id.type == Token::Char
54
- if alias_name
55
- name = number.to_s + alias_name
56
- else
57
- name = number.to_s + id.s_value
58
- end
51
+ name = number.to_s + display_name
59
52
  when term? && id.type == Token::Ident
60
53
  name = id.s_value
61
54
  when nterm? && (id.s_value.include?("$") || id.s_value.include?("@"))
@@ -66,7 +59,7 @@ module Lrama
66
59
  raise "Unexpected #{self}"
67
60
  end
68
61
 
69
- "YYSYMBOL_" + name.gsub(/[^a-zA-Z_0-9]+/, "_")
62
+ "YYSYMBOL_" + name.gsub(/\W+/, "_")
70
63
  end
71
64
 
72
65
  # comment for yysymbol_kind_t
data/lib/lrama/grammar.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "lrama/grammar/auxiliary"
1
2
  require "lrama/grammar/code"
2
3
  require "lrama/grammar/error_token"
3
4
  require "lrama/grammar/precedence"
@@ -7,16 +8,13 @@ require "lrama/grammar/rule"
7
8
  require "lrama/grammar/symbol"
8
9
  require "lrama/grammar/union"
9
10
  require "lrama/lexer"
11
+ require "lrama/type"
10
12
 
11
13
  module Lrama
12
- Type = Struct.new(:id, :tag, keyword_init: true)
13
14
  Token = Lrama::Lexer::Token
14
15
 
15
16
  # Grammar is the result of parsing an input grammar file
16
17
  class Grammar
17
- # Grammar file information not used by States but by Output
18
- Aux = Struct.new(:prologue_first_lineno, :prologue, :epilogue_first_lineno, :epilogue, keyword_init: true)
19
-
20
18
  attr_reader :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux
21
19
  attr_accessor :union, :expect,
22
20
  :printers, :error_tokens,
@@ -38,7 +36,7 @@ module Lrama
38
36
  @error_symbol = nil
39
37
  @undef_symbol = nil
40
38
  @accept_symbol = nil
41
- @aux = Aux.new
39
+ @aux = Auxiliary.new
42
40
 
43
41
  append_special_symbols
44
42
  end
@@ -48,7 +46,7 @@ module Lrama
48
46
  end
49
47
 
50
48
  def add_error_token(ident_or_tags:, code:, lineno:)
51
- @error_tokens << ErrorToken.new(ident_or_tags, code, lineno)
49
+ @error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, code: code, lineno: lineno)
52
50
  end
53
51
 
54
52
  def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false)
@@ -215,6 +213,41 @@ module Lrama
215
213
  end
216
214
  end
217
215
 
216
+ def compute_first_set
217
+ terms.each do |term|
218
+ term.first_set = Set.new([term]).freeze
219
+ term.first_set_bitmap = Lrama::Bitmap.from_array([term.number])
220
+ end
221
+
222
+ nterms.each do |nterm|
223
+ nterm.first_set = Set.new([]).freeze
224
+ nterm.first_set_bitmap = Lrama::Bitmap.from_array([])
225
+ end
226
+
227
+ while true do
228
+ changed = false
229
+
230
+ @rules.each do |rule|
231
+ rule.rhs.each do |r|
232
+ if rule.lhs.first_set_bitmap | r.first_set_bitmap != rule.lhs.first_set_bitmap
233
+ changed = true
234
+ rule.lhs.first_set_bitmap = rule.lhs.first_set_bitmap | r.first_set_bitmap
235
+ end
236
+
237
+ break unless r.nullable
238
+ end
239
+ end
240
+
241
+ break unless changed
242
+ end
243
+
244
+ nterms.each do |nterm|
245
+ nterm.first_set = Lrama::Bitmap.to_array(nterm.first_set_bitmap).map do |number|
246
+ find_symbol_by_number!(number)
247
+ end.to_set
248
+ end
249
+ end
250
+
218
251
  def find_symbol_by_s_value(s_value)
219
252
  @symbols.find do |sym|
220
253
  sym.id.s_value == s_value
@@ -0,0 +1,8 @@
1
+ module Lrama
2
+ class Lexer
3
+ class Token < Struct.new(:type, :s_value, :alias, keyword_init: true)
4
+ class Type < Struct.new(:id, :name, keyword_init: true)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,8 @@
1
+ require 'lrama/lexer/token/type'
2
+
1
3
  module Lrama
2
4
  class Lexer
3
- class Token < Struct.new(:type, :s_value, :alias, keyword_init: true)
4
- Type = Struct.new(:id, :name, keyword_init: true)
5
+ class Token
5
6
 
6
7
  attr_accessor :line, :column, :referred
7
8
  # For User_code
data/lib/lrama/output.rb CHANGED
@@ -252,7 +252,7 @@ module Lrama
252
252
  end
253
253
 
254
254
  def extract_param_name(param)
255
- /\A(.)+([a-zA-Z0-9_]+)\z/.match(param)[2]
255
+ /\A(\W*)([a-zA-Z0-9_]+)\z/.match(param.split.last)[2]
256
256
  end
257
257
 
258
258
  def parse_param_name
@@ -11,7 +11,7 @@ module Lrama
11
11
  end
12
12
 
13
13
  def current_type
14
- current_token && current_token.type
14
+ current_token&.type
15
15
  end
16
16
 
17
17
  def previous_token
@@ -26,9 +26,7 @@ module Lrama
26
26
 
27
27
  def consume(*token_types)
28
28
  if token_types.include?(current_type)
29
- token = current_token
30
- self.next
31
- return token
29
+ return self.next
32
30
  end
33
31
 
34
32
  return nil
@@ -42,8 +40,7 @@ module Lrama
42
40
  a = []
43
41
 
44
42
  while token_types.include?(current_type)
45
- a << current_token
46
- self.next
43
+ a << self.next
47
44
  end
48
45
 
49
46
  raise "No token is consumed. #{token_types}" if a.empty?
data/lib/lrama/parser.rb CHANGED
@@ -22,6 +22,7 @@ module Lrama
22
22
  process_epilogue(grammar, lexer)
23
23
  grammar.prepare
24
24
  grammar.compute_nullable
25
+ grammar.compute_first_set
25
26
  grammar.validate!
26
27
 
27
28
  grammar
@@ -0,0 +1,9 @@
1
+ module Lrama
2
+ class State
3
+ class ReduceReduceConflict < Struct.new(:symbols, :reduce1, :reduce2, keyword_init: true)
4
+ def type
5
+ :reduce_reduce
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lrama
2
+ class State
3
+ class ShiftReduceConflict < Struct.new(:symbols, :shift, :reduce, keyword_init: true)
4
+ def type
5
+ :shift_reduce
6
+ end
7
+ end
8
+ end
9
+ end
data/lib/lrama/state.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  require "lrama/state/reduce"
2
- require "lrama/state/shift"
2
+ require "lrama/state/reduce_reduce_conflict"
3
3
  require "lrama/state/resolved_conflict"
4
+ require "lrama/state/shift"
5
+ require "lrama/state/shift_reduce_conflict"
4
6
 
5
7
  module Lrama
6
8
  class State
7
- Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
8
-
9
9
  attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
10
10
  :default_reduction_rule, :closure, :items
11
11
  attr_accessor :shifts, :reduces
@@ -101,6 +101,10 @@ module Lrama
101
101
  @term_transitions
102
102
  end
103
103
 
104
+ def transitions
105
+ term_transitions + nterm_transitions
106
+ end
107
+
104
108
  def selected_term_transitions
105
109
  term_transitions.select do |shift, next_state|
106
110
  !shift.not_selected
@@ -144,6 +148,10 @@ module Lrama
144
148
  end
145
149
  end
146
150
 
151
+ def has_conflicts?
152
+ !@conflicts.empty?
153
+ end
154
+
147
155
  def sr_conflicts
148
156
  @conflicts.select do |conflict|
149
157
  conflict.type == :shift_reduce
@@ -12,20 +12,56 @@ module Lrama
12
12
  rule.id
13
13
  end
14
14
 
15
+ def empty_rule?
16
+ rule.empty_rule?
17
+ end
18
+
19
+ def number_of_rest_symbols
20
+ rule.rhs.count - position
21
+ end
22
+
23
+ def lhs
24
+ rule.lhs
25
+ end
26
+
15
27
  def next_sym
16
28
  rule.rhs[position]
17
29
  end
18
30
 
31
+ def next_next_sym
32
+ rule.rhs[position + 1]
33
+ end
34
+
35
+ def previous_sym
36
+ rule.rhs[position - 1]
37
+ end
38
+
19
39
  def end_of_rule?
20
40
  rule.rhs.count == position
21
41
  end
22
42
 
43
+ def beginning_of_rule?
44
+ position == 0
45
+ end
46
+
47
+ def start_item?
48
+ rule.id == 0 && position == 0
49
+ end
50
+
23
51
  def new_by_next_position
24
52
  Item.new(rule: rule, position: position + 1)
25
53
  end
26
54
 
27
- def previous_sym
28
- rule.rhs[position - 1]
55
+ def symbols_before_dot
56
+ rule.rhs[0...position]
57
+ end
58
+
59
+ def symbols_after_dot
60
+ rule.rhs[position..-1]
61
+ end
62
+
63
+ def to_s
64
+ "#{lhs.id.s_value}: #{display_name}"
29
65
  end
30
66
 
31
67
  def display_name
data/lib/lrama/states.rb CHANGED
@@ -102,43 +102,27 @@ module Lrama
102
102
  end
103
103
 
104
104
  def direct_read_sets
105
- h = {}
106
-
107
- @direct_read_sets.each do |k, v|
108
- h[k] = bitmap_to_terms(v)
105
+ @direct_read_sets.transform_values do |v|
106
+ bitmap_to_terms(v)
109
107
  end
110
-
111
- return h
112
108
  end
113
109
 
114
110
  def read_sets
115
- h = {}
116
-
117
- @read_sets.each do |k, v|
118
- h[k] = bitmap_to_terms(v)
111
+ @read_sets.transform_values do |v|
112
+ bitmap_to_terms(v)
119
113
  end
120
-
121
- return h
122
114
  end
123
115
 
124
116
  def follow_sets
125
- h = {}
126
-
127
- @follow_sets.each do |k, v|
128
- h[k] = bitmap_to_terms(v)
117
+ @follow_sets.transform_values do |v|
118
+ bitmap_to_terms(v)
129
119
  end
130
-
131
- return h
132
120
  end
133
121
 
134
122
  def la
135
- h = {}
136
-
137
- @la.each do |k, v|
138
- h[k] = bitmap_to_terms(v)
123
+ @la.transform_values do |v|
124
+ bitmap_to_terms(v)
139
125
  end
140
-
141
- return h
142
126
  end
143
127
 
144
128
  private
@@ -452,7 +436,7 @@ module Lrama
452
436
 
453
437
  # Can resolve only when both have prec
454
438
  unless shift_prec && reduce_prec
455
- state.conflicts << State::Conflict.new(symbols: [sym], reduce: reduce, type: :shift_reduce)
439
+ state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
456
440
  next
457
441
  end
458
442
 
@@ -501,16 +485,21 @@ module Lrama
501
485
 
502
486
  def compute_reduce_reduce_conflicts
503
487
  states.each do |state|
504
- a = []
488
+ count = state.reduces.count
505
489
 
506
- state.reduces.each do |reduce|
507
- next if reduce.look_ahead.nil?
490
+ for i in 0...count do
491
+ reduce1 = state.reduces[i]
492
+ next if reduce1.look_ahead.nil?
508
493
 
509
- intersection = a & reduce.look_ahead
510
- a += reduce.look_ahead
494
+ for j in (i+1)...count do
495
+ reduce2 = state.reduces[j]
496
+ next if reduce2.look_ahead.nil?
511
497
 
512
- if !intersection.empty?
513
- state.conflicts << State::Conflict.new(symbols: intersection.dup, reduce: reduce, type: :reduce_reduce)
498
+ intersection = reduce1.look_ahead & reduce2.look_ahead
499
+
500
+ if !intersection.empty?
501
+ state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
502
+ end
514
503
  end
515
504
  end
516
505
  end
@@ -14,13 +14,13 @@ module Lrama
14
14
 
15
15
  private
16
16
 
17
- def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, verbose: false)
17
+ def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false)
18
18
  # TODO: Unused terms
19
19
  # TODO: Unused rules
20
20
 
21
21
  report_conflicts(io)
22
22
  report_grammar(io) if grammar
23
- report_states(io, itemsets, lookaheads, solved, verbose)
23
+ report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
24
24
  end
25
25
 
26
26
  def report_conflicts(io)
@@ -71,7 +71,11 @@ module Lrama
71
71
  io << "\n\n"
72
72
  end
73
73
 
74
- def report_states(io, itemsets, lookaheads, solved, verbose)
74
+ def report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
75
+ if counterexamples
76
+ cex = Counterexamples.new(@states)
77
+ end
78
+
75
79
  @states.states.each do |state|
76
80
  # Report State
77
81
  io << "State #{state.id}\n\n"
@@ -194,6 +198,27 @@ module Lrama
194
198
  io << "\n" if !state.resolved_conflicts.empty?
195
199
  end
196
200
 
201
+ if counterexamples && state.has_conflicts?
202
+ # Report counterexamples
203
+ examples = cex.compute(state)
204
+ examples.each do |example|
205
+ label0 = example.type == :shift_reduce ? "shift/reduce" : "reduce/reduce"
206
+ label1 = example.type == :shift_reduce ? "Shift derivation" : "First Reduce derivation"
207
+ label2 = example.type == :shift_reduce ? "Reduce derivation" : "Second Reduce derivation"
208
+
209
+ io << " #{label0} conflict on token #{example.conflict_symbol.id.s_value}:\n"
210
+ io << " #{example.path1_item.to_s}\n"
211
+ io << " #{example.path2_item.to_s}\n"
212
+ io << " #{label1}\n"
213
+ example.derivations1.render_strings_for_report.each do |str|
214
+ io << " #{str}\n"
215
+ end
216
+ io << " #{label2}\n"
217
+ example.derivations2.render_strings_for_report.each do |str|
218
+ io << " #{str}\n"
219
+ end
220
+ end
221
+ end
197
222
 
198
223
  if verbose
199
224
  # Report direct_read_sets
data/lib/lrama/type.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Lrama
2
+ class Type < Struct.new(:id, :tag, keyword_init: true)
3
+ end
4
+ end
data/lib/lrama/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lrama
2
- VERSION = "0.5.3".freeze
2
+ VERSION = "0.5.4".freeze
3
3
  end
data/lib/lrama.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "lrama/bitmap"
2
2
  require "lrama/command"
3
3
  require "lrama/context"
4
+ require "lrama/counterexamples"
4
5
  require "lrama/digraph"
5
6
  require "lrama/grammar"
6
7
  require "lrama/lexer"
@@ -10,5 +11,6 @@ require "lrama/report"
10
11
  require "lrama/state"
11
12
  require "lrama/states"
12
13
  require "lrama/states_reporter"
14
+ require "lrama/type"
13
15
  require "lrama/version"
14
16
  require "lrama/warning"