lrama 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/lrama/report.rb CHANGED
@@ -1,47 +1,2 @@
1
- module Lrama
2
- class Report
3
- module Profile
4
- # 1. Wrap target method with Profile.report_profile like below:
5
- #
6
- # Lrama::Report::Profile.report_profile { method }
7
- #
8
- # 2. Run lrama command, for example
9
- #
10
- # $ ./exe/lrama --trace=time spec/fixtures/integration/ruby_3_2_0/parse.tmp.y
11
- #
12
- # 3. Generate html file
13
- #
14
- # $ stackprof --d3-flamegraph tmp/stackprof-cpu-myapp.dump > tmp/flamegraph.html
15
- #
16
- def self.report_profile
17
- require "stackprof"
18
-
19
- StackProf.run(mode: :cpu, raw: true, out: 'tmp/stackprof-cpu-myapp.dump') do
20
- yield
21
- end
22
- end
23
- end
24
-
25
- module Duration
26
- def self.enable
27
- @_report_duration_enabled = true
28
- end
29
-
30
- def self.enabled?
31
- !!@_report_duration_enabled
32
- end
33
-
34
- def report_duration(method_name)
35
- time1 = Time.now.to_f
36
- result = yield
37
- time2 = Time.now.to_f
38
-
39
- if Duration.enabled?
40
- puts sprintf("%s %10.5f s", method_name, time2 - time1)
41
- end
42
-
43
- return result
44
- end
45
- end
46
- end
47
- end
1
+ require 'lrama/report/duration'
2
+ require 'lrama/report/profile'
@@ -0,0 +1,29 @@
1
+ module Lrama
2
+ class State
3
+ # * symbol: A symbol under discussion
4
+ # * reduce: A reduce under discussion
5
+ # * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative)
6
+ class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true)
7
+ def report_message
8
+ s = symbol.display_name
9
+ r = reduce.rule.precedence_sym.display_name
10
+ case
11
+ when which == :shift && same_prec
12
+ msg = "resolved as #{which} (%right #{s})"
13
+ when which == :shift
14
+ msg = "resolved as #{which} (#{r} < #{s})"
15
+ when which == :reduce && same_prec
16
+ msg = "resolved as #{which} (%left #{s})"
17
+ when which == :reduce
18
+ msg = "resolved as #{which} (#{s} < #{r})"
19
+ when which == :error
20
+ msg = "resolved as an #{which} (%nonassoc #{s})"
21
+ else
22
+ raise "Unknown direction. #{self}"
23
+ end
24
+
25
+ "Conflict between rule #{reduce.rule.id} and token #{s} #{msg}."
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/lrama/state.rb CHANGED
@@ -1,34 +1,9 @@
1
1
  require "lrama/state/reduce"
2
2
  require "lrama/state/shift"
3
+ require "lrama/state/resolved_conflict"
3
4
 
4
5
  module Lrama
5
6
  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
7
  Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
33
8
 
34
9
  attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
@@ -96,7 +71,7 @@ module Lrama
96
71
  reduce.look_ahead = look_ahead
97
72
  end
98
73
 
99
- # Returns array of [nterm, next_state]
74
+ # Returns array of [Shift, next_state]
100
75
  def nterm_transitions
101
76
  return @nterm_transitions if @nterm_transitions
102
77
 
@@ -111,7 +86,7 @@ module Lrama
111
86
  @nterm_transitions
112
87
  end
113
88
 
114
- # Returns array of [term, next_state]
89
+ # Returns array of [Shift, next_state]
115
90
  def term_transitions
116
91
  return @term_transitions if @term_transitions
117
92
 
@@ -0,0 +1,43 @@
1
+ # TODO: Validate position is not over rule rhs
2
+
3
+ module Lrama
4
+ class States
5
+ class Item < Struct.new(:rule, :position, keyword_init: true)
6
+ # Optimization for States#setup_state
7
+ def hash
8
+ [rule.id, position].hash
9
+ end
10
+
11
+ def rule_id
12
+ rule.id
13
+ end
14
+
15
+ def next_sym
16
+ rule.rhs[position]
17
+ end
18
+
19
+ def end_of_rule?
20
+ rule.rhs.count == position
21
+ end
22
+
23
+ def new_by_next_position
24
+ Item.new(rule: rule, position: position + 1)
25
+ end
26
+
27
+ def previous_sym
28
+ rule.rhs[position - 1]
29
+ end
30
+
31
+ def display_name
32
+ r = rule.rhs.map(&:display_name).insert(position, "•").join(" ")
33
+ "#{r} (rule #{rule.id})"
34
+ end
35
+
36
+ # Right after position
37
+ def display_rest
38
+ r = rule.rhs[position..-1].map(&:display_name).join(" ")
39
+ ". #{r} (rule #{rule.id})"
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/lrama/states.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "forwardable"
2
- require "lrama/report"
2
+ require "lrama/report/duration"
3
+ require "lrama/states/item"
3
4
 
