1 module epsilon.emitgen;
2 
3 import EAG = epsilon.eag;
4 import epsilon.settings;
5 import runtime;
6 import std.bitmanip : BitArray;
7 import std.stdio;
8 
9 private const CaseLabels = 127;
10 private BitArray Type3;
11 private BitArray Type2;
12 private int StartMNont;
13 
14 public void GenEmitProc(File output, Settings settings)
15 {
16     void CalcSets(int Nont)
17     in (EAG.firstMNont <= Nont)
18     in (Nont < EAG.NextMNont)
19     {
20         int A;
21         int F;
22         int M;
23 
24         if (EAG.MNont[Nont].IsToken)
25             Type3[Nont] = true;
26         A = EAG.MNont[Nont].MRule;
27         while (A != EAG.nil)
28         {
29             F = EAG.MAlt[A].Right;
30             while (EAG.MembBuf[F] != EAG.nil)
31             {
32                 M = EAG.MembBuf[F];
33                 if (M > 0)
34                 {
35                     if (Type3[Nont] && !Type3[M])
36                     {
37                         Type3[M] = true;
38                         CalcSets(M);
39                     }
40                     if (Type2[Nont] && !Type2[M])
41                     {
42                         if (!EAG.MNont[M].IsToken)
43                             Type2[M] = true;
44                         CalcSets(M);
45                     }
46                 }
47                 ++F;
48             }
49             A = EAG.MAlt[A].Next;
50         }
51     }
52 
53     void GenEmitProcs(BitArray MNonts)
54     {
55         void GenProcName(size_t N, BitArray Type)
56         {
57             output.write("Emit", N, "Type", (Type == Type2) ? "2" : "3");
58         }
59 
60         void GenAlts(size_t N)
61         {
62             int A;
63             int F;
64             int M;
65             int arity;
66             int ANum;
67 
68             void WhiteSpace()
69             {
70                 if (settings.space)
71                     output.write("Out.write(' '); ");
72                 else
73                     output.write("Out.writeln; ");
74             }
75 
76             A = EAG.MNont[N].MRule;
77             ANum = 1;
78             output.writeln("switch (MOD(Heap[Ptr], arityConst))");
79             output.writeln("{");
80             while (A != EAG.nil)
81             {
82                 if (ANum > CaseLabels)
83                 {
84                     stdout.write("internal error: Too many meta alts in ");
85                     stdout.write(EAG.MTerm[N].Id.repr);
86                     stdout.writeln;
87                     assert(0);
88                 }
89                 F = EAG.MAlt[A].Right;
90                 arity = 0;
91                 output.writeln("case ", ANum, ":");
92                 while (EAG.MembBuf[F] != EAG.nil)
93                 {
94                     M = EAG.MembBuf[F];
95                     if (M < 0)
96                     {
97                         output.write("Out.write(");
98                         output.write(EAG.MTerm[-M].Id.repr);
99                         output.write("); ");
100                         if (MNonts == Type2)
101                             WhiteSpace;
102                     }
103                     else
104                     {
105                         if (MNonts == Type3 || EAG.MNont[M].IsToken)
106                             GenProcName(M, Type3);
107                         else
108                             GenProcName(M, Type2);
109                         ++arity;
110                         output.write("(Heap[Ptr + ");
111                         output.write(arity);
112                         output.write("]); ");
113                         if (EAG.MNont[M].IsToken && MNonts == Type2)
114                             WhiteSpace;
115                     }
116                     ++F;
117                     output.writeln;
118                 }
119                 output.writeln("break;");
120                 A = EAG.MAlt[A].Next;
121                 ++ANum;
122             }
123             output.writeln("default:");
124             output.writeln("Out.write(Heap[Ptr]);");
125             output.writeln("}");
126         }
127 
128         foreach (N; MNonts.bitsSet)
129         {
130             output.write("void ");
131             GenProcName(N, MNonts);
132             output.writeln("(HeapType Ptr)");
133             output.writeln("{");
134             output.writeln("OutputSize += DIV(MOD(Heap[Ptr], refConst), arityConst) + 1;");
135             GenAlts(N);
136             output.writeln("}");
137             output.writeln;
138         }
139     }
140 
141     StartMNont = EAG.DomBuf[EAG.HNont[EAG.StartSym].Sig];
142     Type3 = BitArray();
143     Type3.length = EAG.NextMNont + 1;
144     Type2 = BitArray();
145     Type2.length = EAG.NextMNont + 1;
146     if (!EAG.MNont[StartMNont].IsToken)
147         Type2[StartMNont] = true;
148     CalcSets(StartMNont);
149     if (!Type3.bitsSet.empty)
150         GenEmitProcs(Type3);
151     if (!Type2.bitsSet.empty)
152         GenEmitProcs(Type2);
153 }
154 
155 public void GenShowHeap(File output) @safe
156 {
157     output.writeln("if (info_)");
158     output.writeln("{");
159     output.write(`stdout.write("    tree of "); `);
160     output.writeln("stdout.write(OutputSize);");
161     output.writeln(`stdout.write(" uses ");`);
162     output.writeln(`stdout.write(CountHeap());`);
163     output.writeln(`stdout.write(" of ");`);
164     output.writeln(`stdout.write(NextHeap);`);
165     output.writeln(`stdout.write(" allocated, with ");`);
166     output.writeln("stdout.write(predefined + 1);");
167     output.writeln(`stdout.writeln(" predefined");`);
168     output.writeln("}");
169 }
170 
171 public void GenEmitCall(File output, Settings settings)
172 {
173     output.write("if (");
174     if (settings.write)
175         output.write("!");
176     output.writeln("write)");
177     output.writeln(`Out = File("`, EAG.BaseName, `.Out", "w");`);
178     output.writeln("else");
179     output.writeln("Out = stdout;");
180     output.writeln("Emit", StartMNont, "Type",  Type2[StartMNont] ? "2" : "3", "(V1);");
181     output.writeln("Out.writeln;");
182     output.writeln("Out.flush;");
183 }
184 
185 private string repr(int id)
186 {
187     import std.range : dropBackOne, dropOne, front, only;
188     import std.format : format;
189 
190     const value = EAG.symbolTable.symbol(id);
191 
192     if (value.front == '\'')
193     {
194         if (value == `'"'`)
195             return "`\"`";
196         return format!`"%s"`(value.dropOne.dropBackOne);
197     }
198     return value;
199 
200 }