1 module epsilon.soag.soaggen;
2 
3 import EAG = epsilon.eag;
4 import EmitGen = epsilon.emitgen;
5 import SLAGGen = epsilon.slaggen;
6 import epsilon.settings;
7 import io : Input, read;
8 import log;
9 import runtime;
10 import optimizer = epsilon.soag.optimizer;
11 import partition = epsilon.soag.partition;
12 import Protocol = epsilon.soag.protocol;
13 import SOAG = epsilon.soag.soag;
14 import VisitSeq = epsilon.soag.visitseq;
15 import std.bitmanip : BitArray;
16 import std.stdio;
17 
18 private const firstAffixOffset = 0;
19 private const optimizedStorage = -1;
20 private const notApplied = -2;
21 private bool UseConst;
22 private bool UseRefCnt;
23 private bool Optimize;
24 private int[] LocalVars;
25 private int[] NodeName;
26 private int[] AffixOffset;
27 private int[] AffixVarCount;
28 private int[] SubTreeOffset;
29 private int[] FirstRule;
30 private int[] AffixAppls;
31 private File output;
32 private bool Close;
33 
34 /**
35  * SEM: Steuerung der Generierung
36  */
37 public string Generate(Settings settings)
38 in (EAG.Performed(EAG.analysed | EAG.predicates))
39 {
40     UseConst = !settings.c;
41     UseRefCnt = !settings.r;
42     Optimize = !settings.o;
43     partition.Compute;
44     VisitSeq.Generate;
45     if (Optimize)
46         optimizer.Optimize;
47     info!"SOAG writing %s"(EAG.BaseName);
48     if (Optimize)
49         info!"optimize";
50     else
51         info!"don't optimize";
52     Init;
53 
54     const fileName = GenerateModule(settings);
55 
56     EAG.History |= EAG.isSweep;
57     EAG.History |= EAG.hasEvaluator;
58     return fileName;
59 }
60 
61 /**
62  * IN:  Regel
63  * OUT: -
64  * SEM: Berechnet im Feld NodeNames für alle Affixbaumanalysen der Regel
65  *      die Namen der temp. Variablen für die Baumknoten;
66  *      die maximale Variablenummer der Regel wird in LocalVars[] abgelegt
67  */
68 private void ComputeNodeNames(int R) @nogc nothrow
69 {
70     int Var;
71     int ProcVar;
72     int AP;
73     int Node;
74     int SO;
75     int PBI;
76 
77     /**
78      * IN: Knoten in NodeBuf[], Variablenname
79      * OUT: -
80      * SEM: Berechnet für jeden Knoten des Teilbaums NodeBuf[Node]
81      *      die temp. Variable für die Baumanalyse oder -synthese
82      */
83     void Traverse(int Node, ref int Var)
84     {
85         int Node1;
86         const Arity = EAG.MAlt[EAG.NodeBuf[Node]].Arity;
87 
88         ++Var;
89         NodeName[Node] = Var;
90         for (size_t n = 1; n <= Arity; ++n)
91         {
92             Node1 = EAG.NodeBuf[Node + n];
93             if (Node1 > 0)
94             {
95                 if (UseConst && EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
96                 {
97                     ++Var;
98                     NodeName[Node1] = Var;
99                 }
100                 else
101                 {
102                     Traverse(Node1, Var);
103                 }
104             }
105         }
106     }
107 
108     LocalVars[R] = 0;
109     for (AP = SOAG.Rule[R].AffOcc.Beg; AP <= SOAG.Rule[R].AffOcc.End; ++AP)
110     {
111         PBI = SOAG.AffOcc[AP].ParamBufInd;
112         if (EAG.ParamBuf[PBI].isDef || UseRefCnt)
113         {
114             Var = 0;
115             Node = EAG.ParamBuf[PBI].Affixform;
116             if (Node > 0)
117             {
118                 if (UseConst && EAG.MAlt[EAG.NodeBuf[Node]].Arity == 0)
119                 {
120                     ++Var;
121                     NodeName[Node] = Var;
122                 }
123                 else
124                 {
125                     Traverse(Node, Var);
126                 }
127             }
128             if (Var > LocalVars[R])
129             {
130                 LocalVars[R] = Var;
131             }
132         }
133     }
134     for (SO = SOAG.Rule[R].SymOcc.Beg; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
135     {
136         if (SOAG.IsPredNont(SO))
137         {
138             Var = 0;
139             ProcVar = 0;
140             for (AP = SOAG.SymOcc[SO].AffOcc.Beg; AP <= SOAG.SymOcc[SO].AffOcc.End;
141                     ++AP)
142             {
143                 PBI = SOAG.AffOcc[AP].ParamBufInd;
144                 Node = EAG.ParamBuf[PBI].Affixform;
145                 if (!EAG.ParamBuf[PBI].isDef)
146                 {
147                     if (Node > 0)
148                     {
149                         ++Var;
150                         NodeName[Node] = Var;
151                     }
152                 }
153             }
154             if (Var > LocalVars[R])
155             {
156                 LocalVars[R] = Var;
157             }
158         }
159     }
160 }
161 
162 /**
163  * IN:  Affixparameter
164  * OUT: Affixposition
165  * SEM: gibt die Affixposition zurück, zu der der Affixparameter korrespondiert
166  */
167 private int GetCorrespondedAffPos(int AP) @nogc nothrow @safe
168 {
169     const SO = SOAG.AffOcc[AP].SymOccInd;
170     const AN = AP - SOAG.SymOcc[SO].AffOcc.Beg;
171 
172     return SOAG.Sym[SOAG.SymOcc[SO].SymInd].AffPos.Beg + AN;
173 }
174 
175 /**
176  * IN:  Regel
177  * OUT: -
178  * SEM: berechnet im Feld AffixOffset[], das parallel zu EAG.Var liegt,
179  *      den Offset der Affixvariablen im Feld Var[] des generierten Compilers;
180  *      alle nicht-applizierten Affixvariablen (AffixAppls[]=0) werden ausgelassen
181  * PRE: AffixAppls[] muss berechnet sein
182  */
183 private void ComputeAffixOffset(int R) @nogc nothrow @safe
184 {
185     EAG.ScopeDesc Scope;
186 
187     if (auto ordRule = cast(SOAG.OrdRule) SOAG.Rule[R])
188     {
189         Scope = ordRule.Alt.Scope;
190     }
191     else if (auto emptyRule = cast(SOAG.EmptyRule) SOAG.Rule[R])
192     {
193         EAG.Rule EAGRule = emptyRule.Rule;
194 
195         if (auto opt = cast(EAG.Opt) EAGRule)
196             Scope = opt.Scope;
197         else if (auto rep = cast(EAG.Rep) EAGRule)
198             Scope = rep.Scope;
199     }
200 
201     int Offset = firstAffixOffset;
202 
203     foreach (A; Scope.Beg .. Scope.End)
204     {
205         if (AffixAppls[A] > 0)
206         {
207             if (Optimize)
208             {
209                 const AP = GetCorrespondedAffPos(SOAG.DefAffOcc[A]);
210 
211                 if (SOAG.StorageName[AP] == 0)
212                 {
213                     AffixOffset[A] = Offset;
214                     ++Offset;
215                 }
216                 else
217                 {
218                     AffixOffset[A] = optimizedStorage;
219                 }
220             }
221             else
222             {
223                 AffixOffset[A] = Offset;
224                 ++Offset;
225             }
226         }
227         else
228         {
229             AffixOffset[A] = notApplied;
230         }
231     }
232     AffixVarCount[R] = Offset - firstAffixOffset;
233 }
234 
235 /**
236  * SEM: liefert die echte Anzahl an Affixvariablen in der Regel;
237  *      nur zur Information über die Optimierungleistung
238  */
239 private int GetAffixCount(int R) @nogc nothrow @safe
240 {
241     EAG.ScopeDesc Scope;
242 
243     if (auto ordRule = cast(SOAG.OrdRule) SOAG.Rule[R])
244     {
245         Scope = ordRule.Alt.Scope;
246     }
247     else if (auto emptyRule = cast(SOAG.EmptyRule) SOAG.Rule[R])
248     {
249         EAG.Rule EAGRule = emptyRule.Rule;
250 
251         if (auto opt = cast(EAG.Opt) EAGRule)
252             Scope = opt.Scope;
253         else if (auto rep = cast(EAG.Rep) EAGRule)
254             Scope = rep.Scope;
255     }
256     return Scope.End - Scope.Beg;
257 }
258 
259 /**
260  * IN:  -
261  * OUT: Hyper-Arity-Konstante
262  * SEM: Liefert die Arity-Konstante für den Ableitungsbaum, der durch den Parser erzeugt wird;
263  *      müsste eigentlich von SLAG geliefert werden (in Sweep wurde es auch intern definiert,
264  *      deshalb wird es hier für spätere Module exportiert)
265  */
266 private int HyperArity() nothrow
267 {
268     const Nonts = EAG.All - EAG.Pred;
269     int Max = 0;
270     int i;
271 
272     foreach (N; Nonts.bitsSet)
273     {
274         EAG.Alt A = EAG.HNont[N].Def.Sub;
275 
276         i = 0;
277         do
278         {
279             ++i;
280             A = A.Next;
281         }
282         while (A !is null);
283         if (cast(EAG.Opt) EAG.HNont[N].Def || cast(EAG.Rep) EAG.HNont[N].Def)
284             ++i;
285         if (i > Max)
286             Max = i;
287     }
288     i = 1;
289     while (i <= Max)
290         i = i * 2;
291     return i;
292 }
293 
294 /**
295  * SEM: Initialisierung der Datenstrukturen des Moduls
296  */
297 private void Init() nothrow
298 {
299     int R;
300     int SO;
301     int S;
302     int Offset;
303 
304     LocalVars = new int[SOAG.NextRule];
305     AffixVarCount = new int[SOAG.NextRule];
306     AffixOffset = new int[EAG.NextVar];
307     NodeName = new int[EAG.NextNode];
308     SubTreeOffset = new int[SOAG.NextSymOcc];
309     FirstRule = new int[SOAG.NextSym];
310     AffixAppls = new int[EAG.NextVar];
311     for (size_t i = SOAG.firstRule; i < SOAG.NextRule; ++i)
312     {
313         LocalVars[i] = 0;
314         AffixVarCount[i] = -1;
315     }
316     for (size_t i = EAG.firstNode; i < EAG.NextNode; ++i)
317     {
318         NodeName[i] = -1;
319     }
320     for (size_t i = EAG.firstVar; i < EAG.NextVar; ++i)
321     {
322         EAG.Var[i].Def = false;
323         AffixAppls[i] = SOAG.AffixApplCnt[i];
324     }
325     for (R = SOAG.firstRule; R < SOAG.NextRule; ++R)
326     {
327         Offset = 0;
328         for (SO = SOAG.Rule[R].SymOcc.Beg + 1; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
329         {
330             if (!SOAG.IsPredNont(SO))
331             {
332                 ++Offset;
333                 SubTreeOffset[SO] = Offset;
334             }
335         }
336     }
337     for (S = SOAG.firstSym; S < SOAG.NextSym; ++S)
338     {
339         SO = SOAG.Sym[S].FirstOcc;
340         if (SO != SOAG.nil)
341         {
342             R = SOAG.SymOcc[SO].RuleInd;
343             while (SO != SOAG.Rule[R].SymOcc.Beg)
344             {
345                 SO = SOAG.SymOcc[SO].Next;
346                 R = SOAG.SymOcc[SO].RuleInd;
347             }
348             SO = SOAG.SymOcc[SO].Next;
349             while (R >= SOAG.firstRule && S == SOAG.SymOcc[SOAG.Rule[R].SymOcc.Beg].SymInd)
350             {
351                 FirstRule[S] = R;
352                 --R;
353             }
354         }
355     }
356 }
357 
358 private void GenHeapInc(int n) @safe
359 {
360     if (n != 0)
361     {
362         if (n == 1)
363             output.writeln("++NextHeap;");
364         else
365             output.writeln("NextHeap += ", n, ";");
366     }
367 }
368 
369 private void GenVar(int Var) @safe
370 {
371     output.write("V", Var);
372 }
373 
374 private void GenHeap(int Var, int Offset) @safe
375 {
376     output.write("Heap[");
377     if (Var > 0)
378         GenVar(Var);
379     else
380         output.write("NextHeap");
381     if (Offset > 0)
382         output.write(" + ", Offset);
383     else if (Offset < 0)
384         output.write(" - ", -Offset);
385     output.write("]");
386 }
387 
388 private void GenOverflowGuard(int n) @safe
389 {
390     if (n > 0)
391         output.writeln("if (NextHeap >= Heap.length - ", n, ") EvalExpand;");
392 }
393 
394 /**
395  * IN:  Symbol, Nummer eines Affixparameter relativ zum Symbolvorkommen
396  * OUT: -
397  * SEM: Generierung eines Zugriffs auf die Instanz einer Affixposition
398  */
399 private void GenAffPos(int S, int AN) @safe
400 {
401     output.write("AffPos[S", S, " + ", AN, "]");
402 }
403 
404 /**
405  * IN: Affixnummer
406  * OUT: -
407  * SEM: Generiert einen Zugriff auf den Inhalt eines Affixes
408  */
409 private void GenAffix(int V) @safe
410 in (AffixOffset[V] != notApplied)
411 {
412     int AP;
413 
414     if (AffixOffset[V] == optimizedStorage)
415     {
416         AP = GetCorrespondedAffPos(SOAG.DefAffOcc[V]);
417         if (SOAG.StorageName[AP] > 0)
418             output.write("Stacks.Top(Stack", SOAG.StorageName[AP], ") ");
419         else
420             output.write("GV", -SOAG.StorageName[AP]);
421     }
422     else
423     {
424         output.write("Var[VI + ", AffixOffset[V], "]");
425     }
426 }
427 
428 /**
429  * IN: Affix
430  * OUT: -
431  * SEM: Generierung einer Zuweisung zu einer Instanz einer Affixvariable;
432  *      nur in Kombination mit der Prozedur GenClose zu verwenden
433  */
434 private void GenAffixAssign(int V) @safe
435 in (AffixOffset[V] != notApplied)
436 {
437     int AP;
438 
439     if (AffixOffset[V] == optimizedStorage)
440     {
441         AP = GetCorrespondedAffPos(SOAG.DefAffOcc[V]);
442         if (SOAG.StorageName[AP] > 0)
443         {
444             output.write("Stacks.Push(Stack", SOAG.StorageName[AP], ", ");
445             Close = true;
446         }
447         else
448         {
449             output.write("GV", -SOAG.StorageName[AP], " = ");
450             Close = false;
451         }
452     }
453     else
454     {
455         output.write("Var[VI + ", AffixOffset[V], "] = ");
456         Close = false;
457     }
458 }
459 
460 private void GenClose() @safe
461 {
462     if (Close)
463         output.write(");");
464     else
465         output.write(";");
466 }
467 
468 /**
469  * IN: Affixvariable oder (< 0) lokale Variable
470  * OUT: -
471  * SEM: Generiert eine Erhöhung des Referenzzählers des Knotens auf den das Affixes
472  *      bzw. der Index verweist, im Falle eines Stacks wird globale Var. RefIncVar verwendet
473  */
474 private void GenIncRefCnt(int Var) @safe
475 {
476     output.write("Heap[");
477     if (Var < 0)
478         GenVar(-Var);
479     else
480         GenAffix(Var);
481     output.writeln("] += refConst;");
482 }
483 
484 /**
485  * IN: Affixvariable
486  * OUT: -
487  * SEM: generiert die Freigabe des alloziierten Speichers,
488  *      wenn die Affixvariable das letzte mal appliziert wurde (AffixAppls = 0)
489  */
490 private void GenFreeAffix(int V) @safe
491 {
492     if (AffixAppls[V] == 0)
493     {
494         output.write("FreeHeap(");
495         GenAffix(V);
496         output.writeln(");");
497     }
498 }
499 
500 /**
501  * IN: Affixvariable
502  * OUT: -
503  * SEM: generiert die Kellerspeicherfreigabe,
504  *      wenn die Affixvariable das letzte mal appliziert wurde (AffixAppls = 0)
505  */
506 private void GenPopAffix(int V) @safe
507 {
508     if (AffixAppls[V] == 0)
509     {
510         if (AffixOffset[V] == optimizedStorage)
511         {
512             const AP = GetCorrespondedAffPos(SOAG.DefAffOcc[V]);
513 
514             if (SOAG.StorageName[AP] > 0)
515                 output.writeln("Stacks.Pop(Stack", SOAG.StorageName[AP], ");");
516             else
517                 output.writeln("GV", -SOAG.StorageName[AP], " = -1;");
518         }
519     }
520 }
521 
522 /**
523  * IN: Symbolvorkommen
524  * OUT: -
525  * SEM: Generierung der Syntheseaktionen eines Besuchs für die besuchsrelevanten Affixparameter eines Symbolvorkommens
526  */
527 private void GenSynPred(int SymOccInd, int VisitNo)
528 {
529     int Node;
530     int S;
531     int Offset;
532     int AP;
533     int AN;
534     int V;
535     int SN;
536     int P;
537     bool IsPred;
538 
539     /**
540      * IN: Knoten des Affixbaumes, Offset des nächsten freien Heap-Elementes
541      * OUT: -
542      * SEM: Traversierung eines Affixbaumes und Ausgabe der Syntheseaktionen für den zu generierenden Compiler
543      */
544     void GenSynTraverse(int Node, ref int Offset)
545     {
546         int Offset1;
547         int Node1;
548         int n;
549         int V;
550         const Alt = EAG.NodeBuf[Node];
551 
552         GenHeap(-1, Offset);
553         output.writeln(" = ", SLAGGen.NodeIdent[Alt], ";");
554         Offset1 = Offset;
555         Offset += 1 + EAG.MAlt[Alt].Arity;
556         for (n = 1; n <= EAG.MAlt[Alt].Arity; ++n)
557         {
558             Node1 = EAG.NodeBuf[Node + n];
559             if (Node1 < 0)
560             {
561                 V = -Node1;
562                 if (!EAG.Var[V].Def)
563                 {
564                     SOAG.Error(SOAG.abnormalError, "eSOAGGen.GenSynTraverse: Affix nicht definiert.");
565                 }
566                 else
567                 {
568                     GenHeap(-1, Offset1 + n);
569                     output.write(" = ");
570                     GenAffix(V);
571                     output.writeln(";");
572                     --AffixAppls[V];
573                     if (UseRefCnt)
574                         GenFreeAffix(V);
575                     if (Optimize)
576                         GenPopAffix(V);
577                 }
578             }
579             else
580             {
581                 GenHeap(-1, Offset1 + n);
582                 output.write(" = ");
583                 if (UseConst && EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
584                 {
585                     output.writeln(SLAGGen.Leaf[EAG.NodeBuf[Node1]], ";");
586                 }
587                 else
588                 {
589                     output.writeln("NextHeap + ", Offset, ";");
590                     GenSynTraverse(Node1, Offset);
591                 }
592             }
593         }
594     }
595 
596     /**
597      * IN: Knoten des Affixbaumes
598      * OUT: -
599      * SEM: Traversierung eines Affixbaumes und Ausgabe der Syntheseaktionen mit Referenzzähler-Verfahren
600      *      für den zu generierenden Compiler
601      */
602     void GenSynTraverseRefCnt(int Node)
603     {
604         int Node1;
605         int n;
606         int V;
607         const Alt = EAG.NodeBuf[Node];
608 
609         GenHeap(NodeName[Node], 0);
610         output.writeln(" = ", SLAGGen.NodeIdent[Alt], ";");
611         for (n = 1; n <= EAG.MAlt[Alt].Arity; ++n)
612         {
613             Node1 = EAG.NodeBuf[Node + n];
614             if (Node1 < 0)
615             {
616                 V = -Node1;
617                 if (!EAG.Var[V].Def)
618                 {
619                     SOAG.Error(SOAG.abnormalError, "eSOAGGen.GenSynTraverse: Affix nicht definiert.");
620                 }
621                 else
622                 {
623                     GenHeap(NodeName[Node], n);
624                     output.write(" = ");
625                     GenAffix(V);
626                     output.write("; ");
627                     --AffixAppls[V];
628                     if (AffixAppls[V] > 0)
629                         GenIncRefCnt(V);
630                     else
631                         output.writeln("// komplementäre Referenzzählerbehandlung");
632                     if (Optimize)
633                         GenPopAffix(V);
634                 }
635             }
636             else
637             {
638                 if (UseConst && EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
639                 {
640                     GenHeap(NodeName[Node], n);
641                     output.write(" = ", SLAGGen.Leaf[EAG.NodeBuf[Node1]], "; ");
642                     output.writeln("Heap[", SLAGGen.Leaf[EAG.NodeBuf[Node1]], "] += refConst;");
643                 }
644                 else
645                 {
646                     output.write("GetHeap(", EAG.MAlt[EAG.NodeBuf[Node1]].Arity, ", ");
647                     GenVar(NodeName[Node1]);
648                     output.writeln(");");
649                     GenSynTraverseRefCnt(Node1);
650                     GenHeap(NodeName[Node], n);
651                     output.write(" = ");
652                     GenVar(NodeName[Node1]);
653                     output.writeln(";");
654                 }
655             }
656         }
657     }
658 
659     S = SOAG.SymOcc[SymOccInd].SymInd;
660     IsPred = VisitNo == -1;
661     for (AP = SOAG.SymOcc[SymOccInd].AffOcc.Beg; AP <= SOAG.SymOcc[SymOccInd].AffOcc.End;
662             ++AP)
663     {
664         AN = AP - SOAG.SymOcc[SymOccInd].AffOcc.Beg;
665         P = SOAG.AffOcc[AP].ParamBufInd;
666         if (!EAG.ParamBuf[P].isDef && (VisitSeq.GetVisitNo(AP) == VisitNo || IsPred))
667         {
668             Node = EAG.ParamBuf[P].Affixform;
669             SN = SymOccInd - SOAG.Rule[SOAG.SymOcc[SymOccInd].RuleInd].SymOcc.Beg;
670             if (Node < 0)
671             {
672                 V = -Node;
673                 if (!EAG.Var[V].Def)
674                 {
675                     SOAG.Error(SOAG.abnormalError, "eSOAGGen.GenSynTraverse: Affix nicht definiert.");
676                 }
677                 else if (!IsPred)
678                 {
679                     GenAffPos(S, AN);
680                     output.write(" = ");
681                     GenAffix(V);
682                     output.write("; ");
683                     --AffixAppls[V];
684                     if (UseRefCnt && AffixAppls[V] > 0)
685                         GenIncRefCnt(V);
686                     else
687                         output.writeln("// komplementäre Referenzzählerbehandlung");
688                     if (Optimize)
689                         GenPopAffix(V);
690                     output.writeln;
691                 }
692             }
693             else
694             {
695                 if (UseConst && SLAGGen.AffixPlace[P] >= 0)
696                 {
697                     GenAffPos(S, AN);
698                     output.write(" = ", SLAGGen.AffixPlace[P]);
699                     if (UseRefCnt)
700                         output.write("; Heap[", SLAGGen.AffixPlace[P], "] += refConst");
701                     output.writeln(";");
702                 }
703                 else if (UseRefCnt)
704                 {
705                     output.write("GetHeap(", EAG.MAlt[EAG.NodeBuf[Node]].Arity, ", ");
706                     GenVar(NodeName[Node]);
707                     output.writeln(");");
708                     GenSynTraverseRefCnt(Node);
709                     GenAffPos(S, AN);
710                     output.write(" = ");
711                     GenVar(NodeName[Node]);
712                     output.writeln(";");
713                 }
714                 else
715                 {
716                     GenOverflowGuard(SLAGGen.AffixSpace[P]);
717                     GenAffPos(S, AN);
718                     output.writeln(" = NextHeap;");
719                     Offset = 0;
720                     GenSynTraverse(Node, Offset);
721                     GenHeapInc(Offset);
722                 }
723             }
724         }
725     }
726 }
727 
728 /**
729  * IN: Symbolvorkommen, Visit-Nummer
730  * OUT: -
731  * SEM: Generierung der Analyseaktionen eines Besuchs für die besuchsrelevanten Affixparameter eines Symbolvorkommens
732  */
733 private void GenAnalPred(int SymOccInd, int VisitNo) @safe
734 {
735     int S;
736     int AP;
737     int AN;
738     int Node;
739     int V;
740     int SN;
741     bool IsPred;
742     bool PosNeeded;
743 
744     void GenEqualErrMsg(int Var)
745     {
746         output.write(`"'`);
747         output.write(EAG.VarRepr(Var));
748         output.write("' failed in '");
749         output.write(EAG.NamedHNontRepr(SOAG.SymOcc[SymOccInd].SymInd));
750         output.write(`'"`);
751     }
752 
753     void GenAnalErrMsg()
754     {
755         output.write(`"`);
756         output.write(EAG.NamedHNontRepr(SOAG.SymOcc[SymOccInd].SymInd));
757         output.write(`"`);
758     }
759 
760     /**
761      * IN:  Index auf EAG.Var[] des def. Affixes, Index auf NodeName[] und Nr. des Sohnes im Heap
762      * OUT: -
763      * SEM: Generiert einen Vergleich zwischen einer Variable eines def. Affixes und einem Baumeintrag
764      */
765     void GenEqualPred(int V, int Node, int n)
766     {
767         output.write("Eq(");
768         GenHeap(NodeName[Node], n);
769         output.write(", ");
770         GenAffix(V);
771         output.write(", ");
772         GenEqualErrMsg(V);
773         output.writeln(");");
774     }
775 
776     /**
777      * IN:  zwei Indexe auf EAG.Var[]
778      * OUT: -
779      * SEM: Generiert einen Vergleich zwischen zwei Variablen der Felder Var[] (gen. Compiler)
780      */
781     void GenUnequalPred(int V1, int V2)
782     {
783         output.write("UnEq(");
784         GenAffix(V1);
785         output.write(", ");
786         GenAffix(V2);
787         output.write(", ");
788         if (EAG.Var[V1].Num < 0)
789             GenEqualErrMsg(V1);
790         else
791             GenEqualErrMsg(V2);
792         output.writeln(");");
793     }
794 
795     /**
796      * SEM: Generierung einer Positionszuweisung, wenn notwendig
797      */
798     void GenPos(ref bool PosNeeded)
799     {
800         if (PosNeeded)
801         {
802             output.writeln("Pos = SemTree[TreeAdr + ", SubTreeOffset[SymOccInd], "].Pos;");
803             PosNeeded = false;
804         }
805     }
806 
807     /**
808      * IN: Knoten des Affixbaumes
809      * OUT: -
810      * SEM: Traversierung eines Affixbaumes und Ausgabe der Analyseaktionen für den zu generierenden Compiler
811      */
812     void GenAnalTraverse(int Node)
813     {
814         int Node1;
815         int n;
816         int V;
817         const Alt = EAG.NodeBuf[Node];
818 
819         output.write("if (");
820         if (UseConst && EAG.MAlt[Alt].Arity == 0)
821         {
822             GenVar(NodeName[Node]);
823             output.write(" != ", SLAGGen.Leaf[Alt]);
824         }
825         else
826         {
827             GenHeap(NodeName[Node], 0);
828             if (UseRefCnt)
829                 output.write(".MOD(refConst)");
830             output.write(" != ", SLAGGen.NodeIdent[Alt]);
831         }
832         output.write(") AnalyseError(");
833         GenVar(NodeName[Node]);
834         output.write(", ");
835         GenAnalErrMsg;
836         output.writeln(");");
837         for (n = 1; n <= EAG.MAlt[Alt].Arity; ++n)
838         {
839             Node1 = EAG.NodeBuf[Node + n];
840             if (Node1 < 0)
841             {
842                 V = -Node1;
843                 if (EAG.Var[V].Def)
844                 {
845                     GenEqualPred(V, Node, n);
846                     --AffixAppls[V];
847                     if (UseRefCnt)
848                         GenFreeAffix(V);
849                     if (Optimize)
850                         GenPopAffix(V);
851                 }
852                 else
853                 {
854                     EAG.Var[V].Def = true;
855                     if (AffixOffset[V] != notApplied)
856                     {
857                         GenAffixAssign(V);
858                         GenHeap(NodeName[Node], n);
859                         GenClose;
860                         if (EAG.Var[EAG.Var[V].Neg].Def)
861                         {
862                             output.writeln;
863                             GenUnequalPred(EAG.Var[V].Neg, V);
864                             --AffixAppls[EAG.Var[V].Neg];
865                             --AffixAppls[V];
866                             if (UseRefCnt && AffixAppls[V] > 0)
867                                 GenIncRefCnt(V);
868                             if (UseRefCnt)
869                                 GenFreeAffix(EAG.Var[V].Neg);
870                             if (Optimize)
871                             {
872                                 GenPopAffix(EAG.Var[V].Neg);
873                                 GenPopAffix(V);
874                             }
875                         }
876                         else if (UseRefCnt)
877                         {
878                             GenIncRefCnt(V);
879                         }
880                     }
881                 }
882             }
883             else
884             {
885                 GenVar(NodeName[Node1]);
886                 output.write(" = ");
887                 GenHeap(NodeName[Node], n);
888                 output.writeln(";");
889                 GenAnalTraverse(Node1);
890             }
891         }
892     }
893 
894     S = SOAG.SymOcc[SymOccInd].SymInd;
895     IsPred = VisitNo == -1;
896     PosNeeded = !IsPred;
897     for (AP = SOAG.SymOcc[SymOccInd].AffOcc.Beg; AP <= SOAG.SymOcc[SymOccInd].AffOcc.End;
898             ++AP)
899     {
900         AN = AP - SOAG.SymOcc[SymOccInd].AffOcc.Beg;
901         if (EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].isDef
902                 && (VisitSeq.GetVisitNo(AP) == VisitNo || IsPred))
903         {
904             Node = EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].Affixform;
905             SN = SymOccInd - SOAG.Rule[SOAG.SymOcc[SymOccInd].RuleInd].SymOcc.Beg;
906             if (Node < 0)
907             {
908                 V = -Node;
909                 if (EAG.Var[V].Def)
910                 {
911                     GenPos(PosNeeded);
912                     output.write("Eq(");
913                     GenAffPos(S, AN);
914                     output.write(", ");
915                     GenAffix(V);
916                     output.write(", ");
917                     GenEqualErrMsg(V);
918                     output.writeln(");");
919                     --AffixAppls[V];
920                     if (UseRefCnt)
921                         GenFreeAffix(V);
922                     if (Optimize)
923                         GenPopAffix(V);
924                     if (UseRefCnt)
925                     {
926                         output.write("FreeHeap(");
927                         GenAffPos(S, AN);
928                         output.writeln(");");
929                     }
930                 }
931                 else
932                 {
933                     EAG.Var[V].Def = true;
934                     if (!IsPred)
935                     {
936                         if (AffixOffset[V] != notApplied)
937                         {
938                             GenAffixAssign(V);
939                             GenAffPos(S, AN);
940                             GenClose;
941                             if (UseRefCnt)
942                                 output.write(" // komplementäre Referenzzählerbehandlung");
943                             output.writeln;
944                         }
945                     }
946                     if (EAG.Var[EAG.Var[V].Neg].Def)
947                     {
948                         GenPos(PosNeeded);
949                         output.write("UnEq(");
950                         GenAffix(EAG.Var[V].Neg);
951                         output.write(", ");
952                         GenAffix(V);
953                         output.write(", ");
954                         GenEqualErrMsg(V);
955                         output.writeln(");");
956                         --AffixAppls[EAG.Var[V].Neg];
957                         --AffixAppls[V];
958                         if (UseRefCnt)
959                         {
960                             GenFreeAffix(EAG.Var[V].Neg);
961                             GenFreeAffix(V);
962                         }
963                         if (Optimize)
964                         {
965                             GenPopAffix(EAG.Var[V].Neg);
966                             GenPopAffix(V);
967                         }
968                     }
969                 }
970             }
971             else
972             {
973                 GenPos(PosNeeded);
974                 GenVar(NodeName[Node]);
975                 output.write(" = ");
976                 GenAffPos(S, AN);
977                 output.writeln(";");
978                 GenAnalTraverse(Node);
979                 if (UseRefCnt)
980                 {
981                     output.write("FreeHeap(");
982                     GenAffPos(S, AN);
983                     output.writeln(");");
984                 }
985             }
986         }
987     }
988 }
989 
990 /**
991  * IN: Symbolvorkommen, Visit-Nummer
992  * OUT: -
993  * SEM: Generierung eines Aufrufes der Prozedur 'Visit' für den zu generierenden Compiler
994  */
995 private void GenVisitCall(int SO, int VisitNo) @safe
996 {
997     output.writeln("Visit(TreeAdr + ", SubTreeOffset[SO], ", ", VisitNo, ");");
998 }
999 
1000 /**
1001  * SEM: generiert nur Kommentar
1002  */
1003 private void GenLeave(int VisitNo) @safe
1004 {
1005     output.writeln("// Leave; VisitNo: ", VisitNo);
1006 }
1007 
1008 /**
1009  * IN: Symbolvorkommen eines Prädikates
1010  * OUT: -
1011  * SEM: Generierung des Aufrufes einer Prädikatprozedur
1012  */
1013 private void GenPredCall(int SO) @safe
1014 {
1015     int S;
1016     int AP;
1017     int AN;
1018     int AP1;
1019     int Node;
1020     int V;
1021 
1022     if (UseRefCnt)
1023     {
1024         for (AP = SOAG.SymOcc[SO].AffOcc.Beg; AP <= SOAG.SymOcc[SO].AffOcc.End; ++AP)
1025         {
1026             if (!EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].isDef)
1027             {
1028                 AN = AP - SOAG.SymOcc[SO].AffOcc.Beg;
1029                 V = -EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].Affixform;
1030                 if (V > 0)
1031                     GenIncRefCnt(V);
1032             }
1033         }
1034     }
1035     S = SOAG.SymOcc[SO].SymInd;
1036     output.write("Check", S, `("`);
1037     output.write(EAG.NamedHNontRepr(S));
1038     output.write(`", `);
1039     for (AP = SOAG.SymOcc[SO].AffOcc.Beg; AP <= SOAG.SymOcc[SO].AffOcc.End; ++AP)
1040     {
1041         Node = EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].Affixform;
1042         AN = AP - SOAG.SymOcc[SO].AffOcc.Beg;
1043         V = -Node;
1044         if (EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].isDef)
1045         {
1046             if (V > 0 && SOAG.DefAffOcc[V] == AP)
1047             {
1048                 if (Optimize && AffixOffset[V] == optimizedStorage)
1049                 {
1050                     AP1 = GetCorrespondedAffPos(SOAG.DefAffOcc[V]);
1051                     if (SOAG.StorageName[AP1] > 0)
1052                         GenAffPos(S, AN);
1053                     else
1054                         output.write("GV", -SOAG.StorageName[AP1]);
1055                 }
1056                 else if (AffixOffset[V] == notApplied)
1057                 {
1058                     GenAffPos(S, AN);
1059                 }
1060                 else
1061                 {
1062                     GenAffix(V);
1063                 }
1064             }
1065             else
1066             {
1067                 GenAffPos(S, AN);
1068             }
1069         }
1070         else
1071         {
1072             if (Node > 0)
1073                 GenAffPos(S, AN);
1074             else
1075                 GenAffix(V);
1076         }
1077         if (AP != SOAG.SymOcc[SO].AffOcc.End)
1078             output.write(", ");
1079         else
1080             output.writeln(");");
1081     }
1082     for (AP = SOAG.SymOcc[SO].AffOcc.Beg; AP <= SOAG.SymOcc[SO].AffOcc.End; ++AP)
1083     {
1084         AN = AP - SOAG.SymOcc[SO].AffOcc.Beg;
1085         V = -EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].Affixform;
1086         if (V > 0)
1087         {
1088             if (EAG.ParamBuf[SOAG.AffOcc[AP].ParamBufInd].isDef)
1089             {
1090                 if (AffixOffset[V] == optimizedStorage)
1091                 {
1092                     AP1 = GetCorrespondedAffPos(SOAG.DefAffOcc[V]);
1093                     if (SOAG.StorageName[AP1] > 0)
1094                     {
1095                         output.write("Stacks.Push(Stack", SOAG.StorageName[AP1], ", ");
1096                         GenAffPos(S, AN);
1097                         output.writeln(");");
1098                     }
1099                 }
1100                 else if (AffixOffset[V] == notApplied)
1101                 {
1102                     output.write("FreeHeap(");
1103                     GenAffPos(S, AN);
1104                     output.writeln("); // Dummy-Variable");
1105                 }
1106             }
1107             else
1108             {
1109                 --AffixAppls[V];
1110                 if (UseRefCnt)
1111                     GenFreeAffix(V);
1112                 if (Optimize)
1113                     GenPopAffix(V);
1114             }
1115         }
1116     }
1117 }
1118 
1119 /**
1120  * IN:  Regel
1121  * OUT: -
1122  * SEM: Generierung der Variablendeklarationen einer Regel
1123  */
1124 private void GenVarDecls(int R) @safe
1125 {
1126     output.writeln("IndexType TreeAdr;");
1127     output.writeln("IndexType VI;");
1128     output.writeln("SemTreeEntry S;");
1129     if (LocalVars[R] > 0)
1130     {
1131         for (int i = 1; i <= LocalVars[R]; ++i)
1132         {
1133             output.write("HeapType ");
1134             GenVar(i);
1135             output.writeln(";");
1136         }
1137     }
1138 }
1139 
1140 /**
1141  * IN:  Regel, Nummer des Visit-Sequenz-Eintrages, Notwendigkeit der Positionszuweisung
1142  * OUT: -
1143  * SEM: Generierung der Positionszuweisung vor Prädikatprozeduraufrufen;
1144  *      zugewiesen wird die Position des vorhergehenden Visits
1145  */
1146 private void GenPredPos(int R, int i, ref bool PosNeeded) @safe
1147 {
1148     int k;
1149 
1150     if (PosNeeded)
1151     {
1152         --i;
1153         while (cast(SOAG.Visit) SOAG.VS[i] is null && cast(SOAG.Leave) SOAG.VS[i] is null && i > SOAG.Rule[R].VS.Beg)
1154             --i;
1155         if (auto visit = cast(SOAG.Visit) SOAG.VS[i])
1156             k = SubTreeOffset[visit.SymOcc];
1157         else
1158             k = SOAG.Rule[R].SymOcc.Beg;
1159         output.writeln("Pos = SemTree[TreeAdr + ", k, "].Pos;");
1160         PosNeeded = false;
1161     }
1162 }
1163 
1164 /**
1165  * IN: Regelnummer
1166  * OUT: -
1167  * SEM: Generiert Code für die Visit-Sequenzen einer Regel
1168  */
1169 private void GenVisitRule(int R)
1170 {
1171     int SO;
1172     int VN;
1173     int VisitNo;
1174     int i;
1175     int S;
1176     int NontCnt;
1177     bool onlyoneVisit;
1178     bool first;
1179     bool PosNeeded;
1180 
1181     output.writeln("void VisitRule", R, "(long Symbol, int VisitNo)");
1182     output.writeln("/*");
1183     Protocol.output = output;
1184     output.write(" * ");
1185     Protocol.WriteRule(R);
1186     output.writeln(" */");
1187     Protocol.output = stdout;
1188     output.writeln("{");
1189     GenVarDecls(R);
1190     NontCnt = 1;
1191     for (SO = SOAG.Rule[R].SymOcc.Beg + 1; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
1192         if (!SOAG.IsPredNont(SO))
1193             ++NontCnt;
1194     SO = SOAG.Rule[R].SymOcc.Beg;
1195     output.writeln("if (VisitNo == syntacticPart)");
1196     output.writeln("{");
1197     output.writeln("if (NextSemTree >= SemTree.length - ", NontCnt, ") ExpandSemTree;");
1198     output.writeln("TreeAdr = SemTree[Symbol].Adr;");
1199     output.writeln("SemTree[Symbol].Adr = NextSemTree;");
1200     output.writeln("SemTree[Symbol].Pos = PosTree[TreeAdr];");
1201     output.writeln("AffixVarCount += ", GetAffixCount(R), ";");
1202     if (AffixVarCount[R] > 0)
1203     {
1204         output.writeln("if (NextVar >= Var.length - ", AffixVarCount[R], ") ExpandVar;");
1205         output.writeln("SemTree[Symbol].VarInd = NextVar; NextVar += ", AffixVarCount[R], ";");
1206     }
1207     else
1208     {
1209         output.writeln("SemTree[Symbol].VarInd = nil;");
1210     }
1211     output.writeln("SemTree[NextSemTree] = SemTree[Symbol];");
1212     output.writeln("++NextSemTree;");
1213     for (SO = SOAG.Rule[R].SymOcc.Beg + 1; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
1214     {
1215         if (!SOAG.IsPredNont(SO))
1216         {
1217             output.writeln("S = new SemTreeEntry;");
1218             output.writeln("S.Adr = Tree[TreeAdr + ", SubTreeOffset[SO], "];");
1219             output.writeln("S.Rule = ", FirstRule[SOAG.SymOcc[SO].SymInd] - 1, " + MOD(Tree[S.Adr], hyperArityConst);");
1220             output.writeln("SemTree[NextSemTree] = S; ++NextSemTree;");
1221         }
1222     }
1223     first = true;
1224     for (SO = SOAG.Rule[R].SymOcc.Beg + 1; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
1225     {
1226         if (!SOAG.IsPredNont(SO))
1227         {
1228             if (first)
1229             {
1230                 output.writeln("TreeAdr = SemTree[Symbol].Adr;");
1231                 first = false;
1232             }
1233             output.writeln("Visit(TreeAdr + ", SubTreeOffset[SO], ", syntacticPart);");
1234         }
1235     }
1236     output.writeln("}");
1237     output.writeln("else");
1238     output.writeln("{");
1239     output.writeln("TreeAdr = SemTree[Symbol].Adr;");
1240     if (AffixVarCount[R] > 0)
1241         output.writeln("VI = SemTree[Symbol].VarInd;");
1242     if (VisitSeq.GetMaxVisitNo(SOAG.Rule[R].SymOcc.Beg) == 1)
1243     {
1244         onlyoneVisit = true;
1245     }
1246     else
1247     {
1248         onlyoneVisit = false;
1249         output.writeln("switch (VisitNo)");
1250         output.writeln("{");
1251         output.writeln("case 1:");
1252     }
1253     VisitNo = 1;
1254     PosNeeded = true;
1255     output.writeln("// Visit-beginnende Analyse");
1256     GenAnalPred(SOAG.Rule[R].SymOcc.Beg, VisitNo);
1257     for (i = SOAG.Rule[R].VS.Beg; i <= SOAG.Rule[R].VS.End; ++i)
1258     {
1259         if (auto visit = cast(SOAG.Visit) SOAG.VS[i])
1260         {
1261             SO = visit.SymOcc;
1262             S = SOAG.SymOcc[SO].SymInd;
1263             VN = visit.VisitNo;
1264             output.writeln("// Synthese");
1265             GenSynPred(SO, VN);
1266             GenVisitCall(SO, VN);
1267             output.writeln("// Analyse");
1268             GenAnalPred(SO, VN);
1269             output.writeln;
1270             PosNeeded = true;
1271         }
1272         else if (auto call = cast(SOAG.Call) SOAG.VS[i])
1273         {
1274             SO = call.SymOcc;
1275             output.writeln("// Synthese");
1276             GenSynPred(SO, -1);
1277             GenPredPos(R, i, PosNeeded);
1278             GenPredCall(SO);
1279             output.writeln("// Analyse");
1280             GenAnalPred(SO, -1);
1281             output.writeln;
1282         }
1283         else if (auto leave = cast(SOAG.Leave) SOAG.VS[i])
1284         {
1285             SO = SOAG.Rule[R].SymOcc.Beg;
1286             VN = leave.VisitNo;
1287 
1288             assert(VN == VisitNo);
1289 
1290             output.writeln("// Visit-abschließende Synthese");
1291             GenSynPred(SO, VisitNo);
1292             GenLeave(VisitNo);
1293             if (VisitNo < VisitSeq.GetMaxVisitNo(SO))
1294             {
1295                 output.writeln("break;");
1296                 ++VisitNo;
1297                 PosNeeded = true;
1298                 output.writeln("case ", VisitNo, ":");
1299                 output.writeln("// Visit-beginnende Analyse");
1300                 GenAnalPred(SO, VisitNo);
1301             }
1302             else
1303             {
1304                 if (!onlyoneVisit)
1305                     output.writeln("break;");
1306             }
1307         }
1308     }
1309     if (!onlyoneVisit)
1310     {
1311         output.writeln("default:");
1312         output.writeln("assert(0);");
1313         output.writeln("}");
1314     }
1315     output.writeln("}");
1316     output.writeln("}");
1317     output.writeln;
1318 }
1319 
1320 /**
1321  * SEM: Generierung der Prozedur 'Visit', die die Besuche auf die entsprechenden Regeln verteilt
1322  */
1323 private void GenVisit()
1324 {
1325     output.writeln("void Visit(long Symbol, int VisitNo)");
1326     output.writeln("{");
1327     output.writeln("switch (SemTree[Symbol].Rule)");
1328     output.writeln("{");
1329     for (int R = SOAG.firstRule; R < SOAG.NextRule; ++R)
1330     {
1331         if (SOAG.IsEvaluatorRule(R))
1332         {
1333             output.write("case ", R, ": ");
1334             output.writeln("VisitRule", R, "(Symbol, VisitNo); break;");
1335         }
1336     }
1337     output.writeln("default:");
1338     output.writeln("assert(0);");
1339     output.writeln("}");
1340     output.writeln("}");
1341     output.writeln;
1342 }
1343 
1344 /**
1345  * SEM: Generierung der Konstanten für den Zugriff auf AffPos[] im generierten Compiler
1346  */
1347 private void GenConstDeclarations() @safe
1348 {
1349     for (int S = SOAG.firstSym; S < SOAG.NextSym; ++S)
1350     {
1351         output.write("const S", S, " = ");
1352         output.write(SOAG.Sym[S].AffPos.Beg, "; // ");
1353         output.write(EAG.HNontRepr(S));
1354         output.writeln;
1355     }
1356 }
1357 
1358 /**
1359  * SEM: Generierung der Deklarationen der globalen Variablen und Stacks
1360  */
1361 private void GenStackDeclarations() @safe
1362 {
1363     if (optimizer.GlobalVar > 0 || optimizer.StackVar > 0)
1364     {
1365         for (int V = optimizer.firstGlobalVar; V <= optimizer.GlobalVar; ++V)
1366             output.writeln("HeapType GV", V, ";");
1367         for (int V = optimizer.firstStackVar; V <= optimizer.StackVar; ++V)
1368             output.writeln("Stacks.Stack Stack", V, ";");
1369         output.writeln;
1370     }
1371 }
1372 
1373 /**
1374  * SEM: Generierung der Initialisierungen der Stacks
1375  */
1376 private void GenStackInit() @safe
1377 {
1378     if (optimizer.StackVar > 0)
1379     {
1380         for (int S = optimizer.firstStackVar; S <= optimizer.StackVar; ++S)
1381             output.writeln("Stacks.New(Stack", S, ", 8);");
1382     }
1383 }
1384 
1385 /**
1386  * SEM: Generierung des Compiler-Moduls
1387  */
1388 private string GenerateModule(Settings settings)
1389 {
1390     int R;
1391     Input Fix;
1392     int StartRule;
1393 
1394     void InclFix(char Term)
1395     {
1396         import std.conv : to;
1397         import std.exception : enforce;
1398 
1399         char c = Fix.front.to!char;
1400 
1401         while (c != Term)
1402         {
1403             enforce(c != 0,
1404                     "error: unexpected end of eSOAG.fix.d");
1405 
1406             output.write(c);
1407             Fix.popFront;
1408             c = Fix.front.to!char;
1409         }
1410         Fix.popFront;
1411     }
1412 
1413     enum fixName = "soag.fix.d";
1414     const name = EAG.BaseName ~ "Eval";
1415     const fileName = settings.path(name ~ ".d");
1416 
1417     Fix = Input(fixName, import(fixName));
1418     output = File(fileName, "w");
1419     SLAGGen.InitGen(output, SLAGGen.sweepPass, settings);
1420     InclFix('$');
1421     output.write(name);
1422     InclFix('$');
1423     output.write(HyperArity());
1424     InclFix('$');
1425     GenConstDeclarations;
1426     InclFix('$');
1427     if (Optimize)
1428         GenStackDeclarations;
1429     SLAGGen.GenDeclarations(settings);
1430     InclFix('$');
1431     SLAGGen.GenPredProcs;
1432     for (R = SOAG.firstRule; R < SOAG.NextRule; ++R)
1433     {
1434         if (SOAG.IsEvaluatorRule(R))
1435         {
1436             ComputeNodeNames(R);
1437             ComputeAffixOffset(R);
1438             GenVisitRule(R);
1439         }
1440     }
1441     GenVisit;
1442     EmitGen.GenEmitProc(output, settings);
1443     InclFix('$');
1444     output.write(SOAG.NextPartNum);
1445     InclFix('$');
1446     if (Optimize)
1447         GenStackInit;
1448     StartRule = FirstRule[SOAG.SymOcc[SOAG.Sym[EAG.StartSym].FirstOcc].RuleInd];
1449     InclFix('$');
1450     if (StartRule - 1 != 0)
1451         output.write(StartRule - 1, " + ");
1452     InclFix('$');
1453     output.write("S", EAG.StartSym);
1454     InclFix('$');
1455     EmitGen.GenEmitCall(output, settings);
1456     InclFix('$');
1457     EmitGen.GenShowHeap(output);
1458     InclFix('$');
1459     if (Optimize)
1460         output.write(optimizer.StackVar);
1461     else
1462         output.write(0);
1463     InclFix('$');
1464     if (Optimize)
1465         output.write(optimizer.GlobalVar);
1466     else
1467         output.write(0);
1468     InclFix('$');
1469     output.write(EAG.BaseName);
1470     output.write("Eval");
1471     InclFix('$');
1472     output.flush;
1473     SLAGGen.FinitGen;
1474     output.close;
1475     return fileName;
1476 }