4
5
  module Lrama
5
6
  # States is passed to a template file
@@ -11,46 +12,7 @@ module Lrama
11
12
  include Lrama::Report::Duration
12
13
 
13
14
  def_delegators "@grammar", :symbols, :terms, :nterms, :rules,
14
- :accept_symbol, :eof_symbol, :find_symbol_by_s_value!
15
-
16
- # TODO: Validate position is not over rule rhs
17
- Item = Struct.new(:rule, :position, keyword_init: true) do
18
- # Optimization for States#setup_state
19
- def hash
20
- [rule.id, position].hash
21
- end
22
-
23
- def rule_id
24
- rule.id
25
- end
26
-
27
- def next_sym
28
- rule.rhs[position]
29
- end
30
-
31
- def end_of_rule?
32
- rule.rhs.count == position
33
- end
34
-
35
- def new_by_next_position
36
- Item.new(rule: rule, position: position + 1)
37
- end
38
-
39
- def previous_sym
40
- rule.rhs[position - 1]
41
- end
42
-
43
- def display_name
44
- r = rule.rhs.map(&:display_name).insert(position, "•").join(" ")
45
- "#{r} (rule #{rule.id})"
46
- end
47
-
48
- # Right after position
49
- def display_rest
50
- r = rule.rhs[position..-1].map(&:display_name).join(" ")
51
- ". #{r} (rule #{rule.id})"
52
- end
53
- end
15
+ :accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!
54
16
 
55
17
  attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
56
18
 
data/lib/lrama/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lrama
2
- VERSION = "0.5.2".freeze
2
+ VERSION = "0.5.3".freeze
3
3
  end
data/lrama.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.description = "LALR (1) parser generator written by Ruby"
11
11
  spec.homepage = "https://github.com/ruby/lrama"
12
12
  # See LEGAL.md file for detail
13
- spec.license = "GNU GPLv3"
13
+ spec.license = "GPL-3.0-or-later"
14
14
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
15
15
 
16
16
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
@@ -1,9 +1,5 @@
1
1
  module Lrama
2
2
  class Report
3
- module Profile
4
- def self.report_profile: { -> void } -> StackProf::result
5
- end
6
-
7
3
  module Duration
8
4
  self.@_report_duration_enabled: bool | nil
9
5
 
@@ -0,0 +1,7 @@
1
+ module Lrama
2
+ class Report
3
+ module Profile
4
+ def self.report_profile: { -> void } -> StackProf::result
5
+ end
6
+ end
7
+ end
@@ -542,6 +542,13 @@ static const <%= output.int_type_for(output.context.yytranslate) %> yytranslate[
542
542
  <%= output.yytranslate %>
543
543
  };
544
544
 
545
+ <%- if output.error_recovery -%>
546
+ /* YYTRANSLATE_INVERTED[SYMBOL-NUM] -- Token number corresponding to SYMBOL-NUM */
547
+ static const <%= output.int_type_for(output.context.yytranslate_inverted) %> yytranslate_inverted[] =
548
+ {
549
+ <%= output.yytranslate_inverted %>
550
+ };
551
+ <%- end -%>
545
552
  #if YYDEBUG
546
553
  /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
547
554
  static const <%= output.int_type_for(output.context.yyrline) %> yyrline[] =
