1 module gamma.parsgen.lalr1.LR1ParserTablesWriter;
2 
3 import gamma.grammar.Alternative;
4 import gamma.grammar.Node;
5 import gamma.grammar.Nonterminal;
6 import gamma.grammar.Rule;
7 import gamma.grammar.Symbol;
8 import gamma.grammar.SymbolNode;
9 import gamma.grammar.Terminal;
10 import gamma.parsgen.lalr1.OrderedLR1Tables;
11 import std.algorithm;
12 import std.array;
13 import std.json;
14 import std.stdio;
15 
16 /**
17  * Writes an OrderedLR1Tables representation to a given output file.
18  */
19 public static void write(OrderedLR1Tables parserTables, File output)
20 {
21     JSONValue[string] grammarObject;
22     JSONValue[] nonterminals;
23 
24     foreach (nonterminal; parserTables.grammar.nonterminals)
25         nonterminals ~= JSONValue([
26             "index": JSONValue(nonterminal.index),
27             "repr": JSONValue(nonterminal.toString),
28         ]);
29     grammarObject["nonterminals"] = nonterminals;
30 
31     JSONValue[] terminals;
32 
33     foreach (terminal; parserTables.grammar.terminals)
34         terminals ~= JSONValue([
35             "index": JSONValue(terminal.index),
36             "repr": JSONValue(terminal.toString),
37         ]);
38     grammarObject["terminals"] = terminals;
39 
40     JSONValue[] rules;
41     size_t altIndex = 0;
42     size_t[Alternative] alt2IndexMap;
43 
44     foreach (rule; parserTables.grammar.rules)
45     {
46         JSONValue[string] ruleObject;
47 
48         if (rule.alternatives.length == 0)
49             continue;
50 
51         ruleObject["lhs"] = (cast(Nonterminal)(cast(Alternative) rule.alternatives[0]).lhs.symbol).index;
52 
53         JSONValue[] alternatives;
54 
55         foreach (alternative; rule.alternatives)
56         {
57             JSONValue[string] alternativeObject;
58 
59             alternativeObject["index"] = altIndex;
60             alt2IndexMap[alternative] = altIndex;
61             ++altIndex;
62 
63             JSONValue[] symbols;
64 
65             foreach (node; alternative.rhs)
66             {
67                 assert(cast(SymbolNode) node);
68 
69                 auto symbol = (cast(SymbolNode) node).symbol;
70 
71                 if (cast(Terminal) symbol)
72                     symbols ~= JSONValue([
73                         "type": JSONValue("terminal"),
74                         "index": JSONValue((cast(Terminal) symbol).index),
75                     ]);
76                 else if (cast(Nonterminal) symbol)
77                     symbols ~= JSONValue([
78                         "type": JSONValue("nonterminal"),
79                         "index": JSONValue((cast(Nonterminal) symbol).index)
80                     ]);
81             }
82             alternativeObject["rhs"] = symbols;
83             alternatives ~= JSONValue(alternativeObject);
84         }
85         ruleObject["alternatives"] = alternatives;
86         rules ~= JSONValue(ruleObject);
87     }
88     grammarObject["rules"] = rules;
89     grammarObject["startSymbol"] = ["index": parserTables.grammar.startSymbol.index];
90 
91     JSONValue[] states;
92 
93     foreach (state; 0 .. parserTables.stateCount)
94     {
95         JSONValue[string] stateObject;
96 
97         stateObject["index"] = state;
98 
99         JSONValue[] actions;
100 
101         foreach (action; parserTables.getSortedParserActionRow(state))
102         {
103             JSONValue[string] actionObject;
104 
105             actionObject["on"] = action.lookahead.index;
106             if (cast(OrderedLR1Tables.Shift) action)
107             {
108                 actionObject["type"] = "shift";
109                 actionObject["to"] = (cast(OrderedLR1Tables.Shift) action).state;
110             }
111             else if (cast(OrderedLR1Tables.Reduce) action)
112             {
113                 OrderedLR1Tables.Reduce ra = cast(OrderedLR1Tables.Reduce) action;
114 
115                 actionObject["type"] = "reduce";
116                 actionObject["ruleAlt"] = alt2IndexMap[ra.alternative];
117             }
118             else if (cast(OrderedLR1Tables.Halt) action)
119             {
120                 actionObject["type"] = "halt";
121             }
122             if (action.isContinuationAction)
123                 actionObject["continues"] = true;
124             actions ~= JSONValue(actionObject);
125         }
126         stateObject["actions"] = actions;
127 
128         JSONValue[] transitions;
129 
130         foreach (g; parserTables.getSortedGotoRow(state))
131             transitions ~= JSONValue([
132                 "on": JSONValue(g.lhs.index),
133                 "to": JSONValue(g.state),
134             ]);
135         stateObject["transitions"] = transitions;
136         states ~= JSONValue(stateObject);
137     }
138 
139     JSONValue value = [
140         "grammar": JSONValue(grammarObject),
141         "states": JSONValue(states),
142         ];
143 
144     output.writeln(value.toPrettyString);
145 }