Coverage Report

Created: 2026-10-28 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hobbes/lib/hobbes/parse/lalr.C
Line
Count
Source
1
2
#include <hobbes/parse/lalr.H>
3
#include <algorithm>
4
#include <stdexcept>
5
#include <string>
6
#include <vector>
7
8
namespace hobbes {
9
10
/*
11
 * basic grammar/rule analysis
12
 */
13
0
void removeRuleDefs(terminal* s, grammar* g) {
14
0
  auto r = g->find(s);
15
0
  if (r != g->end()) {
16
0
    g->erase(r);
17
0
  }
18
0
}
19
20
0
void removeRuleRefs(terminal* s, grammar* g) {
21
0
  for (auto &sd : *g) {
22
0
    for (nat r = 0; r < sd.second.size();) {
23
0
      if (in(s, sd.second[r])) {
24
0
        sd.second.erase(sd.second.begin() + r);
25
0
      } else {
26
0
        ++r;
27
0
      }
28
0
    }
29
0
  }
30
0
}
31
32
0
void undefineSymbol(terminal* s, grammar* g) {
33
0
  removeRuleDefs(s, g);
34
0
  removeRuleRefs(s, g);
35
0
}
36
37
0
grammar removeRuleDefs(terminal* s, const grammar& g) {
38
0
  grammar r = g;
39
0
  removeRuleDefs(s, &r);
40
0
  return r;
41
0
}
42
43
0
grammar removeRuleRefs(terminal* s, const grammar& g) {
44
0
  grammar r = g;
45
0
  removeRuleRefs(s, &r);
46
0
  return r;
47
0
}
48
49
0
grammar undefineSymbol(terminal* s, const grammar& g) {
50
0
  grammar r = g;
51
0
  undefineSymbol(s, &r);
52
0
  return r;
53
0
}
54
55
0
terminalset definedSymbols(const grammar& g) {
56
0
  return keys(g);
57
0
}
58
59
// a top-level symbol is used by nothing, or just by itself
60
0
terminalset topLevelSymbols(const grammar& g) {
61
0
  terminalset result;
62
0
  terminalset dsyms = definedSymbols(g);
63
64
0
  for (auto *dsym : dsyms) {
65
0
    terminalset users = symbolsUsing(g, dsym);
66
0
    if (users.empty() || (users.size() == 1 && in(dsym, users))) {
67
0
      result.insert(dsym);
68
0
    }
69
0
  }
70
71
0
  return result;
72
0
}
73
74
0
void symbolsUsed(const grammar& g, const rule& r, terminalset* ss) {
75
0
  for (auto *t : r) {
76
0
    if (hasRule(g, t)) {
77
0
      if (!in(t, *ss)) {
78
0
        ss->insert(t);
79
0
        symbolsUsed(g, t, ss);
80
0
      }
81
0
    }
82
0
  }
83
0
}
84
85
0
void symbolsUsed(const grammar& g, const rules& rs, terminalset* ss) {
86
0
  for (const auto &r : rs) {
87
0
    symbolsUsed(g, r, ss);
88
0
  }
89
0
}
90
91
0
void symbolsUsed(const grammar& g, terminal* s, terminalset* ss) {
92
0
  auto sd = g.find(s);
93
0
  if (sd != g.end()) {
94
0
    symbolsUsed(g, sd->second, ss);
95
0
  }
96
0
}
97
98
0
terminalset symbolsUsed(const grammar& g, terminal* s) {
99
0
  terminalset r;
100
0
  symbolsUsed(g, s, &r);
101
0
  return r;
102
0
}
103
104
0
terminalset symbolsUsing(const grammar& g, terminal* s) {
105
0
  terminalset result;
106
0
  terminalset dsyms = definedSymbols(g);
107
108
0
  for (auto *dsym : dsyms) {
109
0
    if (in(s, symbolsUsed(g, dsym))) {
110
0
      result.insert(dsym);
111
0
    }
112
0
  }
113
114
0
  return result;
115
0
}
116
117
0
bool hasRule(const grammar& g, terminal* t) {
118
0
  return g.find(t) != g.end();
119
0
}
120
121
0
const rules* aggRules(const grammar& g, terminal* t) {
122
0
  auto ad = g.find(t);
123
0
  if (ad == g.end()) {
124
0
    throw std::runtime_error("Internal error, no such aggregate defined.");
125
0
  } else {
126
0
    return &(ad->second);
127
0
  }
128
0
}
129
130
0
const rule& nthRule(const rules* rs, nat n) {
131
0
  if (n >= rs->size()) {
132
0
    throw std::runtime_error("Internal error, no such rule.");
133
0
  } else {
134
0
    return (*rs)[n];
135
0
  }
136
0
}
137
138
0
terminal* ruleElement(const rule& r, nat i) {
139
0
  if (i >= r.size()) {
140
0
    return nullptr;
141
0
  } else {
142
0
    return r[i];
143
0
  }
144
0
}
145
146
0
bool directlyDerivesNull(const rule& r) {
147
0
  return r.empty();
148
0
}
149
150
0
bool directlyDerivesNull(const grammar& g, terminal* s) {
151
0
  const rules* rs = aggRules(g, s);
152
0
  for (const auto &r : *rs) {
153
0
    if (directlyDerivesNull(r)) {
154
0
      return true;
155
0
    }
156
0
  }
157
0
  return false;
158
0
}
159
160
0
bool derivesNull(const terminalset& nullAggs, const rule& r) {
161
0
  for (auto *v : r) {
162
0
    if (nullAggs.find(v) == nullAggs.end()) {
163
0
      return false;
164
0
    }
165
0
  }
166
0
  return true;
167
0
}
168
169
0
bool derivesNull(const grammar& g, const terminalset& nullAggs, terminal* s) {
170
0
  const rules* rs = aggRules(g, s);
171
0
  for (const auto & r : *rs) {
172
0
    if (derivesNull(nullAggs, r)) {
173
0
      return true;
174
0
    }
175
0
  }
176
0
  return false;
177
0
}
178
179
0
bool derivesNull(const grammar& g, const terminalset& nullAggs, const terminals& ss) {
180
0
  for (auto *s : ss) {
181
0
    if (!derivesNull(g, nullAggs, s)) {
182
0
      return false;
183
0
    }
184
0
  }
185
0
  return true;
186
0
}
187
188
0
bool derivesNull(const parserdef& p, terminal* s) {
189
0
  return p.nullable.find(s) != p.nullable.end();
190
0
}
191
192
// the least set of defined symbols with a rule all of whose symbols are in the set
193
//   (found from a worklist: each rule counts its symbols not yet known to derive null, and is
194
//    told as each becomes known, so each rule is visited once per symbol in it. Passing over all
195
//    of the symbols until none changed took time quadratic in a chain of them, A_i -> A_i+1,
196
//    which each pass could advance by just one)
197
0
terminalset symbolsDerivingNull(const grammar& g) {
198
0
  terminalset nulls;
199
200
0
  std::vector<std::pair<terminal*, size_t>> unknowns; // for each rule, its symbol and how many of its symbols aren't known to derive null
201
0
  std::map<terminal*, std::vector<size_t>>  uses;     // for each symbol, the rules it appears in (once for each time)
202
0
  std::vector<terminal*>                    known;    // symbols known to derive null, whose uses are still to be told
203
204
0
  for (const auto& sd : g) {
205
0
    for (const auto& r : sd.second) {
206
0
      size_t i = unknowns.size();
207
0
      unknowns.push_back(std::make_pair(sd.first, r.size()));
208
0
      for (auto* v : r) {
209
0
        uses[v].push_back(i);
210
0
      }
211
0
      if (r.empty() && nulls.insert(sd.first).second) {
212
0
        known.push_back(sd.first);
213
0
      }
214
0
    }
215
0
  }
216
217
0
  while (!known.empty()) {
218
0
    terminal* v = known.back();
219
0
    known.pop_back();
220
221
0
    auto u = uses.find(v);
222
0
    if (u != uses.end()) {
223
0
      for (size_t i : u->second) {
224
0
        if (--unknowns[i].second == 0 && nulls.insert(unknowns[i].first).second) {
225
0
          known.push_back(unknowns[i].first);
226
0
        }
227
0
      }
228
0
    }
229
0
  }
230
0
  return nulls;
231
0
}
232
233
/*
234
 * LR(0) parser determination
235
 */
236
0
item::item(terminal* agg, nat p, nat r, const terminalset& la) : agg(agg), p(p), r(r), la(la) { }
237
238
0
bool item::operator<(const item& rhs) const {
239
0
  if (this->agg != rhs.agg) {
240
0
    return this->agg < rhs.agg;
241
0
  } else if (this->p != rhs.p) {
242
0
    return this->p < rhs.p;
243
0
  } else {
244
0
    return this->r < rhs.r;
245
0
  }
246
0
}
247
248
0
bool item::operator==(const item& rhs) const {
249
0
  return this->agg == rhs.agg &&
250
0
       this->p   == rhs.p   &&
251
0
       this->r   == rhs.r;
252
0
}
253
254
0
void show(std::ostream& out, const grammar& g, const item& i) {
255
0
  i.agg->show(out);
256
0
  out << " -> ";
257
0
  const rule& r = nthRule(aggRules(g, i.agg), i.r);
258
0
  for (nat k = 0; k < r.size(); ++k) {
259
0
    if (k == i.p) {
260
0
      out << "#";
261
0
    }
262
0
    r[k]->show(out);
263
0
  }
264
0
  if (i.p == r.size()) {
265
0
    out << "#";
266
0
    out << " [";
267
0
    if (!i.la.empty()) {
268
0
      auto lat = i.la.begin();
269
0
      (*lat)->show(out);
270
0
      ++lat;
271
0
      while (lat != i.la.end()) {
272
0
        out << ", ";
273
0
        (*lat)->show(out);
274
0
        ++lat;
275
0
      }
276
0
    }
277
0
    out << "]";
278
0
  }
279
0
  out << std::endl;
280
0
}
281
282
0
void show(std::ostream& out, const grammar& g, const itemset& is) {
283
0
  for (const auto &i : is) {
284
0
    show(out, g, i);
285
0
  }
286
0
}
287
288
0
bool ruleItems(const grammar& g, terminal* t, itemset* is) {
289
0
  bool         inserted = false;
290
0
  const rules* rs       = aggRules(g, t);
291
292
0
  for (nat r = 0; r < rs->size(); ++r) {
293
0
    inserted |= is->insert(item(t, 0, r)).second;
294
0
  }
295
296
0
  return inserted;
297
0
}
298
299
0
itemset ruleItems(const grammar& g, terminal* t) {
300
0
  itemset is;
301
0
  ruleItems(g, t, &is);
302
0
  return is;
303
0
}
304
305
0
item succ(const item& i) {
306
0
  return item(i.agg, i.p+1, i.r, i.la);
307
0
}
308
309
0
terminal* next(const grammar& g, const item& i) {
310
0
  return ruleElement(nthRule(aggRules(g, i.agg), i.r), i.p);
311
0
}
312
313
0
terminalset next(const grammar& g, const itemset& is) {
314
0
  terminalset r;
315
0
  for (const auto &i : is) {
316
0
    if (terminal* t = next(g, i)) {
317
0
      r.insert(t);
318
0
    }
319
0
  }
320
0
  return r;
321
0
}
322
323
0
terminalset nextPrim(const grammar& g, const itemset& is) {
324
0
  terminalset r;
325
0
  for (const auto &i : is) {
326
0
    if (terminal* v = next(g, i)) {
327
0
      if (!hasRule(g, v)) {
328
0
        r.insert(v);
329
0
      }
330
0
    }
331
0
  }
332
0
  return r;
333
0
}
334
335
0
itemset follow(const grammar& g, const itemset& is, terminal* v) {
336
0
  itemset r;
337
0
  for (const auto &i : is) {
338
0
    if (next(g, i) == v) {
339
0
      r.insert(succ(i));
340
0
    }
341
0
  }
342
0
  return r;
343
0
}
344
345
0
itemsets follow(const grammar& g, const itemset& is, const terminals& vs) {
346
0
  itemsets r;
347
0
  for (auto *v : vs) {
348
0
    r.push_back(follow(g, is, v));
349
0
  }
350
0
  return r;
351
0
}
352
353
0
void gclosure(const grammar& g, itemset* is) {
354
  // add implied items to a fixed point
355
  //   (each nonterminal is expanded once, and only the items it adds are looked at again,
356
  //    rather than the whole set once per round)
357
0
  terminalset              expanded;
358
0
  std::vector<const item*> pending;
359
0
  for (const auto& i : *is) {
360
0
    pending.push_back(&i);
361
0
  }
362
363
0
  while (!pending.empty()) {
364
0
    terminal* t = next(g, *pending.back());
365
0
    pending.pop_back();
366
367
0
    if ((t != nullptr) && hasRule(g, t) && expanded.insert(t).second) {
368
0
      const rules* rs = aggRules(g, t);
369
0
      for (nat r = 0; r < rs->size(); ++r) {
370
0
        auto ins = is->insert(item(t, 0, r));
371
0
        if (ins.second) {
372
0
          pending.push_back(&(*ins.first));
373
0
        }
374
0
      }
375
0
    }
376
0
  }
377
0
}
378
379
0
itemset gclosure(const grammar& g, const itemset& is) {
380
0
  itemset r = is;
381
0
  gclosure(g, &r);
382
0
  return r;
383
0
}
384
385
0
nat parserState(const itemset& s, parserdef* p) {
386
0
  parser_states::const_iterator si = p->states.find(s);
387
0
  if (si != p->states.end()) {
388
0
    return si->second;
389
0
  } else {
390
0
    nat n = p->states.size();
391
0
    p->states    [s] = n;
392
0
    p->state_defs[n] = s;
393
0
    return n;
394
0
  }
395
0
}
396
397
0
const itemset& parserStateDef(const parserdef& p, nat n) {
398
0
  auto sd = p.state_defs.find(n);
399
0
  if (sd == p.state_defs.end()) {
400
0
    throw std::runtime_error("Internal error, invalid state referenced.");
401
0
  } else {
402
0
    return sd->second;
403
0
  }
404
0
}
405
406
parser_too_large::parser_too_large(limit l, size_t bound) :
407
0
  std::runtime_error(
408
0
    l == limit::items     ? "parser states hold more than " + std::to_string(bound) + " items" :
409
0
    l == limit::lookahead ? "parser lookahead takes more than " + std::to_string(bound) + " steps" :
410
0
                            "parser states' stack depths sum to more than " + std::to_string(bound)),
411
0
  l(l), b(bound) {
412
0
}
413
0
parser_too_large::limit parser_too_large::which() const { return this->l; }
414
0
size_t parser_too_large::bound() const { return this->b; }
415
416
namespace {
417
418
// counts the size of an LR(0) parser as its states are made, giving up once it is past its limits
419
//   (checked as each state is made, not as it is visited: a state can have as many successors
420
//    as the grammar has rules, each of them as large as the grammar, so the parser can grow
421
//    quadratically in the grammar before the next state is visited)
422
class lr0budget {
423
public:
424
0
  explicit lr0budget(const parserlimits& limits) : limits(limits) { }
425
426
  // the state reached from a kernel of items (the successors of some state's items on one symbol)
427
  //   (a state is found by its kernel before its closure is made: many states can reach one
428
  //    state, and making its closure again for each of them took time quadratic in the grammar;
429
  //    a kernel's items have all read something, and its closure adds only items that haven't,
430
  //    so kernels and the states made from them determine each other)
431
0
  nat successor(const grammar& g, itemset* kernel, parserdef* p) {
432
0
    auto k = this->kernels.find(*kernel);
433
0
    if (k != this->kernels.end()) {
434
0
      return k->second;
435
0
    }
436
0
    itemset ks = *kernel;
437
0
    gclosure(g, kernel);
438
0
    nat r = state(*kernel, p);
439
0
    this->kernels[std::move(ks)] = r;
440
0
    return r;
441
0
  }
442
443
0
  nat state(const itemset& s, parserdef* p) {
444
0
    size_t n = p->states.size();
445
0
    nat    r = parserState(s, p);
446
0
    if (p->states.size() != n) {
447
0
      nat d = 0;
448
0
      for (const auto& i : s) {
449
0
        d = std::max(d, i.p);
450
0
      }
451
0
      this->depthSum += d;
452
0
      this->items    += s.size();
453
454
0
      if (this->depthSum > this->limits.maxStackDepthSum) {
455
0
        throw parser_too_large(parser_too_large::limit::stackDepthSum, this->limits.maxStackDepthSum);
456
0
      }
457
0
      if (this->items > this->limits.maxItems) {
458
0
        throw parser_too_large(parser_too_large::limit::items, this->limits.maxItems);
459
0
      }
460
0
    }
461
0
    return r;
462
0
  }
463
private:
464
  const parserlimits&     limits;
465
  size_t                  depthSum = 0;
466
  size_t                  items    = 0;
467
  std::map<itemset, nat>  kernels;
468
};
469
470
0
state_transitions follow(const grammar& g, const itemset& is, const terminalset& vs, parserdef* p, lr0budget* b) {
471
  // sort the items by the symbol they expect in one pass,
472
  // rather than passing over all of them for each symbol
473
0
  std::map<terminal*, itemset> succs;
474
0
  for (const auto& i : is) {
475
0
    terminal* v = next(g, i);
476
0
    if (v != nullptr && vs.count(v) != 0) {
477
0
      succs[v].insert(succ(i));
478
0
    }
479
0
  }
480
481
  // and number the states they make in the order of vs
482
0
  state_transitions r;
483
0
  for (auto *v : vs) {
484
0
    if (v != endOfFile::value()) {
485
0
      r[v] = b->successor(g, &succs[v], p);
486
0
    }
487
0
  }
488
0
  return r;
489
0
}
490
491
}
492
493
0
state_transitions follow(const grammar& g, const itemset& is, const terminalset& vs, parserdef* p) {
494
0
  static const parserlimits unlimited;
495
0
  lr0budget b(unlimited);
496
0
  return follow(g, is, vs, p, &b);
497
0
}
498
499
0
parserdef lr0parser(const grammar& g, terminal* s) {
500
0
  return lr0parser(g, s, parserlimits());
501
0
}
502
503
0
parserdef lr0parser(const grammar& g, terminal* s, const parserlimits& limits) {
504
0
  parserdef p;
505
0
  lr0budget b(limits);
506
507
  // tweak this grammar to have a boot rule
508
  // s' -> s $
509
0
  p.g = g;
510
0
  p.s = s;
511
512
0
  static symbol privstart(".S");
513
0
  terminal* boot = &privstart;
514
0
  rule br; br.push_back(s); br.push_back(endOfFile::value());
515
0
  p.g[boot].push_back(br);
516
517
  // enumerate the state space implied by this grammar
518
0
  nat n = b.state(gclosure(p.g, ruleItems(p.g, boot)), &p);
519
0
  while (n < p.states.size()) {
520
0
    const itemset& nis = parserStateDef(p, n);
521
0
    p.transitions[n] = follow(p.g, nis, next(p.g, nis), &p, &b);
522
0
    ++n;
523
0
  }
524
0
  p.nullable = symbolsDerivingNull(p.g);
525
0
  return p;
526
0
}
527
528
/*
529
 * Relations on the LR(0) parser and LALR(1) determination
530
 */
531
532
0
transitionset transitions(const parserdef& p) {
533
0
  transitionset r;
534
0
  for (auto pst = p.transitions.begin(); pst != p.transitions.end(); ++pst) {
535
0
    for (auto st = pst->second.begin(); st != pst->second.end(); ++st) {
536
0
      if (hasRule(p.g, st->first)) {
537
0
        r.insert(transition(pst->first, st->first));
538
0
      }
539
0
    }
540
0
  }
541
0
  return r;
542
0
}
543
544
0
const state_transitions& transitions(const parserdef& p, nat q) {
545
0
  auto r = p.transitions.find(q);
546
0
  if (r == p.transitions.end()) {
547
0
    throw std::runtime_error("Internal error, invalid state given for finding transitions.");
548
0
  } else {
549
0
    return r->second;
550
0
  }
551
0
}
552
553
0
bool follows(const state_transitions& st, terminal* t) {
554
0
  return st.find(t) != st.end();
555
0
}
556
557
0
bool follows(const parserdef& p, nat q, terminal* t) {
558
0
  return follows(transitions(p, q), t);
559
0
}
560
561
0
nat follow(const state_transitions& st, terminal* t) {
562
0
  auto x = st.find(t);
563
0
  if (x == st.end()) {
564
0
    throw std::runtime_error("Internal error, invalid symbol given for determining state transition.");
565
0
  } else {
566
0
    return x->second;
567
0
  }
568
0
}
569
570
0
nat follow(const parserdef& p, nat q, terminal* t) {
571
0
  return follow(transitions(p, q), t);
572
0
}
573
574
0
nat follow(const parserdef& p, const transition& x) {
575
0
  return follow(p, x.first, x.second);
576
0
}
577
578
0
nat follow(const parserdef& p, nat s, const terminals& ts) {
579
0
  nat r = s;
580
0
  for (auto *t : ts) {
581
0
    r = follow(p, r, t);
582
0
  }
583
0
  return r;
584
0
}
585
586
// check if a transition "looks back" to a state where a given rule has been completed
587
0
bool lookback(const parserdef& p, nat q, terminal* r, const rule& w, const transition& t) {
588
0
  if (t.second != r) {
589
0
    return false;
590
0
  } else {
591
0
    nat s = t.first;
592
0
    for (auto *t : w) {
593
0
      const state_transitions& st = transitions(p, s);
594
0
      if (follows(st, t)) {
595
0
        s = follow(st, t);
596
0
      } else {
597
0
        return false;
598
0
      }
599
0
    }
600
0
    return s == q;
601
0
  }
602
0
}
603
604
// for a rule w and sym A, find all prefixes b such that w = bAs, s =>* eps
605
using prefixes = std::vector<terminals>;
606
607
0
prefixes endingAt(const parserdef& p, const rule& w, terminal* a) {
608
0
  prefixes r;
609
0
  nat i = w.size();
610
0
  while (i > 0) {
611
0
    --i;
612
613
0
    if (w[i] == a) {
614
0
      r.push_back(terminals(w.begin(), w.begin() + i));
615
0
    }
616
0
    if (!derivesNull(p, w[i])) {
617
0
      break;
618
0
    }
619
0
  }
620
0
  return r;
621
0
}
622
623
// x=(s,A) includes y=(s',B) if B -> wAg, g =>* eps, and s' --w--> s
624
0
bool includes(const parserdef& p, const transition& x, const transition& y) {
625
0
  const rules* rs = aggRules(p.g, y.second);
626
0
  for (const auto &r : *rs) {
627
0
    prefixes pr = endingAt(p, r, x.second);
628
0
    for (const auto & pfx : pr) {
629
0
      if (follow(p, y.first, pfx) == x.first) {
630
0
        return true;
631
0
      }
632
0
    }
633
0
  }
634
0
  return false;
635
0
}
636
637
// (s,A) reads (s',B) if s --A--> s' and B =>* eps
638
0
bool reads(const parserdef& p, const transition& x, const transition& y) {
639
0
  return follow(p, x) == y.first && derivesNull(p, y.second);
640
0
}
641
642
// from x=(s,A), find all non-aggregate terminals immediately expected after transitioning from state s to s' along A
643
0
terminalset directReads(const parserdef& p, const transition& x) {
644
0
  return nextPrim(p.g, parserStateDef(p, follow(p, x)));
645
0
}
646
647
// the relations above (reads, includes, lookback) define LALR(1) lookahead,
648
// but deciding them one pair at a time costs a search over every pair of
649
// transitions (and, for lookback, over every completed item besides): more
650
// than a minute, under a sanitizer, for a `parse {}` grammar of a few
651
// thousand states (OSS-Fuzz 571908642).
652
// The edges of each relation can instead be built forward from each
653
// transition, as DeRemer and Pennello do, in time linear in the size of the
654
// LR(0) parser, which is what the functions below do.
655
namespace {
656
657
// the nonterminal transitions of a parser, numbered in the order of a
658
// transitionset, with each relation as a list of edges between those numbers
659
struct transitionIndex {
660
  std::vector<transition> ts;
661
  std::map<transition, nat> idx;
662
663
0
  explicit transitionIndex(const transitionset& xs) : ts(xs.begin(), xs.end()) {
664
0
    for (nat i = 0; i < this->ts.size(); ++i) {
665
0
      this->idx[this->ts[i]] = i;
666
0
    }
667
0
  }
668
669
  // the number of a transition, or ts.size() if it isn't one
670
0
  nat find(nat s, terminal* t) const {
671
0
    auto i = this->idx.find(transition(s, t));
672
0
    return (i == this->idx.end()) ? static_cast<nat>(this->ts.size()) : i->second;
673
0
  }
674
};
675
676
// counts the steps taken to find a parser's lookahead (terminals copied and merged, rule walks
677
// and edges), giving up once there are too many
678
//   (the sets are as many as its transitions and items, each as large as its terminals, so their
679
//    size can be quadratic in a grammar that passes the bounds on its LR(0) states; and they are
680
//    merged along each edge of the relations, so the time to make them can be cubic. Each copy
681
//    and merge is counted, whether or not it adds anything, so this bounds the time as well as
682
//    the size, which can't be more than what was copied and merged into it; and the walks along
683
//    rules that find the relations' edges are counted as well, as there can be as many of those
684
//    as transitions on a nonterminal times the length of its rules)
685
class lookaheadBudget {
686
public:
687
0
  explicit lookaheadBudget(size_t limit) : limit(limit) { }
688
689
0
  void count(size_t k) {
690
0
    this->n += k;
691
0
    if (this->n > this->limit) {
692
0
      throw parser_too_large(parser_too_large::limit::lookahead, this->limit);
693
0
    }
694
0
  }
695
696
0
  void assign(terminalset* s, const terminalset& ts) {
697
0
    count(ts.size());
698
0
    *s = ts;
699
0
  }
700
701
0
  void insert(terminalset* s, const terminalset& ts) {
702
0
    count(ts.size());
703
0
    s->insert(ts.begin(), ts.end());
704
0
  }
705
private:
706
  size_t limit;
707
  size_t n = 0;
708
};
709
710
using edges = std::vector<std::vector<nat>>;
711
712
// list each node's edges in transitionset order, without repeats
713
0
void normalize(edges* es) {
714
0
  for (auto& e : *es) {
715
0
    std::sort(e.begin(), e.end());
716
0
    e.erase(std::unique(e.begin(), e.end()), e.end());
717
0
  }
718
0
}
719
720
// (s,A) reads (s',B) if s --A--> s' and B =>* eps
721
//   (which depends only on s', so the edges are found once for each state that transitions lead
722
//    to, rather than once for each transition: many transitions can lead to one state, which can
723
//    have many transitions out of it)
724
0
edges readsEdges(const parserdef& p, const transitionIndex& ti) {
725
0
  edges r(p.states.size());
726
0
  std::vector<bool> done(p.states.size(), false);
727
0
  for (const auto& x : ti.ts) {
728
0
    nat s = follow(p, x);
729
0
    if (!done[s]) {
730
0
      done[s] = true;
731
0
      for (const auto& st : transitions(p, s)) {
732
0
        if (derivesNull(p, st.first)) {
733
0
          nat y = ti.find(s, st.first);
734
0
          if (y < ti.ts.size()) {
735
0
            r[s].push_back(y);
736
0
          }
737
0
        }
738
0
      }
739
0
    }
740
0
  }
741
0
  normalize(&r);
742
0
  return r;
743
0
}
744
745
// x=(s,A) includes y=(s',B) if B -> wAg, g =>* eps, and s' --w--> s
746
//   so walk each rule of B from s', and take the edge at each A in its nullable tail
747
0
edges includesEdges(const parserdef& p, const transitionIndex& ti, lookaheadBudget* b) {
748
0
  edges r(ti.ts.size());
749
0
  std::vector<nat> path;
750
0
  for (nat y = 0; y < ti.ts.size(); ++y) {
751
0
    for (const auto& w : *aggRules(p.g, ti.ts[y].second)) {
752
      // the states before each symbol (but the last, after which nothing is looked for)
753
0
      b->count(w.size() + 1);
754
0
      path.resize(w.size());
755
0
      nat s = ti.ts[y].first;
756
0
      for (nat i = 0; i < w.size(); ++i) {
757
0
        path[i] = s;
758
0
        if (i + 1 < w.size()) {
759
0
          s = follow(p, s, w[i]);
760
0
        }
761
0
      }
762
763
0
      for (nat i = w.size(); i > 0;) {
764
0
        --i;
765
0
        nat x = ti.find(path[i], w[i]);
766
0
        if (x < ti.ts.size()) {
767
0
          b->count(1);
768
0
          r[x].push_back(y);
769
0
        }
770
0
        if (!derivesNull(p, w[i])) {
771
0
          break;
772
0
        }
773
0
      }
774
0
    }
775
0
  }
776
0
  normalize(&r);
777
0
  return r;
778
0
}
779
780
781
// for each x, f(x) = fp(x) + sum(f(y) | x R y), as digraphF computes it
782
// (visiting nodes and edges in the same order, so with the same result),
783
// but with R given as edges, and without recursion: an edge chain can be as
784
// long as the parser has transitions.
785
//
786
// Many nodes can share one fp and one list of edges (all of the transitions
787
// to one state, for reads). Once one of them is done, having read only values
788
// that were themselves done (none of its edges went back into the stack), its
789
// value is what any other node with the same fp and edges would compute, so
790
// that is used rather than visiting the same edges again for each of them.
791
0
transition_lookahead digraph(const transitionIndex& ti, const std::vector<const terminalset*>& fp, const std::vector<const std::vector<nat>*>& es, lookaheadBudget* b) {
792
0
  static const nat inf = static_cast<nat>(-1);
793
794
0
  nat                      n = ti.ts.size();
795
0
  std::vector<nat>         depth(n, 0);
796
0
  std::vector<terminalset> f(n);
797
0
  std::vector<nat>         stack;
798
799
0
  using shape = std::pair<const terminalset*, const std::vector<nat>*>;
800
0
  std::map<shape, nat> doneShapes;
801
802
0
  struct frame { nat x; nat d; nat e; bool partial; };
803
0
  std::vector<frame> frames;
804
805
0
  auto enter = [&](nat x) {
806
0
    stack.push_back(x);
807
0
    nat d = stack.size();
808
0
    depth[x] = d;
809
810
0
    auto ds = doneShapes.find(shape(fp[x], es[x]));
811
0
    if (ds != doneShapes.end()) {
812
0
      b->assign(&f[x], f[ds->second]);
813
0
      frames.push_back(frame{x, d, static_cast<nat>(es[x]->size()), false});
814
0
    } else {
815
0
      b->assign(&f[x], *fp[x]);
816
0
      frames.push_back(frame{x, d, 0, false});
817
0
    }
818
0
  };
819
820
0
  for (nat root = 0; root < n; ++root) {
821
0
    if (depth[root] != 0) {
822
0
      continue;
823
0
    }
824
0
    enter(root);
825
826
0
    while (!frames.empty()) {
827
0
      frame& fr = frames.back();
828
0
      const auto& e = *es[fr.x];
829
830
0
      if (fr.e < e.size()) {
831
0
        nat y = e[fr.e];
832
0
        if (depth[y] == 0) {
833
          // visit y first, then come back to this edge to add in its value
834
0
          enter(y);
835
0
        } else {
836
0
          if (depth[y] != inf) {
837
0
            fr.partial = true; // y is still in the stack, so its value isn't done
838
0
          }
839
0
          b->insert(&f[fr.x], f[y]);
840
0
          ++fr.e;
841
0
        }
842
0
        continue;
843
0
      }
844
845
      // join all the nodes in this SCC
846
0
      nat  x       = fr.x;
847
0
      bool partial = fr.partial;
848
0
      if (depth[x] == fr.d) {
849
0
        while (true) {
850
0
          nat cx = stack.back();
851
0
          stack.pop_back();
852
0
          depth[cx] = inf;
853
0
          if (cx == x) {
854
0
            break;
855
0
          } else {
856
0
            b->assign(&f[cx], f[x]);
857
0
          }
858
0
        }
859
0
      }
860
0
      frames.pop_back();
861
0
      if (!partial) {
862
0
        doneShapes.insert(std::make_pair(shape(fp[x], es[x]), x));
863
0
      }
864
865
      // and add this node's value to the edge that led here
866
0
      if (!frames.empty()) {
867
0
        frame& pr = frames.back();
868
0
        b->insert(&f[pr.x], f[x]);
869
0
        ++pr.e;
870
0
      }
871
0
    }
872
0
  }
873
874
0
  transition_lookahead r;
875
0
  for (nat x = 0; x < n; ++x) {
876
0
    r[ti.ts[x]] = std::move(f[x]);
877
0
  }
878
0
  return r;
879
0
}
880
881
0
transition_lookahead Reads(const parserdef& p, const transitionIndex& ti, lookaheadBudget* b) {
882
  // the terminals read directly after a transition, and the transitions it reads,
883
  // depend only on the state that it leads to, so are found once for each such state
884
0
  std::vector<terminalset> drs(p.states.size());
885
0
  std::vector<bool>        done(p.states.size(), false);
886
0
  edges                    res = readsEdges(p, ti);
887
888
0
  std::vector<const terminalset*>      dr(ti.ts.size());
889
0
  std::vector<const std::vector<nat>*> es(ti.ts.size());
890
0
  for (nat x = 0; x < ti.ts.size(); ++x) {
891
0
    nat s = follow(p, ti.ts[x]);
892
0
    if (!done[s]) {
893
0
      done[s] = true;
894
0
      drs[s]  = directReads(p, ti.ts[x]);
895
0
    }
896
0
    dr[x] = &drs[s];
897
0
    es[x] = &res[s];
898
0
  }
899
0
  return digraph(ti, dr, es, b);
900
0
}
901
902
0
transition_lookahead Follow(const parserdef& p, const transitionIndex& ti, lookaheadBudget* b) {
903
0
  transition_lookahead rs = Reads(p, ti, b);
904
0
  std::vector<terminalset> rds;
905
0
  rds.reserve(ti.ts.size());
906
0
  for (const auto& x : ti.ts) {
907
0
    rds.push_back(std::move(rs[x]));
908
0
  }
909
0
  rs.clear();
910
911
0
  edges ies = includesEdges(p, ti, b);
912
0
  std::vector<const terminalset*>      fp(ti.ts.size());
913
0
  std::vector<const std::vector<nat>*> es(ti.ts.size());
914
0
  for (nat x = 0; x < ti.ts.size(); ++x) {
915
0
    fp[x] = &rds[x];
916
0
    es[x] = &ies[x];
917
0
  }
918
0
  return digraph(ti, fp, es, b);
919
0
}
920
921
// (q, A -> w.) looks back to (s,A) when s --w--> q, so walk each rule of A from s
922
//   (counting each walk, as includesEdges does)
923
0
void apply(const transition_lookahead& tl, parserdef* p, lookaheadBudget* b) {
924
0
  std::vector<itemset*> states(p->states.size(), nullptr);
925
0
  for (auto& s : p->states) {
926
0
    if (s.second < states.size()) {
927
0
      states[s.second] = const_cast<itemset*>(&s.first);
928
0
    }
929
0
  }
930
931
0
  for (const auto& tli : tl) {
932
0
    terminal*    a  = tli.first.second;
933
0
    const rules* rs = aggRules(p->g, a);
934
0
    for (nat r = 0; r < rs->size(); ++r) {
935
0
      const rule& w = (*rs)[r];
936
0
      b->count(w.size() + 1);
937
0
      nat  q  = tli.first.first;
938
0
      bool ok = true;
939
0
      for (auto* t : w) {
940
0
        const state_transitions& st = transitions(*p, q);
941
0
        auto n = st.find(t);
942
0
        if (n == st.end()) {
943
0
          ok = false;
944
0
          break;
945
0
        }
946
0
        q = n->second;
947
0
      }
948
0
      if (!ok || q >= states.size() || states[q] == nullptr) {
949
0
        continue;
950
0
      }
951
952
0
      auto i = states[q]->find(item(a, w.size(), r));
953
0
      if (i != states[q]->end()) {
954
0
        b->insert(&const_cast<item*>(&(*i))->la, tli.second);
955
0
      }
956
0
    }
957
0
  }
958
0
}
959
960
}
961
962
// compute Read(x=(s,A)) = directReads(s,A) + (Read(q,B) | (s,A) reads (q,B))
963
0
transition_lookahead Reads(const parserdef& p, const transitionset& ts) {
964
0
  lookaheadBudget b(static_cast<size_t>(-1));
965
0
  return Reads(p, transitionIndex(ts), &b);
966
0
}
967
968
// compute Follow(x=(s,A)) = Read((s,A)) + (Follow(q,B) | (s,A) includes (q,B))
969
0
transition_lookahead Follow(const parserdef& p, const transitionset& ts) {
970
0
  lookaheadBudget b(static_cast<size_t>(-1));
971
0
  return Follow(p, transitionIndex(ts), &b);
972
0
}
973
974
// apply transition lookahead to every applicable completed item in an LR(0) parser
975
0
void apply(const transition_lookahead& tl, parserdef* p) {
976
0
  lookaheadBudget b(static_cast<size_t>(-1));
977
0
  apply(tl, p, &b);
978
0
}
979
980
// determine the LALR(1) parser definition
981
0
void lalr1lookahead(parserdef* p) {
982
0
  lalr1lookahead(p, parserlimits());
983
0
}
984
985
0
void lalr1lookahead(parserdef* p, const parserlimits& limits) {
986
0
  lookaheadBudget b(limits.maxLookahead);
987
0
  apply(Follow(*p, transitionIndex(transitions(*p)), &b), p, &b);
988
0
}
989
990
0
parserdef lalr1parser(const grammar& g, terminal* s) {
991
0
  parserdef p = lr0parser(g, s);
992
0
  lalr1lookahead(&p);
993
0
  return p;
994
0
}
995
996
0
terminal* reduceOpTerminal(const parserdef& pd, const action& a) {
997
0
  const rule& r = nthRule(aggRules(pd.g, a.reduceSym()), a.reduceRule());
998
0
  for (auto e = r.rbegin(); e != r.rend(); ++e) {
999
0
    if (!hasRule(pd.g, *e)) {
1000
0
      return *e;
1001
0
    }
1002
0
  }
1003
0
  return nullptr;
1004
0
}
1005
1006
0
bool shiftInstead(const parserdef& pd, const precedence& px, nat, terminal* t, const action& a) {
1007
0
  terminal* u = reduceOpTerminal(pd, a);
1008
1009
0
  if (u == nullptr) {
1010
0
    throw ambiguity_conflict("Unable to resolve shift/reduce conflict in grammar", t);
1011
0
  }
1012
1013
0
  auto tp = px.find(t);
1014
0
  auto up = px.find(u);
1015
1016
0
  if (tp == px.end() || up == px.end()) {
1017
0
    throw ambiguity_conflict("Unable to resolve shift/reduce conflict in grammar", t);
1018
0
  }
1019
1020
0
  if (tp->second.level < up->second.level) {
1021
0
    return false;
1022
0
  } else if (up->second.level < tp->second.level) {
1023
0
    return true;
1024
0
  } else if (tp->second.asc == up->second.asc && tp->second.asc != assoc::non) {
1025
0
    return tp->second.asc != assoc::left;
1026
0
  } else {
1027
0
    throw ambiguity_conflict("Unable to resolve shift/reduce conflict in grammar", t);
1028
0
  }
1029
0
}
1030
1031
// determine the LALR(1) table to drive an LR parser
1032
0
lrtable lalrTable(const grammar& g, terminal* s, const precedence& px) {
1033
0
  return lalrTable(lalr1parser(g, s), px);
1034
0
}
1035
1036
0
void addAction(const parserdef& pd, lrstate& s, terminal* t, const action& a, const precedence& px) {
1037
0
  auto sc = s.find(t);
1038
0
  if (sc == s.end()) {
1039
0
    s.insert(std::make_pair(t, a));
1040
0
  } else if (sc->second != a) {
1041
0
    if (a.isReduce() && sc->second.isReduce()) {
1042
0
      std::ostringstream ss;
1043
0
      ss << "Conflict between " << a << " and " << sc->second << " on " << show(t);
1044
0
      throw ambiguity_conflict(ss.str(), t);
1045
0
    } else if (a.isShift()) {
1046
0
      if (shiftInstead(pd, px, a.shiftState(), t, sc->second)) {
1047
0
        sc->second = a;
1048
0
      }
1049
0
    } else {
1050
0
      if (!shiftInstead(pd, px, sc->second.shiftState(), t, a)) {
1051
0
        sc->second = a;
1052
0
      }
1053
0
    }
1054
0
  }
1055
0
}
1056
1057
0
void addAccept(lrstate& s, terminal* t) {
1058
0
  s.insert(std::make_pair(t, action::accept()));
1059
0
}
1060
1061
0
void addReduce(const parserdef& pd, lrstate& s, const terminalset& ts, terminal* agg, nat rule, nat len, const precedence& px) {
1062
0
  for (auto *t : ts) {
1063
0
    addAction(pd, s, t, action::reduce(agg, rule, len), px);
1064
0
  }
1065
0
}
1066
1067
0
void addGoto(lrstate& s, terminal* nt, nat next) {
1068
0
  s.insert(std::make_pair(nt, action::goTo(next)));
1069
0
}
1070
1071
0
void addShift(const parserdef& pd, lrstate& s, terminal* t, nat next, const precedence& px) {
1072
0
  addAction(pd, s, t, action::shift(next), px);
1073
0
}
1074
1075
0
lrtable lalrTable(const parserdef& p, const precedence& px) {
1076
0
  lrtable r;
1077
0
  r.resize(p.states.size());
1078
1079
0
  for (auto s = p.states.begin(); s != p.states.end(); ++s) {
1080
    // each item in this state's set translates to an LR parser action (goto, shift, reduce, or accept)
1081
0
    const itemset& is = s->first;
1082
0
    nat            n  = s->second;
1083
0
    lrstate&       ps = r[n];
1084
1085
    // if we fail to compile a table row, report the itemset that failed
1086
0
    try {
1087
0
      for (const auto & i : is) {
1088
0
        terminal* t = next(p.g, i);
1089
  
1090
0
        if (t == nullptr) {
1091
          // reduce
1092
0
          addReduce(p, ps, i.la, i.agg, i.r, i.p, px);
1093
0
        } else if (hasRule(p.g, t)) {
1094
          // goto
1095
0
          addGoto(ps, t, follow(p, n, t));
1096
0
        } else if (t == endOfFile::value()) {
1097
          // accept
1098
0
          addAccept(ps, t);
1099
0
        } else {
1100
          // shift
1101
0
          addShift(p, ps, t, follow(p, n, t), px);
1102
0
        }
1103
0
      }
1104
0
    } catch (ambiguity_conflict& ex) {
1105
0
      throw compile_table_failure(ex.what(), p.g, is, ex.failedTerminal());
1106
0
    }
1107
0
  }
1108
1109
0
  return r;
1110
0
}
1111
1112
0
ambiguity_conflict::ambiguity_conflict(const std::string& ex, terminal* t) noexcept : std::runtime_error(ex), t(t) {
1113
0
}
1114
1115
0
terminal* ambiguity_conflict::failedTerminal() const {
1116
0
  return this->t;
1117
0
}
1118
1119
0
compile_table_failure::compile_table_failure(const std::string& msg, const grammar& g, const itemset& faileditems, terminal* t) noexcept : std::runtime_error(msg), g(g), faileditems(faileditems), t(t) {
1120
0
}
1121
1122
0
const grammar& compile_table_failure::failedGrammar() const {
1123
0
  return this->g;
1124
0
}
1125
1126
0
const itemset& compile_table_failure::failedItems() const {
1127
0
  return this->faileditems;
1128
0
}
1129
1130
0
terminal* compile_table_failure::failedTerminal() const {
1131
0
  return this->t;
1132
0
}
1133
1134
0
inline bool referencesSym(const grammar& g, const item& i, terminal* t) {
1135
0
  return in(t, nthRule(aggRules(g, i.agg), i.r)) || in(t, i.la);
1136
0
}
1137
1138
0
void compile_table_failure::print(std::ostream& out) const {
1139
0
  for (const auto &faileditem : this->faileditems) {
1140
0
    if (referencesSym(this->g, faileditem, this->t)) {
1141
0
      print(out, faileditem);
1142
0
    }
1143
0
  }
1144
0
}
1145
1146
0
void beginHighlight(std::ostream& out) {
1147
0
  static const char bgccmd[] = { 27, '[', '4', '1', 'm' };
1148
0
  static const char fgccmd[] = { 27, '[', '3', '7', 'm' };
1149
1150
0
  out.write(bgccmd, sizeof(bgccmd));
1151
0
  out.write(fgccmd, sizeof(fgccmd));
1152
0
}
1153
1154
0
void endHighlight(std::ostream& out) {
1155
0
  static const char rstcmd[] = { 27, '[', '0',  'm' };
1156
1157
0
  out.write(rstcmd, sizeof(rstcmd));
1158
0
}
1159
1160
0
inline void showHLTerm(std::ostream& out, terminal* x, terminal* hx) {
1161
0
  if (x == hx) {
1162
0
    beginHighlight(out);
1163
0
    x->show(out);
1164
0
    endHighlight(out);
1165
0
  } else {
1166
0
    x->show(out);
1167
0
  }
1168
0
}
1169
1170
0
void compile_table_failure::print(std::ostream& out, const item& i) const {
1171
0
  i.agg->show(out);
1172
0
  out << " ->";
1173
1174
0
  const rule& r = nthRule(aggRules(this->g, i.agg), i.r);
1175
0
  for (nat k = 0; k < r.size(); ++k) {
1176
0
    out << ' ';
1177
0
    if (k == i.p) {
1178
0
      out << '#';
1179
0
      showHLTerm(out, r[k], this->t);
1180
0
    } else {
1181
0
      r[k]->show(out);
1182
0
    }
1183
0
  }
1184
0
  if (i.p == r.size()) {
1185
0
    out << "#";
1186
0
    out << " [";
1187
0
    if (!i.la.empty()) {
1188
0
      auto lat = i.la.begin();
1189
0
      showHLTerm(out, *lat, this->t);
1190
0
      ++lat;
1191
0
      while (lat != i.la.end()) {
1192
0
        out << ", ";
1193
0
        showHLTerm(out, *lat, this->t);
1194
0
        ++lat;
1195
0
      }
1196
0
    }
1197
0
    out << "]";
1198
0
  }
1199
0
  out << std::endl;
1200
0
}
1201
1202
// lr tables / actions
1203
0
action::action() = default;
1204
1205
0
action action::goTo(nat s) {
1206
0
  action a;
1207
0
  a.act = 0;
1208
0
  a.d.s = s;
1209
0
  return a;
1210
0
}
1211
0
bool action::isGoTo()    const { return this->act == 0; }
1212
0
nat  action::goToState() const { return this->d.s; }
1213
1214
0
action action::shift(nat s) {
1215
0
  action a;
1216
0
  a.act = 1;
1217
0
  a.d.s = s;
1218
0
  return a;
1219
0
}
1220
0
bool action::isShift()    const { return this->act == 1; }
1221
0
nat  action::shiftState() const { return this->d.s; }
1222
1223
0
action action::reduce(terminal* x, nat r, nat n) {
1224
0
  action a;
1225
0
  a.act = 2;
1226
0
  a.d.x = x;
1227
0
  a.d.r = r;
1228
0
  a.d.n = n;
1229
0
  return a;
1230
0
}
1231
0
bool      action::isReduce()   const { return this->act == 2; }
1232
0
terminal* action::reduceSym()  const { return this->d.x; }
1233
0
nat       action::reduceRule() const { return this->d.r; }
1234
0
nat       action::reduceSize() const { return this->d.n; }
1235
1236
0
action action::accept() {
1237
0
  action a;
1238
0
  a.act = 3;
1239
0
  return a;
1240
0
}
1241
0
bool action::isAccept() const { return this->act == 3; }
1242
1243
0
std::ostream& action::fmt(std::ostream& out) const {
1244
0
  switch (this->act) {
1245
0
  case 0: out << this->d.s; break;
1246
0
  case 1: out << "s" << this->d.s; break;
1247
0
  case 2: out << "r" << this->d.r; break;
1248
0
  case 3: out << "A"; break;
1249
0
  }
1250
0
  return out;
1251
0
}
1252
1253
0
std::ostream& operator<<(std::ostream& out, const action& act) {
1254
0
  return act.fmt(out);
1255
0
}
1256
1257
0
bool action::operator==(const action& rhs) const {
1258
0
  if (this->act != rhs.act) {
1259
0
    return false;
1260
0
  } else {
1261
0
    switch (this->act) {
1262
0
    default:
1263
0
    case 0: return rhs.d.s == this->d.s;
1264
0
    case 1: return rhs.d.s == this->d.s;
1265
0
    case 2: return rhs.d.x == this->d.x && rhs.d.r == this->d.r && rhs.d.n == this->d.n;
1266
0
    case 3: return true;
1267
0
    }
1268
0
  }
1269
0
}
1270
1271
0
bool action::operator!=(const action& rhs) const {
1272
0
  return !(*this == rhs);
1273
0
}
1274
1275
0
terminalset definedSymbols(const lrtable& t) {
1276
0
  terminalset r;
1277
0
  for (const auto& s : t) {
1278
0
    for (const auto& k : s) {
1279
0
      r.insert(k.first);
1280
0
    }
1281
0
  }
1282
0
  return r;
1283
0
}
1284
1285
0
terminals dispOrd(const terminalset& ts) {
1286
0
  terminals r(ts.begin(), ts.end());
1287
0
  std::sort(r.begin(), r.end(),
1288
0
    [](terminal* a, terminal* b) {
1289
0
      if (a == endOfFile::value()) {
1290
0
        return b != endOfFile::value();
1291
0
      } else if (b == endOfFile::value()) {
1292
0
        return false;
1293
0
      } else if (const character* c = dynamic_cast<character*>(a)) {
1294
0
        if (const character* z = dynamic_cast<character*>(b)) {
1295
0
          return c->value() < z->value();
1296
0
        } else {
1297
0
          return true;
1298
0
        }
1299
0
      } else if (dynamic_cast<character*>(b) != nullptr) {
1300
0
        return false;
1301
0
      } else {
1302
0
        std::ostringstream as, bs;
1303
0
        a->show(as);
1304
0
        b->show(bs);
1305
0
        return as.str() < bs.str();
1306
0
      }
1307
0
    }
1308
0
  );
1309
0
  return r;
1310
0
}
1311
1312
0
void show(std::ostream& out, const lrtable& tbl) {
1313
0
  auto      ts = dispOrd(definedSymbols(tbl));
1314
0
  str::seqs stbl;
1315
0
  for (auto *t : ts) {
1316
0
    stbl.push_back(str::seq());
1317
0
    str::seq& c = stbl.back();
1318
1319
0
    std::ostringstream ss;
1320
0
    t->show(ss);
1321
0
    c.push_back(ss.str());
1322
1323
0
    for (const auto& s : tbl) {
1324
0
      auto ki = s.find(t);
1325
0
      if (ki == s.end()) {
1326
0
        c.push_back("");
1327
0
      } else {
1328
0
        std::ostringstream ss;
1329
0
        ki->second.fmt(ss);
1330
0
        c.push_back(ss.str());
1331
0
      }
1332
0
    }
1333
0
  }
1334
0
  str::printRightAlignedTable(out, stbl);
1335
0
}
1336
1337
}
1338