@@ -1211,6 +1218,303 @@ yydestruct (const char *yymsg,
1211
1218
 
1212
1219
 
1213
1220
 
1221
+ <%- if output.error_recovery -%>
1222
+ #ifndef YYMAXREPAIR
1223
+ # define YYMAXREPAIR 3
1224
+ #endif
1225
+
1226
+ enum repair_type {
1227
+ insert,
1228
+ delete,
1229
+ shift,
1230
+ };
1231
+
1232
+ struct repair {
1233
+ enum repair_type type;
1234
+ yysymbol_kind_t term;
1235
+ };
1236
+ typedef struct repair repair;
1237
+
1238
+ struct repairs {
1239
+ /* For debug */
1240
+ int id;
1241
+ /* For breadth-first traversing */
1242
+ struct repairs *next;
1243
+ YYPTRDIFF_T stack_length;
1244
+ /* Bottom of states */
1245
+ yy_state_t *states;
1246
+ /* Top of states */
1247
+ yy_state_t *state;
1248
+ /* repair length */
1249
+ int repair_length;
1250
+ /* */
1251
+ struct repairs *prev_repair;
1252
+ struct repair repair;
1253
+ };
1254
+ typedef struct repairs repairs;
1255
+
1256
+ struct yy_term {
1257
+ yysymbol_kind_t kind;
1258
+ YYSTYPE value;
1259
+ YYLTYPE location;
1260
+ };
1261
+ typedef struct yy_term yy_term;
1262
+
1263
+ struct repair_terms {
1264
+ int id;
1265
+ int length;
1266
+ yy_term terms[];
1267
+ };
1268
+ typedef struct repair_terms repair_terms;
1269
+
1270
+ static void
1271
+ yy_error_token_initialize (yysymbol_kind_t yykind, YYSTYPE * const yyvaluep, YYLTYPE * const yylocationp<%= output.user_formals %>)
1272
+ {
1273
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
1274
+ switch (yykind)
1275
+ {
1276
+ <%= output.symbol_actions_for_error_token -%>
1277
+ default:
1278
+ break;
1279
+ }
1280
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
1281
+ }
1282
+
1283
+ static repair_terms *
1284
+ yy_create_repair_terms(repairs *reps)
1285
+ {
1286
+ repairs *r = reps;
1287
+ repair_terms *rep_terms;
1288
+ int count = 0;
1289
+
1290
+ while (r->prev_repair)
1291
+ {
1292
+ count++;
1293
+ r = r->prev_repair;
1294
+ }
1295
+
1296
+ rep_terms = (repair_terms *) malloc (sizeof (repair_terms) + sizeof (yy_term) * count);
1297
+ rep_terms->id = reps->id;
1298
+ rep_terms->length = count;
1299
+
1300
+ r = reps;
1301
+ while (r->prev_repair)
1302
+ {
1303
+ rep_terms->terms[count-1].kind = r->repair.term;
1304
+ count--;
1305
+ r = r->prev_repair;
1306
+ }
1307
+
1308
+ return rep_terms;
1309
+ }
1310
+
1311
+ static void
1312
+ yy_print_repairs(repairs *reps)
1313
+ {
1314
+ repairs *r = reps;
1315
+
1316
+ fprintf (stderr,
1317
+ "id: %d, repair_length: %d, repair_state: %d, prev_repair_id: %d\n",
1318
+ reps->id, reps->repair_length, *reps->state, reps->prev_repair->id);
1319
+
1320
+ while (r->prev_repair)
1321
+ {
1322
+ fprintf (stderr, "%s ", yysymbol_name (r->repair.term));
1323
+ r = r->prev_repair;
1324
+ }
1325
+
1326
+ fprintf (stderr, "\n");
1327
+ }
1328
+
1329
+ static void
1330
+ yy_print_repair_terms(repair_terms *rep_terms)
1331
+ {
1332
+ for (int i = 0; i < rep_terms->length; i++)
1333
+ fprintf (stderr, "%s ", yysymbol_name (rep_terms->terms[i].kind));
1334
+
1335
+ fprintf (stderr, "\n");
1336
+ }
1337
+
1338
+ static void
1339
+ yy_free_repairs(repairs *reps)
1340
+ {
1341
+ while (reps)
1342
+ {
1343
+ repairs *r = reps;
1344
+ reps = reps->next;
1345
+ free (r->states);
1346
+ free (r);
1347
+ }
1348
+ }
1349
+
1350
+ static int
1351
+ yy_process_repairs(repairs *reps, yysymbol_kind_t token)
1352
+ {
1353
+ int yyn;
1354
+ int yystate = *reps->state;
1355
+ int yylen = 0;
1356
+ yysymbol_kind_t yytoken = token;
1357
+
1358
+ goto yyrecover_backup;
1359
+
1360
+ yyrecover_newstate:
1361
+ // TODO: check reps->stack_length
1362
+ reps->state += 1;
1363
+ *reps->state = (yy_state_t) yystate;
1364
+
1365
+
1366
+ yyrecover_backup:
1367
+ yyn = yypact[yystate];
1368
+ if (yypact_value_is_default (yyn))
1369
+ goto yyrecover_default;
1370
+
1371
+ /* "Reading a token" */
1372
+ if (yytoken == YYSYMBOL_YYEMPTY)
1373
+ return 1;
1374
+
1375
+ yyn += yytoken;
1376
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1377
+ goto yyrecover_default;
1378
+ yyn = yytable[yyn];
1379
+ if (yyn <= 0)
1380
+ {
1381
+ if (yytable_value_is_error (yyn))
1382
+ goto yyrecover_errlab;
1383
+ yyn = -yyn;
1384
+ goto yyrecover_reduce;
1385
+ }
1386
+
1387
+ /* shift */
1388
+ yystate = yyn;
1389
+ yytoken = YYSYMBOL_YYEMPTY;
1390
+ goto yyrecover_newstate;
1391
+
1392
+
1393
+ yyrecover_default:
1394
+ yyn = yydefact[yystate];
1395
+ if (yyn == 0)
1396
+ goto yyrecover_errlab;
1397
+ goto yyrecover_reduce;
1398
+
1399
+
1400
+ yyrecover_reduce:
1401
+ yylen = yyr2[yyn];
1402
+ /* YYPOPSTACK */
1403
+ reps->state -= yylen;
1404
+ yylen = 0;
1405
+
1406
+ {
1407
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
1408
+ const int yyi = yypgoto[yylhs] + *reps->state;
1409
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *reps->state
1410
+ ? yytable[yyi]
1411
+ : yydefgoto[yylhs]);
1412
+ }
1413
+
1414
+ goto yyrecover_newstate;
1415
+
1416
+ yyrecover_errlab:
1417
+ return 0;
1418
+ }
1419
+
1420
+ static repair_terms *
1421
+ yyrecover(yy_state_t *yyss, yy_state_t *yyssp, int yychar)
1422
+ {
1423
+ yysymbol_kind_t yytoken = YYTRANSLATE (yychar);
1424
+ repair_terms *rep_terms = YY_NULLPTR;
1425
+ int count = 0;
1426
+
1427
+ repairs *head = (repairs *) malloc (sizeof (repairs));
1428
+ repairs *current = head;
1429
+ repairs *tail = head;
1430
+ YYPTRDIFF_T stack_length = yyssp - yyss + 1;
1431
+
1432
+ head->id = count;
1433
+ head->next = 0;
1434
+ head->stack_length = stack_length;
1435
+ head->states = (yy_state_t *) malloc (sizeof (yy_state_t) * (stack_length));
1436
+ head->state = head->states + (yyssp - yyss);
1437
+ YYCOPY (head->states, yyss, stack_length);
1438
+ head->repair_length = 0;
1439
+ head->prev_repair = 0;
1440
+
1441
+ stack_length = (stack_length * 2 > 100) ? (stack_length * 2) : 100;
1442
+ count++;
1443
+
1444
+ while (current)
1445
+ {
1446
+ int yystate = *current->state;
1447
+ int yyn = yypact[yystate];
1448
+ /* See also: yypcontext_expected_tokens */
1449
+ if (!yypact_value_is_default (yyn))
1450
+ {
1451
+ int yyxbegin = yyn < 0 ? -yyn : 0;
1452
+ int yychecklim = YYLAST - yyn + 1;
1453
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1454
+ int yyx;
1455
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1456
+ {
1457
+ if (yyx != YYSYMBOL_YYerror)
1458
+ {
1459
+ if (current->repair_length + 1 > YYMAXREPAIR)
1460
+ continue;
1461
+
1462
+ repairs *new = (repairs *) malloc (sizeof (repairs));
1463
+ new->id = count;
1464
+ new->next = 0;
1465
+ new->stack_length = stack_length;
1466
+ new->states = (yy_state_t *) malloc (sizeof (yy_state_t) * (stack_length));
1467
+ new->state = new->states + (current->state - current->states);
1468
+ YYCOPY (new->states, current->states, current->state - current->states + 1);
1469
+ new->repair_length = current->repair_length + 1;
1470
+ new->prev_repair = current;
1471
+ new->repair.type = insert;
1472
+ new->repair.term = (yysymbol_kind_t) yyx;
1473
+
1474
+ /* Process PDA assuming next token is yyx */
1475
+ if (! yy_process_repairs (new, yyx))
1476
+ {
1477
+ free (new);
1478
+ continue;
1479
+ }
1480
+
1481
+ tail->next = new;
1482
+ tail = new;
1483
+ count++;
1484
+
1485
+ if (yyx == yytoken)
1486
+ {
1487
+ rep_terms = yy_create_repair_terms (current);
1488
+ fprintf (stderr, "repair_terms found. id: %d, length: %d\n", rep_terms->id, rep_terms->length);
1489
+ yy_print_repairs (current);
1490
+ yy_print_repair_terms (rep_terms);
1491
+
1492
+ goto done;
1493
+ }
1494
+
1495
+ fprintf (stderr,
1496
+ "New repairs is enqueued. count: %d, yystate: %d, yyx: %d\n",
1497
+ count, yystate, yyx);
1498
+ yy_print_repairs (new);
1499
+ }
1500
+ }
1501
+ }
1502
+
1503
+ current = current->next;
1504
+ }
1505
+
1506
+ done:
1507
+
1508
+ yy_free_repairs(head);
1509
+
1510
+ if (!rep_terms)
1511
+ {
1512
+ fprintf (stderr, "repair_terms not found\n");
1513
+ }
1514
+
1515
+ return rep_terms;
1516
+ }
1517
+ <%- end -%>
1214
1518
 
