1 /*
2   Copyright 2002-2006 John Plevyak, All Rights Reserved
3 */
4 module ddparser.write_tables;
5 
6 import ddparser.util;
7 import ddparser.lex;
8 import ddparser.gram;
9 import ddparser.dparse_tables;
10 import ddparser.lr;
11 
12 import std.bitmanip;
13 import std.system;
14 import std.array;
15 import std.algorithm;
16 
17 
18 private struct ScannerBlock { 
19   int state_index; 
20   uint scanner_index; 
21   int block_index; 
22   ScanState*[] chars; 
23   ScanStateTransition*[] transitions; 
24 }
25 
26 private alias VecScannerBlock = Vec!(ScannerBlock*);
27 private alias VecState = Vec!(State*);
28 
29 private int
30 scanner_size(State *s) {
31   if (s.scanner.states.length < 255 && s.scanner.transitions.length < 255)
32     return 1;
33   if (s.scanner.states.length < 32384 && s.scanner.transitions.length < 32384)
34     return 2;
35   return 4;
36 }
37 
38 uint32
39 scanner_block_hash_fn(ScannerBlock *b, int block_size) {
40   uint32 hash = 0;
41   intptr_t i;
42   ScanState*[] sb = b.chars;
43 
44   for (i = 0; i < block_size; i++) {
45     hash *= 17;
46     hash += sb[i] ? sb[i].index + 2 : 1;
47   }
48   return hash;
49 }
50 
51 int
52 scanner_block_cmp_fn(ScannerBlock *a, ScannerBlock *b, int block_size) {
53   intptr_t i;
54   ScanState*[] sa = a.chars;
55   ScanState*[] sb = b.chars;
56     
57   for (i = 0; i < block_size; i++) {
58     if (sa[i] == sb[i])
59       continue;
60     if (!sa[i] || !sb[i])
61       return 1;
62     if (sa[i].index != sb[i].index)
63       return 1;
64   }
65   return 0;
66 }
67 
68 alias ScannerBlockSet = Set!(ScannerBlock*, scanner_block_hash_fn, scanner_block_cmp_fn);
69 
70 uint32
71 trans_scanner_block_hash_fn(ScannerBlock *b, int block_size) {
72   uint32 hash = 0;
73   intptr_t i;
74   ScanStateTransition*[] sb = b.transitions;
75 
76   for (i = 0; i < block_size; i++) {
77     hash *= 3;
78     hash += sb[i] ? sb[i].index + 1 : 0;
79   }
80   return hash;
81 }
82 
83 int
84 trans_scanner_block_cmp_fn(ScannerBlock *a, ScannerBlock *b, int block_size) {
85   intptr_t i;
86   ScanStateTransition*[] sa = a.transitions;
87   ScanStateTransition*[] sb = b.transitions;
88     
89   for (i = 0; i < block_size; i++) {
90     if (sa[i] == sb[i])
91       continue;
92     if (!sa[i] || !sb[i])
93       return 1;
94     if (sa[i].index != sb[i].index)
95       return 1;
96   }
97   return 0;
98 }
99 
100 
101 alias TransScannerBlockSet = Set!(ScannerBlock*, trans_scanner_block_hash_fn, trans_scanner_block_cmp_fn);
102 
103 
104 uint32
105 shift_hash_fn(Action *sa) {
106   return sa.term.index + (sa.kind == ActionKind.ACTION_SHIFT_TRAILING ? 1000000 : 0);
107 }
108 
109 
110 int
111 shift_cmp_fn(Action *sa, Action *sb) {
112   return (sa.term.index != sb.term.index) || (sa.kind != sb.kind);
113 }
114 
115 alias ShiftSet = Set!(Action *, shift_hash_fn, shift_cmp_fn);
116 
117 
118 private void
119 buildScannerData(Grammar *g, ref BuildTables tables) {
120     ScannerBlock *xv, yv;
121     ScannerBlockSet[4] scanner_block_hash;
122     ScannerBlockSet* pscanner_block_hash;
123     TransScannerBlockSet[4] trans_scanner_block_hash;
124     TransScannerBlockSet* ptrans_scanner_block_hash;
125     ShiftSet shift_hash;
126     int k, x, xx;
127 
128     D_Shift*[] allShifts = new D_Shift*[g.terminals.length];
129     D_Shift*[uint] allTShifts;
130 
131     /* shift_actions */
132     for (int i = 0; i < g.terminals.length; i++) {
133         int action_index = -1;
134         Term *t = g.terminals[i];
135         if (t.regex_production) {
136             action_index = t.regex_production.rules[0].action_index;
137         }
138         D_Shift* shift = new D_Shift();
139         shift.symbol = cast(ushort)(t.index + g.productions.length);
140         shift.shift_kind = cast(ubyte)t.scan_kind;
141         shift.op_assoc = cast(ubyte)t.op_assoc;
142         shift.op_priority = t.op_priority;
143         shift.term_priority = t.term_priority;
144         shift.action_index = action_index;
145         shift.speculative_code = tables.spec_code;
146         allShifts[i] = shift;
147         if (t.trailing_context) {
148             shift = new D_Shift();
149             shift.symbol = cast(ushort)(t.index + g.productions.length);
150             shift.shift_kind = D_SCAN_TRAILING;
151             shift.op_assoc = cast(ubyte)t.op_assoc;
152             shift.op_priority = t.op_priority;
153             shift.term_priority = t.term_priority;
154             shift.action_index = action_index;
155             shift.speculative_code = tables.spec_code;
156             allTShifts[i] = shift;
157         }
158     }
159     /* scanners */
160     size_t nvsblocks = 0;
161     foreach (i; g.states)
162         nvsblocks += i.scanner.states.length * g.scanner_blocks;
163     ScannerBlock[] vsblock = new ScannerBlock[nvsblocks ? nvsblocks : 1];
164 
165     /* shift */
166     int ivsblock = 0;
167 
168     TableMap!(D_Shift*[], 2) tables_d_accepts_diff2;
169     TableMap!(D_Shift *[], 2) tables_d_shift2;
170     TableMap!(ubyte[], 3) tables_d_accepts_diff3;
171     TableMap!(ubyte[], 3) tables_d_scanner3;
172 
173     for (int i = 0; i < g.states.length; i++) {
174         State *s = g.states[i];
175         if (s.same_shifts)
176             continue;
177         auto ss = s.scanner.states;
178 
179         /* build accepts differences */
180         for (int j = 0; j < s.scanner.transitions.n; j++) {
181             D_Shift*[] d_accepts_diff2;
182             foreach (k; s.scanner.transitions[j].accepts_diff) {
183                 if (k.kind != ActionKind.ACTION_SHIFT_TRAILING)
184                     d_accepts_diff2 ~= allShifts[k.term.index];
185                 else
186                     d_accepts_diff2 ~= allTShifts[k.term.index];
187             }
188             //d_accepts_diff2 ~= null;
189             tables_d_accepts_diff2[i, j] = d_accepts_diff2;
190         }
191         if (s.scanner.transitions.n) {
192             D_Shift*[][] d_accepts_diff1;
193             for (int j = 0; j < s.scanner.transitions.n; j++) {
194                 d_accepts_diff1 ~= tables_d_accepts_diff2[i,j];
195             }
196             tables.d_accepts_diff1[i] = d_accepts_diff1;
197         }
198         /* build scanner_block_hash */
199         pscanner_block_hash = &scanner_block_hash[scanner_size(s)-1]; 
200         ptrans_scanner_block_hash = &trans_scanner_block_hash[scanner_size(s)-1]; 
201         for (int j = 0; j < ss.length; j++) {
202             if (!s.same_shifts) {
203                 for (k = 0; k < g.scanner_blocks; k++) {
204                     vsblock[ivsblock].state_index = s.index;
205                     vsblock[ivsblock].scanner_index = j;
206                     vsblock[ivsblock].block_index = k;
207                     vsblock[ivsblock].chars = 
208                         ss[j].chars[k * g.scanner_block_size .. $];
209                     vsblock[ivsblock].transitions = 
210                         ss[j].transition[k * g.scanner_block_size .. $];
211                     xv = &vsblock[ivsblock];
212                     ivsblock++;
213                     assert(ivsblock <= nvsblocks);
214                     /* output state scanner blocks */
215                     yv = pscanner_block_hash.add(xv, g.scanner_block_size);
216                     if (xv == yv) {
217                         int size = scanner_size(s);
218                         auto d_scanner3 = appender!(ubyte[])();
219                         for (x = 0; x < g.scanner_block_size; x++) {
220                             xx = x + k * g.scanner_block_size;
221                             uint val = ss[j].chars[xx] ? ss[j].chars[xx].index + 1 : 0;
222                             if (size == 1)
223                                 d_scanner3.append!(ubyte, endian)(cast(ubyte)val);
224                             else if (size == 2)
225                                 d_scanner3.append!(ushort, endian)(cast(ushort)val);
226                             else
227                                 d_scanner3.append!(uint, endian)(val);
228                         }
229                         tables_d_scanner3[i,j,k] = d_scanner3.data;
230                     }
231                     if (s.scan_kind != D_SCAN_LONGEST || s.trailing_context) {
232                         /* output accept_diff scanner blocks */
233                         yv = ptrans_scanner_block_hash.add(xv, g.scanner_block_size);
234                         if (xv == yv) {
235                             int size = scanner_size(s);
236                             auto d_accepts_diff3 = appender!(ubyte[])();
237                             for (x = 0; x < g.scanner_block_size; x++) {
238                                 xx = x + k * g.scanner_block_size;
239                                 uint val = ss[j].transition[xx].index;
240                                 if (size == 1)
241                                     d_accepts_diff3.append!(ubyte, endian)(cast(ubyte)val);
242                                 else if (size == 2)
243                                     d_accepts_diff3.append!(ushort, endian)(cast(ushort)val);
244                                 else
245                                     d_accepts_diff3.append!(uint, endian)(val);
246                             }
247                             tables_d_accepts_diff3[i,j,k] = d_accepts_diff3.data;
248                         }
249                     }
250                 }
251                 /* output shifts */
252                 if (ss[j].accepts.n) {
253                     size_t[2] tmp = [i, j];
254                     for (k = 0; k < ss[j].accepts.n; k++) {
255                         Action *a = ss[j].accepts.v[k];
256                         if (ss[j].accepts.n == 1) {
257                             if (a.temp_key[0] != size_t.max)
258                             {
259                                 continue;
260                             }
261                             a.temp_key = tmp;
262                             Action *aa = shift_hash.add(a);
263                             if (aa != a)
264                                 continue;
265                         }
266                         /* output shifts */
267                         if (!k) 
268                         {
269                             tables_d_shift2[i,j] = [];
270                         }
271                         if (a.kind != ActionKind.ACTION_SHIFT_TRAILING) {
272                             tables_d_shift2[i,j] ~= allShifts[a.term.index];
273                         } else {
274                             tables_d_shift2[i,j] ~= allTShifts[a.term.index];
275                         }
276                     }
277                 }
278             }
279         }
280     }
281     for (int i = 0; i < g.states.length; i++) {
282         State *s = g.states[i];
283         auto ss = s.scanner.states;
284         ivsblock = 0;
285         if (ss.length && !s.same_shifts) {
286             /* output scanner state transition tables */
287             /* assume SB_uint8, 16, and 32 have same member offsets */
288             static assert((SB_uint8).sizeof == (SB_uint16).sizeof && (SB_uint16).sizeof == (SB_uint32).sizeof);
289             SB_uint32[] d_scanner = new SB_uint32[ss.length];
290             pscanner_block_hash = &scanner_block_hash[scanner_size(s)-1]; 
291             foreach (j, ref sb; d_scanner) {
292                 if (ss[j].accepts.n) {
293                     if (ss[j].accepts.n == 1) {
294                         Action* a = ss[j].accepts.v[0];
295                         a = shift_hash.add(a);
296                         sb.shift = tables_d_shift2.storage[a.temp_key];
297                     } else
298                         sb.shift = tables_d_shift2[i, j];
299                 }
300                 for (k = 0; k < g.scanner_blocks; k++) {
301                     ScannerBlock vs;
302                     vs.state_index = s.index;
303                     vs.scanner_index = cast(uint)j;
304                     vs.block_index = k;
305                     vs.chars = ss[j].chars[k * g.scanner_block_size .. $];
306                     vs.transitions = 
307                         ss[j].transition[k * g.scanner_block_size .. $];
308                     xv = &vs;
309                     yv = pscanner_block_hash.add(xv, g.scanner_block_size);
310                     assert(yv != xv);
311                     sb.scanner_block[k] = cast(uint*)tables_d_scanner3[yv.state_index, yv.scanner_index, yv.block_index].ptr;
312                 }
313             }
314 
315             tables.d_scanner1[i] = d_scanner;
316             if (s.scan_kind != D_SCAN_LONGEST || s.trailing_context) {
317                 SB_trans_uint32[] d_transition = new SB_trans_uint32[ss.length];
318                 /* output scanner accepts diffs tables */
319                 ptrans_scanner_block_hash = 
320                     &trans_scanner_block_hash[scanner_size(s)-1]; 
321                 foreach (j, ref trans; d_transition) {
322                     for (k = 0; k < g.scanner_blocks; k++) {
323                         ScannerBlock vs;
324                         vs.state_index = s.index;
325                         vs.scanner_index = cast(uint)j;
326                         vs.block_index = k;
327                         vs.chars = ss[j].chars[k * g.scanner_block_size .. $];
328                         vs.transitions = 
329                             ss[j].transition[k * g.scanner_block_size .. $];
330                         xv = &vs;
331                         yv = ptrans_scanner_block_hash.add(xv, g.scanner_block_size);
332                         assert(yv != xv);
333                         trans.scanner_block[k] = cast(uint*)tables_d_accepts_diff3[ yv.state_index, yv.scanner_index,
334                                     yv.block_index].ptr;
335                     }
336                 }
337                 tables.d_transition1[i] = d_transition;
338             }
339         }
340     }
341 }
342 
343 private Rule* original_reduction(Rule* r)
344 {
345     return r.same_reduction ? r.same_reduction : r;
346 }
347 
348 private void
349 buildGotoData(Grammar *g, ref BuildTables tables) {
350     size_t nvalid_bytes = ((g.productions.length + g.terminals.length) + 7) / 8;
351     ushort[] vgoto;
352     for (int i = 0; i < g.states.length; i++) {
353         State *s = g.states[i];
354         if (s.gotos.length) {
355             /* check for goto on token */
356             foreach (j; s.gotos)
357                 if (j.elem.kind == ElemKind.ELEM_TERM &&
358                         j.elem.term.kind == TermKind.TERM_TOKEN)
359                 {
360                     s.goto_on_token = 1;
361                     break;
362                 }
363 
364             ubyte[] d_goto_valid = new ubyte[nvalid_bytes];
365             /* find lowest goto, set valid bits */
366             int lowest_sym = elem_symbol(g, s.gotos[0].elem);
367             SET_BIT(d_goto_valid, lowest_sym);
368             for (int j = 1; j < s.gotos.length; j++) {
369                 int sym = elem_symbol(g, s.gotos[j].elem);
370                 SET_BIT(d_goto_valid, sym);
371                 if (sym < lowest_sym)
372                     lowest_sym = sym;
373             }
374             /* insert into vgoto */
375             bool again = true;
376             while (again) {
377                 again = false;
378                 for (int j = 0; j < s.gotos.length; j++) {
379                     int x = elem_symbol(g, s.gotos[j].elem);
380                     x -= lowest_sym;
381                     if (vgoto.length <= x) 
382                         vgoto.length = x + 1;
383 
384                     if (vgoto[x]) {
385                         again = true;
386                         /* undo the damage */
387                         for (--j;j >= 0;j--) {
388                             x = elem_symbol(g, s.gotos[j].elem);
389                             x -= lowest_sym;
390                             vgoto[x] = 0;
391                         }
392                         lowest_sym--;
393                         break;
394                     }
395                     else
396                     {
397                         if (s.gotos[j].state.index + 1 > ushort.max)
398                             d_fail("goto table overflow");
399                         vgoto[x] = cast(ushort)(s.gotos[j].state.index + 1);
400                     }
401                 }
402             }
403             s.goto_table_offset = lowest_sym;
404             /* valid bits */
405             tables.d_goto_valid[i] = d_goto_valid;
406         } else
407             s.goto_table_offset = -int.max;
408         /* reduce_actions */
409         if (s.reduce_actions.n) {
410             tables.d_reductions1[i] = s.reduce_actions.array
411                 .map!(x => tables.reductions[original_reduction(x.rule).index])
412                 .array();
413         }
414         /* modified_reduce_actions */
415         if (s.right_epsilon_hints.n) {
416             D_RightEpsilonHint[] hints = new D_RightEpsilonHint[s.right_epsilon_hints.length];
417             for (uint j = 0; j < s.right_epsilon_hints.length; ++j)
418             {
419                 auto x = s.right_epsilon_hints[j];
420                 hints[j] = D_RightEpsilonHint(cast(ushort)x.depth,
421                                        cast(ushort)x.state.index,
422                                        tables.reductions[original_reduction(x.rule).index]);
423             }
424             tables.d_right_epsilon_hints1[i] = hints;
425         }
426     }
427 
428     /* gotos */
429     tables.d_gotos = vgoto;
430 }
431 
432 private void
433 buildReductions(Grammar *g, ref BuildTables tables) {
434     foreach (p; g.productions) {
435         for (long j = p.rules.length - 1; j >= 0; j--) {
436             Rule *r = p.rules[j];
437             for (int k = 0; k < j; k++)
438                 if (r.elems.length == p.rules[k].elems.length &&
439                         r.speculative_code.code == p.rules[k].speculative_code.code &&
440                         r.final_code == p.rules[k].final_code &&
441                         r.op_priority == p.rules[k].op_priority &&
442                         r.op_assoc == p.rules[k].op_assoc &&
443                         r.rule_priority == p.rules[k].rule_priority &&
444                         r.rule_assoc == p.rules[k].rule_assoc &&
445                         r.action_index == p.rules[k].action_index) 
446                 {
447                     if (r.pass_code.n != p.rules[k].pass_code.n)
448                         continue;
449 
450                     bool cont = false;
451                     for (int l = 0; l < r.pass_code.n; l++) {
452                         if (!r.pass_code[l] && !p.rules[k].pass_code[l])
453                             continue;
454                         if ((!r.pass_code[l] || !p.rules[k].pass_code[l]) ||
455                             (r.pass_code[l].code != p.rules[k].pass_code[l].code))
456                         {
457                             cont = true;
458                             break;
459                         }
460                     }
461 
462                     if (!cont)
463                     {
464                         r.same_reduction = p.rules[k];
465                         break;
466                     }
467                 }
468         }
469         foreach (r; p.rules) {
470             if (r.same_reduction)
471                 continue;
472             D_Reduction* red = new D_Reduction();
473             tables.reductions[r.index] = red;
474             red.nelements = cast(ushort)r.elems.length;
475             red.symbol = cast(ushort)r.prod.index;
476             if (!r.prod.internal && r.final_code.line == -1)
477             {
478                 red.final_code = r.final_code.f;
479             }
480             else if (!r.prod.internal && r.action_index >= 0) {
481                 red.speculative_code = tables.spec_code;
482                 red.final_code = tables.final_code;
483             } else {
484                 red.speculative_code = null;
485                 red.final_code = null;
486             }
487 
488             red.op_assoc = cast(ushort)r.op_assoc;
489             red.rule_assoc = cast(ushort)r.rule_assoc;
490             red.op_priority = r.op_priority;
491             red.rule_priority = r.rule_priority;
492             red.action_index = r.prod.internal ? -1 : r.action_index;
493             red.pass_code = null;
494         }
495     }
496 }
497 
498 uint32
499 er_hint_hash_fn(State *a) {
500   VecHint *sa = &a.error_recovery_hints;
501   uint32 hash = 0, i;
502   Term *ta;
503 
504   for (i = 0; i < sa.n; i++) {
505     ta = sa.v[i].rule.elems[$ - 1].term;
506     hash += (sa.v[i].depth + 1) * 13;
507     hash += strhashl(ta.string_);
508     if (sa.v[i].rule)
509       hash += sa.v[i].rule.prod.index * 10007;
510   }
511   return hash;
512 }
513 
514 int
515 er_hint_cmp_fn(State *a, State *b) {
516   int i;
517   VecHint *sa = &a.error_recovery_hints, sb = &b.error_recovery_hints;
518   if (sa.n != sb.n)
519     return 1;
520   for (i = 0; i < sa.n; i++) {
521     Term *ta = sa.v[i].rule.elems[$ - 1].term;
522     Term *tb = sb.v[i].rule.elems[$ - 1].term;
523     if (sa.v[i].depth != sb.v[i].depth ||
524 	ta.string_ != tb.string_ ||
525 	sa.v[i].rule.prod.index != sb.v[i].rule.prod.index)
526       return 1;
527   }
528   return 0;
529 }
530 
531 alias ErrorHintSet = Set!(State*, er_hint_hash_fn, er_hint_cmp_fn);
532 
533 private void
534 buildErrorData(Grammar *g, ref BuildTables tables, ref ErrorHintSet er_hash) {
535     for (int i = 0; i < g.states.length; i++) {
536         State *s = g.states[i];
537         if (s.error_recovery_hints.n) {
538             State* h = er_hash.add(s);
539             if (h == s) {
540                 D_ErrorRecoveryHint[] d_error_recovery_hints;
541                 foreach (erh; s.error_recovery_hints) {
542                     Term *t = erh.rule.elems[$ - 1].term;
543                     D_ErrorRecoveryHint hint;
544                     hint.depth = cast(ushort)erh.depth;
545                     hint.symbol = cast(ushort)erh.rule.prod.index;
546                     hint.str = escape_string(t.string_);
547                     d_error_recovery_hints ~= hint;
548                 }
549                 tables.d_error_recovery_hints1[i] = d_error_recovery_hints;
550             }
551         }
552     }
553 }
554 
555 private void
556 buildStateData(Grammar *g, ref BuildTables tables, ref ErrorHintSet er_hash) {
557     if (g.states.length) {
558         tables.d_states = new D_State[g.states.length];
559         foreach (i, ref state; tables.d_states) {
560             State *s = g.states[i];
561             State *shifts = s.same_shifts ? s.same_shifts : s;
562 
563             if (s.gotos.length)
564                 state.goto_valid = tables.d_goto_valid[i];
565 
566             state.goto_table_offset = s.goto_table_offset;
567 
568             if (s.reduce_actions.n) {
569                 state.reductions = tables.d_reductions1[i];
570                 assert(s.reduce_actions.n == state.reductions.length);
571             }
572 
573             if (s.right_epsilon_hints.n) {
574                 state.right_epsilon_hints = tables.d_right_epsilon_hints1[i];
575                 assert(state.right_epsilon_hints.length == s.right_epsilon_hints.n);
576             }
577 
578             if (s.error_recovery_hints.n) {
579                 State* h = er_hash.add(s);
580                 state.error_recovery_hints = tables.d_error_recovery_hints1[h.index];
581                 assert(state.error_recovery_hints.length == s.error_recovery_hints.n);
582             }
583 
584             state.shifts = s.shift_actions.n || s.scanner_code || (g.scanner.code && s.goto_on_token);
585 
586             if (s.scanner.states.length) {
587                 state.scanner_table = tables.d_scanner1[shifts.index];
588             }
589 
590             state.scanner_size = cast(ubyte)scanner_size(s);
591             state.accept = s.accept;
592             state.scan_kind = cast(ubyte)s.scan_kind;
593 
594             if ((shifts.scan_kind != D_SCAN_LONGEST || shifts.trailing_context)
595                     && shifts.scanner.states.length) {
596                 state.transition_table = tables.d_transition1[shifts.index];
597             }
598 
599             if ((shifts.scan_kind != D_SCAN_LONGEST || shifts.trailing_context)
600                     && shifts.scanner.states.length)
601                 state.accepts_diff = tables.d_accepts_diff1[shifts.index];
602 
603             if (s.reduces_to)
604                 state.reduces_to = s.reduces_to.index;
605             else
606                 state.reduces_to = -1;
607         }
608     } else {
609         d_fail("no states");
610     }
611 }
612 
613 bool is_EBNF(uint _x)
614 {
615     return _x == InternalKind.INTERNAL_CONDITIONAL || _x == InternalKind.INTERNAL_STAR || _x == InternalKind.INTERNAL_PLUS;
616 }
617 
618 private immutable D_SymbolKind[] d_symbol_values = [ 
619   D_SymbolKind.D_SYMBOL_STRING, D_SymbolKind.D_SYMBOL_REGEX, D_SymbolKind.D_SYMBOL_CODE, D_SymbolKind.D_SYMBOL_TOKEN ];
620 
621 private void
622 buildSymbolData(Grammar *g, ref BuildTables tables) {
623     int i = 0;
624     D_Symbol[] d_symbols = new D_Symbol[g.productions.length + g.terminals.length];
625     foreach (p; g.productions) {
626         int state = -1;
627         if (!p.internal && p.elem)
628             state = p.state.index;
629         d_symbols[i].kind = p.internal ? (is_EBNF(p.internal) ? D_SymbolKind.D_SYMBOL_INTERNAL : D_SymbolKind.D_SYMBOL_EBNF) : D_SymbolKind.D_SYMBOL_NTERM;
630         d_symbols[i].name = p.name;
631         d_symbols[i].start_symbol = state;
632         ++i;
633     }
634     foreach (t; g.terminals) {
635         string name = t.term_name;
636         if (!name.length) name = escape_string(t.string_);
637         d_symbols[i].kind = d_symbol_values[t.kind];
638         d_symbols[i].name = name;
639         ++i;
640     }
641     tables.d_symbols = d_symbols;
642 }
643 
644 private void
645 buildPassesData(Grammar *g, ref BuildTables tables) {
646   int i;
647   if (g.passes.n) {
648     D_Pass[] d_passes;
649     for (i = 0; i < g.passes.n; i++) {
650       D_Pass *p = g.passes.v[i];
651       d_passes ~= *p;
652     }
653     tables.d_passes = d_passes;
654   }
655 }
656 
657 D_ParserTables* createTablesFromGrammar(Grammar* g, D_ReductionCode spec_code, D_ReductionCode final_code)
658 {
659     ErrorHintSet er_hash;
660 
661     g.scanner_block_size = 256/g.scanner_blocks;
662 
663     D_ParserTables* result = new D_ParserTables();
664     BuildTables tables;
665 
666     tables.final_code = final_code;
667     tables.spec_code = spec_code;
668 
669     buildReductions(g, tables);
670     buildScannerData(g, tables);
671     buildGotoData(g, tables);
672     buildErrorData(g, tables, er_hash);
673     buildStateData(g, tables, er_hash);
674     buildSymbolData(g, tables);
675     buildPassesData(g, tables);
676 
677     result.states = tables.d_states;
678     assert(result.states.length == g.states.length);
679 
680     result.goto_table = tables.d_gotos;
681     auto ws = lookup_production(g, "whitespace");
682     if (ws) result.whitespace_state = ws.state.index;
683     result.symbols = tables.d_symbols;
684     assert(result.symbols.length == g.productions.length + g.terminals.length);
685     result.passes = tables.d_passes;
686     assert(result.passes.length == g.passes.length);
687     result.save_parse_tree = g.save_parse_tree;
688     return result;
689 }
690 
691 struct TableMap(T, int dimension = 1)
692 {
693     T[size_t[dimension]] storage;
694 
695     ref T opIndex(size_t[dimension] key ...)
696     {
697         assert(key in storage);
698         return storage[key];
699     }
700 
701     void opIndexAssign(T val, size_t[dimension] key ...)
702     {
703         assert(key !in storage);
704         storage[key] = val;
705     }
706 }
707 
708 struct BuildTables
709 {
710     D_Shift*[][][uint] d_accepts_diff1;
711     D_Symbol[] d_symbols;
712 
713     D_Reduction*[uint] reductions;
714     SB_uint32[][uint] d_scanner1;
715     SB_trans_uint32[][uint] d_transition1;
716     ubyte[][size_t] d_goto_valid;
717     D_Reduction*[][size_t] d_reductions1;
718     D_RightEpsilonHint[][size_t] d_right_epsilon_hints1;
719     D_ErrorRecoveryHint[][size_t] d_error_recovery_hints1;
720     ushort[] d_gotos;
721 
722     D_State[] d_states;
723     D_Pass[] d_passes;
724 
725     D_ReductionCode spec_code;
726     D_ReductionCode final_code;
727 }
728