lrama 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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