1215
1519
 
1216
1520
 
@@ -1281,6 +1585,12 @@ YYLTYPE yylloc = yyloc_default;
1281
1585
 
1282
1586
  /* The locations where the error started and ended. */
1283
1587
  YYLTYPE yyerror_range[3];
1588
+ <%- if output.error_recovery -%>
1589
+ repair_terms *rep_terms = 0;
1590
+ yy_term term_backup;
1591
+ int rep_terms_index;
1592
+ int yychar_backup;
1593
+ <%- end -%>
1284
1594
 
1285
1595
  /* Buffer for error messages, and its allocated size. */
1286
1596
  char yymsgbuf[128];
@@ -1415,6 +1725,36 @@ yybackup:
1415
1725
 
1416
1726
  /* Not known => get a lookahead token if don't already have one. */
1417
1727
 
1728
+ <%- if output.error_recovery -%>
1729
+ if (yychar == YYEMPTY && rep_terms)
1730
+ {
1731
+
1732
+ if (rep_terms_index < rep_terms->length)
1733
+ {
1734
+ YYDPRINTF ((stderr, "An error recovery token is used\n"));
1735
+ yy_term term = rep_terms->terms[rep_terms_index];
1736
+ yytoken = term.kind;
1737
+ yylval = term.value;
1738
+ yylloc = term.location;
1739
+ yychar = yytranslate_inverted[yytoken];
1740
+ YY_SYMBOL_PRINT ("Next error recovery token is", yytoken, &yylval, &yylloc<%= output.user_args %>);
1741
+ rep_terms_index++;
1742
+ }
1743
+ else
1744
+ {
1745
+ YYDPRINTF ((stderr, "Error recovery is completed\n"));
1746
+ yytoken = term_backup.kind;
1747
+ yylval = term_backup.value;
1748
+ yylloc = term_backup.location;
1749
+ yychar = yychar_backup;
1750
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc<%= output.user_args %>);
1751
+
1752
+ free (rep_terms);
1753
+ rep_terms = 0;
1754
+ yychar_backup = 0;
1755
+ }
1756
+ }
1757
+ <%- end -%>
1418
1758
  /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
