lrama 0.4.0 → 0.5.1

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.
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.4.0".freeze
2
+ VERSION = "0.5.1".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"
@@ -0,0 +1,263 @@
1
+ Grammar
2
+
3
+ 0 $accept: list "end of file"
4
+
5
+ 1 list: ε
6
+ 2 | list LF
7
+ 3 | list expr LF
8
+
9
+ 4 expr: NUM
10
+ 5 | expr '+' expr
11
+ 6 | expr '-' expr
12
+ 7 | expr '*' expr
13
+ 8 | expr '/' expr
14
+ 9 | '(' expr ')'
15
+
16
+
17
+ State 0
18
+
19
+ 0 $accept: • list "end of file"
20
+ 1 list: ε •
21
+ 2 | • list LF
22
+ 3 | • list expr LF
23
+
24
+ $default reduce using rule 1 (list)
25
+
26
+ list go to state 1
27
+
28
+
29
+ State 1
30
+
31
+ 0 $accept: list • "end of file"
32
+ 2 list: list • LF
33
+ 3 | list • expr LF
34
+ 4 expr: • NUM
35
+ 5 | • expr '+' expr
36
+ 6 | • expr '-' expr
37
+ 7 | • expr '*' expr
38
+ 8 | • expr '/' expr
39
+ 9 | • '(' expr ')'
40
+
41
+ "end of file" shift, and go to state 2
42
+ LF shift, and go to state 3
43
+ NUM shift, and go to state 4
44
+ '(' shift, and go to state 5
45
+
46
+ expr go to state 6
47
+
48
+
49
+ State 2
50
+
51
+ 0 $accept: list "end of file" •
52
+
53
+ $default accept
54
+
55
+
56
+ State 3
57
+
58
+ 2 list: list LF •
59
+
60
+ $default reduce using rule 2 (list)
61
+
62
+
63
+ State 4
64
+
65
+ 4 expr: NUM •
66
+
67
+ $default reduce using rule 4 (expr)
68
+
69
+
70
+ State 5
71
+
72
+ 4 expr: • NUM
73
+ 5 | • expr '+' expr
74
+ 6 | • expr '-' expr
75
+ 7 | • expr '*' expr
76
+ 8 | • expr '/' expr
77
+ 9 | • '(' expr ')'
78
+ 9 | '(' • expr ')'
79
+
80
+ NUM shift, and go to state 4
81
+ '(' shift, and go to state 5
82
+
83
+ expr go to state 7
84
+
85
+
86
+ State 6
87
+
88
+ 3 list: list expr • LF
89
+ 5 expr: expr • '+' expr
90
+ 6 | expr • '-' expr
91
+ 7 | expr • '*' expr
92
+ 8 | expr • '/' expr
93
+
94
+ LF shift, and go to state 8
95
+ '+' shift, and go to state 9
96
+ '-' shift, and go to state 10
97
+ '*' shift, and go to state 11
98
+ '/' shift, and go to state 12
99
+
100
+
101
+ State 7
102
+
103
+ 5 expr: expr • '+' expr
104
+ 6 | expr • '-' expr
105
+ 7 | expr • '*' expr
106
+ 8 | expr • '/' expr
107
+ 9 | '(' expr • ')'
108
+
109
+ '+' shift, and go to state 9
110
+ '-' shift, and go to state 10
111
+ '*' shift, and go to state 11
112
+ '/' shift, and go to state 12
113
+ ')' shift, and go to state 13
114
+
115
+
116
+ State 8
117
+
118
+ 3 list: list expr LF •
119
+
120
+ $default reduce using rule 3 (list)
121
+
122
+
123
+ State 9
124
+
125
+ 4 expr: • NUM
126
+ 5 | • expr '+' expr
127
+ 5 | expr '+' • expr
128
+ 6 | • expr '-' expr
129
+ 7 | • expr '*' expr
130
+ 8 | • expr '/' expr
131
+ 9 | • '(' expr ')'
132
+
133
+ NUM shift, and go to state 4
134
+ '(' shift, and go to state 5
135
+
136
+ expr go to state 14
137
+
138
+
139
+ State 10
140
+
141
+ 4 expr: • NUM
142
+ 5 | • expr '+' expr
143
+ 6 | • expr '-' expr
144
+ 6 | expr '-' • expr
145
+ 7 | • expr '*' expr
146
+ 8 | • expr '/' expr
147
+ 9 | • '(' expr ')'
148
+
149
+ NUM shift, and go to state 4
150
+ '(' shift, and go to state 5
151
+
152
+ expr go to state 15
153
+
154
+
155
+ State 11
156
+
157
+ 4 expr: • NUM
158
+ 5 | • expr '+' expr
159
+ 6 | • expr '-' expr
160
+ 7 | • expr '*' expr
161
+ 7 | expr '*' • expr
162
+ 8 | • expr '/' expr
163
+ 9 | • '(' expr ')'
164
+
165
+ NUM shift, and go to state 4
166
+ '(' shift, and go to state 5
167
+
168
+ expr go to state 16
169
+
170
+
171
+ State 12
172
+
173
+ 4 expr: • NUM
174
+ 5 | • expr '+' expr
175
+ 6 | • expr '-' expr
176
+ 7 | • expr '*' expr
177
+ 8 | • expr '/' expr
178
+ 8 | expr '/' • expr
179
+ 9 | • '(' expr ')'
180
+
181
+ NUM shift, and go to state 4
182
+ '(' shift, and go to state 5
183
+
184
+ expr go to state 17
185
+
186
+
187
+ State 13
188
+
189
+ 9 expr: '(' expr ')' •
190
+
191
+ $default reduce using rule 9 (expr)
192
+
193
+
194
+ State 14
195
+
196
+ 5 expr: expr • '+' expr
197
+ 5 | expr '+' expr • [LF, '+', '-', ')']
198
+ 6 | expr • '-' expr
199
+ 7 | expr • '*' expr
200
+ 8 | expr • '/' expr
201
+
202
+ '*' shift, and go to state 11
203
+ '/' shift, and go to state 12
204
+
205
+ $default reduce using rule 5 (expr)
206
+
207
+ Conflict between rule 5 and token '+' resolved as reduce (%left '+').
208
+ Conflict between rule 5 and token '-' resolved as reduce (%left '-').
209
+ Conflict between rule 5 and token '*' resolved as shift ('+' < '*').
210
+ Conflict between rule 5 and token '/' resolved as shift ('+' < '/').
211
+
212
+
213
+ State 15
214
+
215
+ 5 expr: expr • '+' expr
216
+ 6 | expr • '-' expr
217
+ 6 | expr '-' expr • [LF, '+', '-', ')']
218
+ 7 | expr • '*' expr
219
+ 8 | expr • '/' expr
220
+
221
+ '*' shift, and go to state 11
222
+ '/' shift, and go to state 12
223
+
224
+ $default reduce using rule 6 (expr)
225
+
226
+ Conflict between rule 6 and token '+' resolved as reduce (%left '+').
227
+ Conflict between rule 6 and token '-' resolved as reduce (%left '-').
228
+ Conflict between rule 6 and token '*' resolved as shift ('-' < '*').
229
+ Conflict between rule 6 and token '/' resolved as shift ('-' < '/').
230
+
231
+
232
+ State 16
233
+
234
+ 5 expr: expr • '+' expr
235
+ 6 | expr • '-' expr
236
+ 7 | expr • '*' expr
237
+ 7 | expr '*' expr • [LF, '+', '-', '*', '/', ')']
238
+ 8 | expr • '/' expr
239
+
240
+ $default reduce using rule 7 (expr)
241
+
242
+ Conflict between rule 7 and token '+' resolved as reduce ('+' < '*').
243
+ Conflict between rule 7 and token '-' resolved as reduce ('-' < '*').
244
+ Conflict between rule 7 and token '*' resolved as reduce (%left '*').
245
+ Conflict between rule 7 and token '/' resolved as reduce (%left '/').
246
+
247
+
248
+ State 17
249
+
250
+ 5 expr: expr • '+' expr
251
+ 6 | expr • '-' expr
252
+ 7 | expr • '*' expr
253
+ 8 | expr • '/' expr
254
+ 8 | expr '/' expr • [LF, '+', '-', '*', '/', ')']
255
+
256
+ $default reduce using rule 8 (expr)
257
+
258
+ Conflict between rule 8 and token '+' resolved as reduce ('+' < '/').
259
+ Conflict between rule 8 and token '-' resolved as reduce ('-' < '/').
260
+ Conflict between rule 8 and token '*' resolved as reduce (%left '*').
261
+ Conflict between rule 8 and token '/' resolved as reduce (%left '/').
262
+
263
+
data/sample/calc.y ADDED
@@ -0,0 +1,98 @@
1
+ /*
2
+ * How to build and run:
3
+ *
4
+ * $ lrama -d calc.y -o calc.c && gcc -Wall calc.c -o calc && ./calc
5
+ * 1
6
+ * => 1
7
+ * 1+2*3
8
+ * => 7
9
+ * (1+2)*3
10
+ * => 9
11
+ *
12
+ */
13
+
14
+ %{
15
+ #include <stdio.h>
16
+ #include <stdlib.h>
17
+ #include <ctype.h>
18
+
19
+ #include "calc.h"
20
+
21
+ static int yylex(YYSTYPE *val, YYLTYPE *loc);
22
+ static int yyerror(YYLTYPE *loc, const char *str);
23
+ %}
24
+
25
+ %union {
26
+ int val;
27
+ }
28
+ %token LF
29
+ %token <val> NUM
30
+ %type <val> expr
31
+ %left '+' '-'
32
+ %left '*' '/'
33
+
34
+ %%
35
+
36
+ list : /* empty */
37
+ | list LF
38
+ | list expr LF { printf("=> %d\n", $2); }
39
+ ;
40
+ expr : NUM
41
+ | expr '+' expr { $$ = $1 + $3; }
42
+ | expr '-' expr { $$ = $1 - $3; }
43
+ | expr '*' expr { $$ = $1 * $3; }
44
+ | expr '/' expr { $$ = $1 / $3; }
45
+ | '(' expr ')' { $$ = $2; }
46
+ ;
47
+
48
+ %%
49
+
50
+ static int yylex(YYSTYPE *yylval, YYLTYPE *loc) {
51
+ int c = getchar();
52
+ int val;
53
+
54
+ switch (c) {
55
+ case ' ': case '\t':
56
+ return yylex(yylval, loc);
57
+
58
+ case '0': case '1': case '2': case '3': case '4':
59
+ case '5': case '6': case '7': case '8': case '9':
60
+ val = c - '0';
61
+ while (1) {
62
+ c = getchar();
63
+ if (isdigit(c)) {
64
+ val = val * 10 + (c - '0');
65
+ }
66
+ else {
67
+ ungetc(c, stdin);
68
+ break;
69
+ }
70
+ }
71
+ yylval->val = val;
72
+ return NUM;
73
+
74
+ case '\n':
75
+ return LF;
76
+
77
+ case '+': case '-': case '*': case '/': case '(': case ')':
78
+ return c;
79
+
80
+ case EOF:
81
+ exit(0);
82
+
83
+ default:
84
+ fprintf(stderr, "unknown character: %c\n", c);
85
+ exit(1);
86
+ }
87
+ }
88
+
89
+ static int yyerror(YYLTYPE *loc, const char *str) {
90
+ fprintf(stderr, "parse error: %s\n", str);
91
+ return 0;
92
+ }
93
+
94
+ int main() {
95
+ printf("Enter the formula:\n");
96
+ yyparse();
97
+ return 0;
98
+ }
@@ -0,0 +1,7 @@
1
+ module Lrama
2
+ module Bitmap
3
+ def self.from_array: (Array[int] ary) -> Integer
4
+
5
+ def self.to_array: (Integer int) -> Array[Integer]
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  <%# b4_generated_by -%>
2
- /* A Bison parser, made by GNU Bison 3.8.2. */
2
+ /* A Bison parser, made by Lrama <%= Lrama::VERSION %>. */
3
3
 
4
4
  <%# b4_copyright -%>
5
5
  /* Bison implementation for Yacc-like parsers in C