1419
1759
  if (yychar == YYEMPTY)
1420
1760
  {
@@ -1639,6 +1979,29 @@ yyerrorlab:
1639
1979
  | yyerrlab1 -- common code for both syntax error and YYERROR. |
1640
1980
  `-------------------------------------------------------------*/
1641
1981
  yyerrlab1:
1982
+ <%- if output.error_recovery -%>
1983
+ {
1984
+ rep_terms = yyrecover (yyss, yyssp, yychar);
1985
+ if (rep_terms)
1986
+ {
1987
+ for (int i = 0; i < rep_terms->length; i++)
1988
+ {
1989
+ yy_term *term = &rep_terms->terms[i];
1990
+ yy_error_token_initialize (term->kind, &term->value, &term->location<%= output.user_args %>);
1991
+ }
1992
+
1993
+ yychar_backup = yychar;
1994
+ /* Can be packed into (the tail of) rep_terms? */
1995
+ term_backup.kind = yytoken;
1996
+ term_backup.value = yylval;
1997
+ term_backup.location = yylloc;
1998
+ rep_terms_index = 0;
1999
+ yychar = YYEMPTY;
2000
+
2001
+ goto yybackup;
2002
+ }
2003
+ }
2004
+ <%- end -%>
1642
2005
  yyerrstatus = 3; /* Each real token shifted decrements this. */
1643
2006
 
1644
2007
  /* Pop stack until we find a state that shifts the error token. */