1 module epsilon.slaggen;
2 
3 import core.time : MonoTime;
4 import EAG = epsilon.eag;
5 import epsilon.settings;
6 import io : Input, Position, read;
7 import log;
8 import runtime;
9 import std.algorithm;
10 import std.bitmanip : BitArray;
11 import std.stdio;
12 import std.typecons;
13 
14 public const parsePass = 0;
15 public const onePass = 1;
16 public const sweepPass = 2;
17 public int[] NodeIdent;
18 public int[] Leaf;
19 public int[] AffixPlace;
20 public int[] AffixSpace;
21 
22 private File output;
23 private bool SavePos;
24 private bool UseConst;
25 private bool UseRefCnt;
26 private bool TraversePass;
27 private int[] VarCnt;
28 private int[] VarAppls;
29 private bool Testing;
30 private bool Generating;
31 private BitArray PreparedHNonts;
32 private int[] VarDeps;
33 private int FirstHeap;
34 private int MaxMAlt;
35 private long RefConst;
36 private int[] AffixName;
37 private BitArray HNontDef;
38 private int[] HNontVars;
39 private int[] HNontFVars;
40 private bool[] RepAppls;
41 private int[] FormalName;
42 private int[] VarRefCnt;
43 private int[] VarDepPos;
44 private int[] VarName;
45 private int[] NodeName;
46 private int IfLevel;
47 private int[] ActualName;
48 private BitArray RepVar;
49 private BitArray EmptySet;
50 
51 public void Test()
52 in (EAG.Performed(EAG.analysed | EAG.predicates))
53 {
54     auto type = Type.slag;
55 
56     info!"SLAG testing %s"(EAG.BaseName);
57     EAG.History &= ~EAG.isSLAG;
58 
59     InitTest;
60     scope (exit)
61         FinitTest;
62 
63     foreach (N; EAG.Prod.bitsSet)
64         if (EAG.HNont[N].Id >= 0)
65             type = min(type, TestHNont(N, Yes.checkSLAG));
66 
67     final switch (type) with (Type)
68     {
69         case neither:
70             info!"%s grammar is no LAG"(EAG.BaseName);
71             break;
72         case lag:
73             info!"%s grammar is no SLAG but LAG"(EAG.BaseName);
74             break;
75         case slag:
76             info!"%s grammar is SLAG"(EAG.BaseName);
77             EAG.History |= EAG.isSLAG;
78             break;
79     }
80 }
81 
82 public void InitTest() nothrow
83 {
84     if (!Generating && !Testing)
85         PrepareInit;
86     Testing = true;
87 }
88 
89 public void FinitTest() nothrow
90 {
91     if (!Generating)
92         PrepareFinit;
93     Testing = false;
94 }
95 
96 public bool PredsOK()
97 {
98     return EAG.Pred.bitsSet
99         .map!(N => IsLAG(N))
100         .all;
101 }
102 
103 public bool IsLAG(size_t N)
104 {
105     return TestHNont(N) != Type.neither;
106 }
107 
108 private Type TestHNont(size_t N, Flag!"checkSLAG" checkSLAG = No.checkSLAG)
109 in (EAG.Prod[N])
110 {
111     auto type = Type.slag;
112 
113     void CheckDefPos(EAG.ParamRecord param)
114     {
115         void DefPos(int Node)
116         {
117             if (Node < 0)
118             {
119                 EAG.Var[-Node].Def = true;
120             }
121             else
122             {
123                 foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
124                     DefPos(EAG.NodeBuf[Node + n + 1]);
125             }
126         }
127 
128         if (param.isDef)
129             DefPos(param.Affixform);
130     }
131 
132     void CheckApplPos(EAG.ParamRecord param)
133     {
134         void ApplPos(int Node)
135         {
136             if (Node < 0)
137             {
138                 const V = -Node;
139 
140                 if (!EAG.Var[V].Def)
141                 {
142                     error!"not left-defining\n%s"(EAG.Var[V].Pos);
143                     type = Type.neither;
144                 }
145             }
146             else
147             {
148                 foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
149                     ApplPos(EAG.NodeBuf[Node + n + 1]);
150             }
151         }
152 
153         if (!param.isDef)
154             ApplPos(param.Affixform);
155     }
156 
157     void CheckSLAGCond(EAG.ParamRecord param)
158     {
159         const Node = param.Affixform;
160 
161         if (param.isDef)
162         {
163             if (Node >= 0)
164             {
165                 error!"cannot analyze bottom up\n%s"(param.Pos);
166                 type = min(type, Type.lag);
167             }
168             else if (EAG.Var[-Node].Def)
169             {
170                 error!"cannot check for equality bottom up\n%s"(param.Pos);
171                 type = min(type, Type.lag);
172             }
173             else if (EAG.Var[EAG.Var[-Node].Neg].Def)
174             {
175                 error!"cannot check for inequality bottom up\n%s"(param.Pos);
176                 type = min(type, Type.lag);
177             }
178             else if (VarAppls[-Node] > 1)
179             {
180                 error!"cannot synthesize %s times bottom up\n%s"(VarAppls[-Node], param.Pos);
181                 type = min(type, Type.lag);
182             }
183         }
184     }
185 
186     Prepare(N);
187 
188     EAG.Rule Node = EAG.HNont[N].Def;
189 
190     if (auto rep = cast(EAG.Rep) Node)
191     {
192         InitScope(rep.Scope);
193         rep.Formal.params.each!(param => CheckDefPos(param));
194         rep.Formal.params.each!(param => CheckApplPos(param));
195     }
196     else if (auto opt = cast(EAG.Opt) Node)
197     {
198         InitScope(opt.Scope);
199         opt.Formal.params.each!(param => CheckDefPos(param));
200         opt.Formal.params.each!(param => CheckApplPos(param));
201     }
202 
203     EAG.Alt A = Node.Sub;
204 
205     do
206     {
207         InitScope(A.Scope);
208         A.Formal.params.each!(param => CheckDefPos(param));
209 
210         EAG.Factor F = A.Sub;
211 
212         while (F !is null)
213         {
214             if (auto nont = cast(EAG.Nont) F)
215             {
216                 nont.Actual.params.each!(param => CheckApplPos(param));
217                 if (checkSLAG && EAG.HNont[nont.Sym].anonymous)
218                     type = min(type, TestHNont(nont.Sym, checkSLAG));
219                 nont.Actual.params.each!(param => CheckDefPos(param));
220             }
221             F = F.Next;
222         }
223         if (cast(EAG.Rep) Node !is null)
224         {
225             A.Actual.params.each!(param => CheckApplPos(param));
226             foreach (param; A.Actual.params)
227             {
228                 if (checkSLAG)
229                     CheckSLAGCond(param);
230                 CheckDefPos(param);
231             }
232         }
233         A.Formal.params.each!(param => CheckApplPos(param));
234         A = A.Next;
235     }
236     while (A !is null);
237     return type;
238 }
239 
240 private enum Type
241 {
242     neither,
243     lag,
244     slag,
245 }
246 
247 private void Prepare(size_t N) nothrow
248 {
249     void Traverse(EAG.ParamRecord[] params)
250     {
251         void DefPos(int Node)
252         {
253             if (Node < 0)
254             {
255                 ++VarCnt[-Node];
256             }
257             else
258             {
259                 foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
260                     DefPos(EAG.NodeBuf[Node + n + 1]);
261             }
262         }
263 
264         void ApplPos(int Node)
265         {
266             if (Node < 0)
267             {
268                 ++VarCnt[-Node];
269                 ++VarAppls[-Node];
270             }
271             else
272             {
273                 foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
274                     ApplPos(EAG.NodeBuf[Node + n + 1]);
275             }
276         }
277 
278         foreach (param; params)
279             if (param.isDef)
280                 DefPos(param.Affixform);
281             else
282                 ApplPos(param.Affixform);
283     }
284 
285     void InitArray(EAG.ScopeDesc Scope)
286     {
287         foreach (i; Scope.Beg .. Scope.End)
288         {
289             VarCnt[i] = 0;
290             VarAppls[i] = 0;
291         }
292     }
293 
294     if (!PreparedHNonts[N])
295     {
296         EAG.Rule Node = EAG.HNont[N].Def;
297 
298         if (auto rep = cast(EAG.Rep) Node)
299         {
300             InitArray(rep.Scope);
301             Traverse(rep.Formal.params);
302         }
303         else if (auto opt = cast(EAG.Opt) Node)
304         {
305             InitArray(opt.Scope);
306             Traverse(opt.Formal.params);
307         }
308 
309         EAG.Alt A = Node.Sub;
310 
311         do
312         {
313             InitArray(A.Scope);
314             Traverse(A.Formal.params);
315 
316             EAG.Factor F = A.Sub;
317 
318             while (F !is null)
319             {
320                 if (auto nont = cast(EAG.Nont) F)
321                     Traverse(nont.Actual.params);
322                 F = F.Next;
323             }
324             if (cast(EAG.Rep) Node !is null)
325             {
326                 Traverse(A.Actual.params);
327                 foreach (param; A.Actual.params)
328                     if (param.isDef && param.Affixform < 0)
329                         RepVar[-param.Affixform] = true;
330             }
331             A = A.Next;
332         }
333         while (A !is null);
334         PreparedHNonts[N] = true;
335     }
336 }
337 
338 public void InitGen(File MOut, int Treatment, Settings settings)
339 {
340     void SetFlags(int Treatment)
341     {
342         switch (Treatment)
343         {
344         case parsePass:
345             SavePos = true;
346             UseConst = false;
347             UseRefCnt = false;
348             break;
349         case onePass:
350             break;
351         case sweepPass:
352             TraversePass = true;
353             break;
354         default:
355             assert(0);
356         }
357     }
358 
359     if (Generating)
360         trace!"resetting SLAG";
361     output = MOut;
362     SavePos = false;
363     TraversePass = false;
364     UseConst = !settings.c;
365     UseRefCnt = !settings.r;
366     SetFlags(Treatment);
367     info!"%s %s"(UseRefCnt ? "+rc" : "-rc", UseConst ? "+ct" : "-ct");
368     if (!Testing)
369         PrepareInit;
370     ComputeNodeIdent;
371     ComputeConstDat;
372     AffixName = new int[EAG.NextParam];
373     foreach (i; EAG.firstParam .. EAG.NextParam)
374         AffixName[i] = -1;
375     NodeName = new int[EAG.NextNode];
376     VarName = new int[EAG.NextVar];
377     VarDeps = new int[EAG.NextVar];
378     VarRefCnt = new int[EAG.NextVar];
379     VarDepPos = new int[EAG.NextVar];
380     foreach (i; EAG.firstVar .. EAG.NextVar)
381     {
382         VarRefCnt[i] = 0;
383         VarDepPos[i] = -1;
384         VarName[i] = -1;
385     }
386     ActualName = new int[EAG.NextDom];
387     FormalName = new int[EAG.NextDom];
388     foreach (i; EAG.firstDom .. EAG.NextDom)
389     {
390         ActualName[i] = -1;
391         FormalName[i] = -1;
392     }
393     HNontVars = new int[EAG.NextHNont];
394     HNontFVars = new int[EAG.NextHNont];
395     HNontDef = BitArray();
396     HNontDef.length = EAG.NextHNont + 1;
397     RepAppls = new bool[EAG.NextHNont];
398     foreach (i; EAG.firstHNont .. EAG.NextHNont)
399         RepAppls[i] = true;
400     EmptySet = BitArray();
401     EmptySet.length = EAG.NextVar + 1;
402     Generating = true;
403 }
404 
405 private void PrepareInit() nothrow
406 {
407     VarCnt = new int[EAG.NextVar];
408     VarAppls = new int[EAG.NextVar];
409     RepVar = BitArray();
410     RepVar.length = EAG.NextVar + 1;
411     PreparedHNonts = BitArray();
412     PreparedHNonts.length = EAG.NextHNont + 1;
413 }
414 
415 private void ComputeNodeIdent() nothrow @safe
416 {
417     int i;
418 
419     NodeIdent = new int[EAG.NextMAlt];
420     foreach (A; EAG.firstMAlt .. EAG.NextMAlt)
421         NodeIdent[A] = -1;
422     MaxMAlt = 0;
423     foreach (N; EAG.firstMNont .. EAG.NextMNont)
424     {
425         int A = EAG.MNont[N].MRule;
426 
427         i = 0;
428         while (A != EAG.nil)
429         {
430             ++i;
431             NodeIdent[A] = i;
432             A = EAG.MAlt[A].Next;
433         }
434         if (i > MaxMAlt)
435             MaxMAlt = i;
436     }
437     i = 1;
438     while (i <= MaxMAlt)
439         i = i * 2;
440     MaxMAlt = i;
441     RefConst = 0;
442     foreach (A; EAG.firstMAlt .. EAG.NextMAlt)
443     {
444         assert(NodeIdent[A] >= 0);
445 
446         NodeIdent[A] = NodeIdent[A] + EAG.MAlt[A].Arity * MaxMAlt;
447         if (RefConst < NodeIdent[A])
448             RefConst = NodeIdent[A];
449     }
450     i = 1;
451     while (i <= RefConst)
452         i = i * 2;
453     RefConst = i;
454 }
455 
456 private void ComputeConstDat() nothrow
457 {
458     void Traverse(size_t N, ref int ConstPtr)
459     {
460         void CheckParams(int P, ref int ConstPtr)
461         {
462             bool isConst;
463 
464             void TraverseTree(int Node, ref int Next)
465             {
466                 if (Node < 0)
467                 {
468                     isConst = false;
469                 }
470                 else
471                 {
472                     const Arity = EAG.MAlt[EAG.NodeBuf[Node]].Arity;
473 
474                     if (!UseConst || Arity != 0)
475                         Next += 1 + Arity;
476                     foreach (n; 0 .. Arity)
477                         TraverseTree(EAG.NodeBuf[Node + n + 1], Next);
478                 }
479             }
480 
481             while (EAG.ParamBuf[P].Affixform != EAG.nil)
482             {
483                 const Tree = EAG.ParamBuf[P].Affixform;
484 
485                 isConst = true;
486                 TraverseTree(Tree, AffixSpace[P]);
487                 if (Tree > 0 && EAG.MAlt[EAG.NodeBuf[Tree]].Arity == 0)
488                 {
489                     if (isConst)
490                         AffixPlace[P] = Leaf[EAG.NodeBuf[Tree]];
491                 }
492                 else
493                 {
494                     if (isConst)
495                     {
496                         AffixPlace[P] = ConstPtr;
497                         ConstPtr += AffixSpace[P];
498                     }
499                 }
500                 ++P;
501             }
502         }
503 
504         EAG.Rule Node = EAG.HNont[N].Def;
505 
506         if (auto rep = cast(EAG.Rep) Node)
507             CheckParams(rep.Formal.Params, ConstPtr);
508         else if (auto opt = cast(EAG.Opt) Node)
509             CheckParams(opt.Formal.Params, ConstPtr);
510 
511         EAG.Alt A = Node.Sub;
512 
513         do
514         {
515             CheckParams(A.Formal.Params, ConstPtr);
516 
517             EAG.Factor F = A.Sub;
518 
519             while (F !is null)
520             {
521                 if (auto nont = cast(EAG.Nont) F)
522                     CheckParams(nont.Actual.Params, ConstPtr);
523                 F = F.Next;
524             }
525             if (cast(EAG.Rep) Node)
526                 CheckParams(A.Actual.Params, ConstPtr);
527             A = A.Next;
528         }
529         while (A !is null);
530     }
531 
532     AffixSpace = new int[EAG.NextParam];
533     AffixPlace = new int[EAG.NextParam];
534     foreach (i; EAG.firstParam .. EAG.NextParam)
535     {
536         AffixSpace[i] = 0;
537         AffixPlace[i] = -1;
538     }
539     Leaf = new int[EAG.NextMAlt];
540 
541     int ConstPtr = EAG.MaxMArity + 1;
542 
543     FirstHeap = ConstPtr;
544     foreach (A; EAG.firstMAlt .. EAG.NextMAlt)
545     {
546         if (EAG.MAlt[A].Arity == 0)
547         {
548             Leaf[A] = ConstPtr;
549             ++ConstPtr;
550         }
551         else
552         {
553             Leaf[A] = -1;
554         }
555     }
556     foreach (i; EAG.Prod.bitsSet)
557         Traverse(i, ConstPtr);
558     if (UseConst)
559         FirstHeap = ConstPtr;
560 }
561 
562 public void FinitGen()
563 {
564     if (!Testing)
565         PrepareFinit;
566     EmptySet.length = 0;
567     NodeIdent = null;
568     AffixSpace = null;
569     AffixPlace = null;
570     Leaf = null;
571     AffixName = null;
572     NodeName = null;
573     VarName = null;
574     VarDeps = null;
575     VarRefCnt = null;
576     VarDepPos = null;
577     ActualName = null;
578     FormalName = null;
579     HNontVars = null;
580     HNontFVars = null;
581     RepAppls = null;
582     Generating = false;
583 }
584 
585 private void PrepareFinit() nothrow
586 {
587     VarCnt = null;
588     VarAppls = null;
589     RepVar.length = 0;
590     PreparedHNonts.length = 0;
591 }
592 
593 public void GenRepStart(int Sym) @safe
594 {
595     if (!UseRefCnt)
596     {
597         import std.conv : to;
598 
599         const Next = (cast(EAG.Rep) EAG.HNont[Sym].Def).Sub.Formal.params
600             .count!(param => !param.isDef)
601             .to!int;
602 
603         GenOverflowGuard(Next);
604     }
605 
606     int Dom = EAG.HNont[Sym].Sig;
607     int P = (cast(EAG.Rep) EAG.HNont[Sym].Def).Sub.Formal.Params;
608 
609     while (EAG.DomBuf[Dom] != EAG.nil)
610     {
611         if (!EAG.ParamBuf[P].isDef)
612         {
613             if (UseRefCnt)
614             {
615                 output.write("GetHeap(0, ");
616                 GenVar(FormalName[Dom]);
617                 output.write("); ");
618             }
619             else
620             {
621                 GenVar(FormalName[Dom]);
622                 output.write(" = NextHeap; ++NextHeap; ");
623             }
624             GenVar(AffixName[P]);
625             output.write(" = ");
626             GenVar(FormalName[Dom]);
627             output.writeln(";");
628         }
629         ++P;
630         ++Dom;
631     }
632 }
633 
634 public void GenDeclarations(Settings settings)
635 {
636     Input Fix;
637 
638     void InclFix(char Term)
639     {
640         import std.conv : to;
641         import std.exception : enforce;
642 
643         char c = Fix.front.to!char;
644 
645         while (c != Term)
646         {
647             enforce(c != 0,
648                     "error: unexpected end of eSLAGGen.fix.d");
649 
650             output.write(c);
651             Fix.popFront;
652             c = Fix.front.to!char;
653         }
654         Fix.popFront;
655     }
656 
657     void SkipFix(char Term)
658     {
659         import std.conv : to;
660         import std.exception : enforce;
661 
662         char c = Fix.front.to!char;
663 
664         while (c != Term)
665         {
666             enforce(c != 0,
667                     "error: unexpected end of eSLAGGen.fix.d");
668 
669             Fix.popFront;
670             c = Fix.front.to!char;
671         }
672         Fix.popFront;
673     }
674 
675     void GenTabFile(string name, long TabTimeStamp)
676     {
677         const errVal = 0;
678         const magic = 1_818_326_597;
679         int[] Heap;
680 
681         void SynTree(int Node, ref int Next)
682         {
683             const Next1 = Next;
684 
685             Heap[Next] = NodeIdent[EAG.NodeBuf[Node]];
686             Next += 1 + EAG.MAlt[EAG.NodeBuf[Node]].Arity;
687             foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
688             {
689                 const Node1 = EAG.NodeBuf[Node + n + 1];
690 
691                 if (EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
692                 {
693                     Heap[Next1 + n + 1] = Leaf[EAG.NodeBuf[Node1]];
694                 }
695                 else
696                 {
697                     Heap[Next1 + n + 1] = Next;
698                     SynTree(Node1, Next);
699                 }
700             }
701         }
702 
703         File Tab = File(settings.path(name), "w");
704 
705         Tab.writefln!"long %s"(magic);
706         Tab.writefln!"long %s"(TabTimeStamp);
707         Tab.writefln!"long %s"(FirstHeap - 1);
708         Heap = new int[FirstHeap];
709         Heap[errVal] = 0;
710         foreach (i; 0 .. EAG.MaxMArity)
711             Heap[i + 1] = errVal;
712         if (UseConst)
713         {
714             foreach (i; EAG.firstMAlt .. EAG.NextMAlt)
715             {
716                 if (Leaf[i] >= errVal)
717                     Heap[Leaf[i]] = NodeIdent[i];
718             }
719             foreach (P; EAG.firstParam .. EAG.NextParam)
720             {
721                 if (EAG.ParamBuf[P].Affixform != EAG.nil && AffixPlace[P] >= 0)
722                 {
723                     int Next = AffixPlace[P];
724 
725                     SynTree(EAG.ParamBuf[P].Affixform, Next);
726                 }
727             }
728         }
729         foreach (i; 0 .. FirstHeap)
730             Tab.writefln!"long %s"(Heap[i]);
731         Tab.writefln!"long %s"(TabTimeStamp);
732     }
733 
734     enum fixName = "slaggen.fix.d";
735     const name = EAG.BaseName ~ (TraversePass ? "Eval.EvalTab" : ".EvalTab");
736     const TabTimeStamp = MonoTime.currTime.ticks;
737 
738     Fix = Input(fixName, import(fixName));
739     InclFix('$');
740     output.write(FirstHeap - 1);
741     InclFix('$');
742     output.write(MaxMAlt);
743     InclFix('$');
744     if (SavePos)
745         output.write("Eval.TreeType");
746     else
747         output.write("long");
748     InclFix('$');
749     if (SavePos)
750         output.write("Eval.TreeType[]");
751     else
752         output.write("HeapType[]");
753     InclFix('$');
754     if (SavePos)
755         InclFix('$');
756     else
757         SkipFix('$');
758     InclFix('$');
759     output.write(EAG.MaxMArity + 1);
760     InclFix('$');
761     output.write(RefConst);
762     InclFix('$');
763     if (SavePos)
764     {
765         SkipFix('$');
766         InclFix('$');
767     }
768     else
769     {
770         InclFix('$');
771         SkipFix('$');
772     }
773     if (UseRefCnt)
774     {
775         InclFix('$');
776         SkipFix('$');
777     }
778     else
779     {
780         SkipFix('$');
781         InclFix('$');
782     }
783     InclFix('$');
784     if (!TraversePass)
785         output.write("S.");
786     InclFix('$');
787     if (UseRefCnt)
788         InclFix('$');
789     else
790         SkipFix('$');
791     InclFix('$');
792     output.write(name);
793     InclFix('$');
794     output.write(TabTimeStamp);
795     InclFix('$');
796     if (SavePos)
797         InclFix('$');
798     else
799         SkipFix('$');
800     InclFix('$');
801     GenTabFile(name, TabTimeStamp);
802 }
803 
804 public bool PosNeeded(int P) @nogc nothrow @safe
805 {
806     while (EAG.ParamBuf[P].Affixform != EAG.nil)
807     {
808         if (EAG.ParamBuf[P].isDef)
809         {
810             const V = -EAG.ParamBuf[P].Affixform;
811 
812             if (V < 0)
813                 return true;
814             else if (EAG.Var[V].Def)
815                 return true;
816             else if (EAG.Var[EAG.Var[V].Neg].Def)
817                 return true;
818         }
819         ++P;
820     }
821     return false;
822 }
823 
824 public void GenRepAlt(int Sym, EAG.Alt A)
825 {
826     int P;
827     int P1;
828     int Dom;
829     const Guard = !RepAppls[Sym];
830 
831     GenSynPred(Sym, A.Actual.Params);
832     if (SavePos)
833         output.writeln("PushPos;");
834     P = A.Actual.Params;
835     Dom = EAG.HNont[Sym].Sig;
836     while (EAG.ParamBuf[P].Affixform != EAG.nil)
837     {
838         if (!EAG.ParamBuf[P].isDef && AffixName[P] != FormalName[Dom])
839         {
840             GenVar(FormalName[Dom]);
841             output.write(" = ");
842             GenVar(AffixName[P]);
843             output.writeln(";");
844         }
845         ++P;
846         ++Dom;
847     }
848     P1 = A.Actual.Params;
849     Dom = EAG.HNont[Sym].Sig;
850     P = A.Formal.Params;
851     if (!UseRefCnt)
852         GetAffixSpace(P);
853     GenHangIn(P, Guard);
854 
855     int Next = 0;
856 
857     while (EAG.ParamBuf[P].Affixform != EAG.nil)
858     {
859         if (!EAG.ParamBuf[P].isDef)
860         {
861             const Tree = EAG.ParamBuf[P].Affixform;
862 
863             if (SavePos)
864                 output.writeln("PopPos(", EAG.MAlt[EAG.NodeBuf[Tree]].Arity, ");");
865             if (Tree > 0 && !(UseConst && AffixPlace[P] >= 0))
866             {
867                 if (Guard)
868                 {
869                     output.write("if (");
870                     GenVar(NodeName[Tree]);
871                     output.writeln(" != undef)");
872                     output.writeln("{");
873                 }
874                 if (UseRefCnt)
875                     Gen1SynTree(Tree, RepVar, EAG.Pred[Sym]);
876                 else
877                     GenSynTree(Tree, RepVar, Next);
878                 output.writeln;
879                 if (Guard)
880                     output.writeln("}");
881             }
882             if (Guard && VarAppls[-EAG.ParamBuf[P1].Affixform] == 0)
883             {
884                 GenVar(AffixName[P1]);
885                 output.writeln(" = undef;");
886             }
887         }
888         ++P;
889         ++P1;
890         ++Dom;
891     }
892     if (!UseRefCnt)
893         GenHeapInc(Next);
894 }
895 
896 public void GenRepEnd(int Sym)
897 {
898     const Guard = false; // TODO: eliminate dead code?
899 
900     InitScope((cast(EAG.Rep) EAG.HNont[Sym].Def).Scope);
901 
902     int P = (cast(EAG.Rep) EAG.HNont[Sym].Def).Formal.Params;
903     int P1 = EAG.HNont[Sym].Def.Sub.Actual.Params;
904     int Dom = EAG.HNont[Sym].Sig;
905     int Next = 0;
906 
907     GenAnalPred(Sym, P);
908     if (!UseRefCnt)
909         GetAffixSpace(P);
910     GenHangIn(P, Guard);
911     while (EAG.ParamBuf[P].Affixform != EAG.nil)
912     {
913         if (!EAG.ParamBuf[P].isDef)
914         {
915             const Tree = EAG.ParamBuf[P].Affixform;
916 
917             if (SavePos)
918                 output.writeln("PopPos(", EAG.MAlt[EAG.NodeBuf[Tree]].Arity, ");");
919             if (Tree > 0 && !(UseConst && AffixPlace[P] >= 0))
920             {
921                 if (Guard)
922                 {
923                     output.write("if (");
924                     GenVar(NodeName[Tree]);
925                     output.writeln(" != undef)");
926                     output.writeln("{");
927                 }
928                 if (UseRefCnt)
929                     Gen1SynTree(Tree, EmptySet, EAG.Pred[Sym]);
930                 else
931                     GenSynTree(Tree, EmptySet, Next);
932                 output.writeln("");
933                 if (Guard)
934                     output.writeln("}");
935             }
936             if (UseRefCnt)
937             {
938                 GenVar(AffixName[P]);
939                 output.write(" = ");
940                 GenVar(FormalName[Dom]);
941                 output.write("; ");
942             }
943             GenVar(FormalName[Dom]);
944             output.write(" = ");
945             GenHeap(FormalName[Dom], 0);
946             output.writeln(";");
947             if (UseRefCnt)
948             {
949                 GenHeap(AffixName[P], 0);
950                 output.writeln(" = 0;");
951                 output.write("FreeHeap(");
952                 GenVar(AffixName[P]);
953                 output.writeln(");");
954             }
955         }
956         ++P;
957         ++P1;
958         ++Dom;
959     }
960     if (!UseRefCnt)
961         GenHeapInc(Next);
962 }
963 
964 private void GenHangIn(int P, bool Guard)
965 {
966     void FreeVariables(int Node)
967     {
968         if (Node < 0)
969         {
970             if (!RepVar[-Node])
971             {
972                 output.write("FreeHeap(");
973                 GenVar(VarName[-Node]);
974                 output.write("); ");
975             }
976         }
977         else
978         {
979             foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
980                 FreeVariables(EAG.NodeBuf[Node + n + 1]);
981         }
982     }
983 
984     int Next = 0;
985 
986     while (EAG.ParamBuf[P].Affixform != EAG.nil)
987     {
988         if (!EAG.ParamBuf[P].isDef)
989         {
990             const Tree = EAG.ParamBuf[P].Affixform;
991             if (Guard)
992             {
993                 output.write("if (");
994                 GenVar(AffixName[P]);
995                 output.writeln(" != undef)");
996                 output.writeln("{");
997             }
998             if (UseConst && AffixPlace[P] >= 0)
999             {
1000                 GenHeap(AffixName[P], 0);
1001                 output.writeln(" = ", AffixPlace[P], ";");
1002                 if (UseRefCnt)
1003                     GenIncRefCnt(-AffixPlace[P], 1);
1004             }
1005             else if (Tree < 0)
1006             {
1007                 if (AffixName[P] != VarName[-Tree])
1008                 {
1009                     GenHeap(AffixName[P], 0);
1010                     output.write(" = ");
1011                     GenVar(VarName[-Tree]);
1012                     output.writeln(";");
1013                     if (Guard)
1014                     {
1015                         output.writeln("}");
1016                         output.writeln("else");
1017                         output.writeln("{");
1018                         output.write("FreeHeap(");
1019                         GenVar(VarName[-Tree]);
1020                         output.writeln(");");
1021                     }
1022                 }
1023             }
1024             else
1025             {
1026                 if (UseRefCnt)
1027                 {
1028                     output.write("GetHeap(", EAG.MAlt[EAG.NodeBuf[Tree]].Arity, ", ");
1029                     GenVar(NodeName[Tree]);
1030                     output.write("); ");
1031                     GenHeap(AffixName[P], 0);
1032                     output.write(" = ");
1033                     GenVar(NodeName[Tree]);
1034                     output.writeln(";");
1035                     if (Guard)
1036                     {
1037                         output.writeln("}");
1038                         output.writeln("else");
1039                         output.writeln("{");
1040                         FreeVariables(Tree);
1041                     }
1042                 }
1043                 else
1044                 {
1045                     GenHeap(AffixName[P], 0);
1046                     output.write(" = NextHeap");
1047                     if (Next != 0)
1048                         output.write(" + ", Next);
1049                     output.writeln(";");
1050                     Next += AffixSpace[P];
1051                     if (Guard)
1052                     {
1053                         output.writeln("}");
1054                         output.writeln("else");
1055                         output.writeln("{");
1056                     }
1057                 }
1058                 if (Guard)
1059                 {
1060                     GenVar(NodeName[Tree]);
1061                     output.writeln(" = undef;");
1062                 }
1063             }
1064             if (Guard)
1065                 output.writeln("}");
1066         }
1067         ++P;
1068     }
1069 }
1070 
1071 public void GenPredProcs()
1072 {
1073     void GenPredCover(size_t N)
1074     in (EAG.Pred[N])
1075     {
1076         output.write("void Check", N, "(string ErrMsg");
1077         GenFormalParams(N, No.parNeeded);
1078         output.writeln(")");
1079         output.writeln("{");
1080         output.write("if (!Pred", N, "(");
1081 
1082         int Dom = EAG.HNont[N].Sig;
1083         int i = 1;
1084 
1085         if (EAG.DomBuf[Dom] != EAG.nil)
1086         {
1087             while (true)
1088             {
1089                 GenVar(i);
1090                 ++Dom;
1091                 ++i;
1092                 if (EAG.DomBuf[Dom] == EAG.nil)
1093                     break;
1094                 output.write(", ");
1095             }
1096         }
1097         output.writeln("))");
1098         output.writeln("{");
1099         Dom = EAG.HNont[N].Sig;
1100         i = 1;
1101         while (EAG.DomBuf[Dom] > 0)
1102             ++Dom;
1103         if (EAG.DomBuf[Dom] != EAG.nil)
1104         {
1105             output.write("if (");
1106             while (true)
1107             {
1108                 GenVar(i);
1109                 output.write(" != errVal");
1110                 do
1111                 {
1112                     ++Dom;
1113                     ++i;
1114                 }
1115                 while (!(EAG.DomBuf[Dom] <= 0));
1116                 if (EAG.DomBuf[Dom] == EAG.nil)
1117                     break;
1118                 output.write(" && ");
1119             }
1120             output.writeln(")");
1121             output.writeln("PredError(ErrMsg);");
1122         }
1123         else
1124         {
1125             output.write("Error(ErrMsg);");
1126         }
1127         output.writeln("}");
1128         output.writeln("}");
1129         output.writeln;
1130     }
1131 
1132     void GenPredicateCode(size_t N)
1133     {
1134         EAG.Rule Node = EAG.HNont[N].Def;
1135         EAG.Alt A;
1136 
1137         void CleanLevel(int Level)
1138         {
1139             if (Level >= 1)
1140             {
1141                 foreach (i; 0 .. Level)
1142                     output.write("} ");
1143                 output.writeln;
1144             }
1145         }
1146 
1147         void FreeParamTrees(int P)
1148         {
1149             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1150             {
1151                 if (EAG.ParamBuf[P].isDef)
1152                     GenFreeHeap(AffixName[P]);
1153                 ++P;
1154             }
1155         }
1156 
1157         void TraverseFactor(EAG.Factor F, int FormalParams)
1158         {
1159             if (F !is null)
1160             {
1161                 auto nont = cast(EAG.Nont) F;
1162 
1163                 assert(nont !is null);
1164                 assert(EAG.Pred[nont.Sym]);
1165 
1166                 GenSynPred(N, nont.Actual.Params);
1167                 output.write("if (Pred", nont.Sym);
1168                 GenActualParams(nont.Actual.Params, true);
1169                 output.writeln(") // ", EAG.HNontRepr(nont.Sym));
1170                 output.writeln("{");
1171                 GenAnalPred(N, nont.Actual.Params);
1172 
1173                 const Level = IfLevel;
1174 
1175                 TraverseFactor(F.Next, FormalParams);
1176                 CleanLevel(Level);
1177                 output.writeln("}");
1178                 if (UseRefCnt)
1179                     FreeParamTrees(nont.Actual.Params);
1180             }
1181             else
1182             {
1183                 if (cast(EAG.Rep) Node)
1184                 {
1185                     GenSynPred(N, A.Actual.Params);
1186                     output.write("if (Pred", N);
1187                     GenActualParams(A.Actual.Params, true);
1188                     output.writeln(") // ", EAG.HNontRepr(N));
1189                     output.writeln("{");
1190                     GenAnalPred(N, A.Actual.Params);
1191 
1192                     const Level = IfLevel;
1193 
1194                     GenSynPred(N, FormalParams);
1195                     output.writeln("Failed = false;");
1196                     CleanLevel(Level);
1197                     output.writeln("}");
1198                     if (UseRefCnt)
1199                         FreeParamTrees(A.Actual.Params);
1200                 }
1201                 else
1202                 {
1203                     GenSynPred(N, FormalParams);
1204                     output.writeln("Failed = false;");
1205                 }
1206             }
1207         }
1208 
1209         int AltLevel = 0;
1210         int P;
1211 
1212         output.writeln("Failed = true;");
1213         if (cast(EAG.Rep) Node || cast(EAG.Opt) Node)
1214         {
1215             EAG.ScopeDesc Scope;
1216 
1217             if (auto opt = cast(EAG.Opt) Node)
1218             {
1219                 P = opt.Formal.Params;
1220                 Scope = opt.Scope;
1221             }
1222             else if (auto rep = cast(EAG.Rep) Node)
1223             {
1224                 P = rep.Formal.Params;
1225                 Scope = rep.Scope;
1226             }
1227             InitScope(Scope);
1228             GenAnalPred(N, P);
1229 
1230             const Level = IfLevel;
1231 
1232             GenSynPred(N, P);
1233             output.writeln("Failed = false;");
1234             CleanLevel(Level);
1235             ++AltLevel;
1236         }
1237         A = Node.Sub;
1238         while (true)
1239         {
1240             if (AltLevel > 0)
1241             {
1242                 output.writeln("if (Failed) // alternative #", AltLevel + 1);
1243                 output.writeln("{");
1244             }
1245             InitScope(A.Scope);
1246             GenAnalPred(N, A.Formal.Params);
1247 
1248             const Level = IfLevel;
1249 
1250             TraverseFactor(A.Sub, A.Formal.Params);
1251             CleanLevel(Level);
1252             ++AltLevel;
1253             A = A.Next;
1254             if (A is null)
1255             {
1256                 break;
1257             }
1258         }
1259         foreach (i; 1 .. AltLevel)
1260             output.write("} ");
1261         output.writeln;
1262         P = Node.Sub.Formal.Params;
1263         if (UseRefCnt)
1264             FreeParamTrees(P);
1265         output.writeln("if (Failed)");
1266         output.writeln("{");
1267         while (EAG.ParamBuf[P].Affixform != EAG.nil)
1268         {
1269             if (!EAG.ParamBuf[P].isDef)
1270             {
1271                 GenVar(AffixName[P]);
1272                 output.writeln(" = errVal;");
1273                 if (UseRefCnt)
1274                     output.writeln("Heap[errVal] += refConst;");
1275             }
1276             ++P;
1277         }
1278         output.writeln("}");
1279     }
1280 
1281     foreach (N; EAG.Pred.bitsSet)
1282         GenPredCover(N);
1283     foreach (N; EAG.Pred.bitsSet)
1284     {
1285         ComputeVarNames(N, No.embed);
1286         output.write("bool Pred", N);
1287         GenFormalParams(N, Yes.parNeeded);
1288         output.writeln(" // ", EAG.HNontRepr(N));
1289         output.writeln("{");
1290         GenVarDecl(N);
1291         GenPredicateCode(N);
1292         output.writeln("return !Failed;");
1293         output.writeln("}");
1294         output.writeln;
1295     }
1296 }
1297 
1298 public void ComputeVarNames(size_t N, Flag!"embed" embed)
1299 in (EAG.Prod[N])
1300 in (!HNontDef[N])
1301 {
1302     int[] FreeVar;
1303     int[] RefCnt;
1304     int Top;
1305     int NextFreeVar;
1306 
1307     void VarExpand()
1308     {
1309         if (NextFreeVar >= RefCnt.length)
1310         {
1311             auto Int = new int[2 * RefCnt.length];
1312 
1313             foreach (i; 0 .. NextFreeVar)
1314                 Int[i] = RefCnt[i];
1315             foreach (i; NextFreeVar .. Int.length)
1316                 Int[i] = 0;
1317             RefCnt = Int;
1318         }
1319         if (Top >= FreeVar.length)
1320         {
1321             auto Int = new int[2 * FreeVar.length];
1322 
1323             foreach (i; 0 .. Top)
1324                 Int[i] = FreeVar[i];
1325             FreeVar = Int;
1326         }
1327     }
1328 
1329     int GetFreeVar()
1330     {
1331         int Var;
1332 
1333         if (Top > 0)
1334         {
1335             --Top;
1336             Var = FreeVar[Top];
1337         }
1338         else
1339         {
1340             ++NextFreeVar;
1341             if (NextFreeVar >= RefCnt.length)
1342                 VarExpand;
1343             RefCnt[NextFreeVar] = 0;
1344             Var = NextFreeVar;
1345         }
1346         trace!"RC: -%s"(Var);
1347         return Var;
1348     }
1349 
1350     void Dispose(int Var)
1351     {
1352         --RefCnt[Var];
1353         if (RefCnt[Var] == 0)
1354         {
1355             trace!"RC: +%s"(Var);
1356             FreeVar[Top] = Var;
1357             ++Top;
1358             if (Top >= FreeVar.length)
1359                 VarExpand;
1360         }
1361     }
1362 
1363     void Traverse(size_t N)
1364     {
1365         EAG.Rule Node;
1366         EAG.Alt A;
1367         EAG.Factor F;
1368         int P;
1369         int Tree;
1370         bool isPred;
1371 
1372         void CheckDefPos(int P)
1373         {
1374             void DefPos(int Node, int Var)
1375             {
1376                 if (Node < 0)
1377                 {
1378                     const V = -Node;
1379 
1380                     if (!EAG.Var[V].Def)
1381                     {
1382                         EAG.Var[V].Def = true;
1383                         if (VarName[V] < 0)
1384                         {
1385                             VarName[V] = GetFreeVar;
1386                             ++RefCnt[VarName[V]];
1387                         }
1388                         if (EAG.Var[EAG.Var[V].Neg].Def)
1389                         {
1390                             const Vn = EAG.Var[V].Neg;
1391 
1392                             --VarDeps[V];
1393                             --VarDeps[Vn];
1394                             if (VarDeps[Vn] == 0)
1395                             {
1396                                 VarDepPos[Vn] = P;
1397                                 Dispose(VarName[Vn]);
1398                             }
1399                         }
1400                     }
1401                     else
1402                     {
1403                         if (VarDeps[V] == 1)
1404                             VarDepPos[V] = P;
1405                     }
1406                     --VarDeps[V];
1407                     if (VarDeps[V] == 0)
1408                         Dispose(VarName[V]);
1409                 }
1410                 else
1411                 {
1412                     const Arity = EAG.MAlt[EAG.NodeBuf[Node]].Arity;
1413 
1414                     if (Arity != 0)
1415                         NodeName[Node] = Var;
1416                     foreach (n; 0 .. Arity)
1417                     {
1418                         const Node1 = EAG.NodeBuf[Node + n + 1];
1419                         const NeedVar = ((isPred || UseRefCnt) && Var == AffixName[P] || n + 1 != Arity)
1420                             && Node1 >= 0
1421                             && EAG.MAlt[EAG.NodeBuf[Node1]].Arity > 0;
1422                         int Var1;
1423 
1424                         if (NeedVar)
1425                         {
1426                             Var1 = GetFreeVar;
1427                             ++RefCnt[Var1];
1428                         }
1429                         else
1430                         {
1431                             Var1 = Var;
1432                         }
1433                         DefPos(Node1, Var1);
1434                         if (NeedVar)
1435                             Dispose(Var1);
1436                     }
1437                 }
1438             }
1439 
1440             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1441             {
1442                 const Tree = EAG.ParamBuf[P].Affixform;
1443 
1444                 if (EAG.ParamBuf[P].isDef)
1445                 {
1446                     if (Tree < 0 && VarName[-Tree] < 0)
1447                     {
1448                         const V = -Tree;
1449 
1450                         VarName[V] = AffixName[P];
1451                         ++RefCnt[VarName[V]];
1452                     }
1453                     DefPos(Tree, AffixName[P]);
1454                 }
1455                 ++P;
1456             }
1457         }
1458 
1459         void CheckApplPos(int P, bool Repetition)
1460         {
1461             int Tree;
1462             int V;
1463             int P1;
1464 
1465             void ApplPos(int Node, int Var)
1466             {
1467                 if (Node < 0)
1468                 {
1469                     const V = -Node;
1470 
1471                     --VarDeps[V];
1472                     if (VarDeps[V] == 0)
1473                         Dispose(VarName[V]);
1474                     if (VarDepPos[V] >= 0)
1475                         VarDepPos[V] = -1;
1476                 }
1477                 else
1478                 {
1479                     const Arity = EAG.MAlt[EAG.NodeBuf[Node]].Arity;
1480 
1481                     NodeName[Node] = Var;
1482                     foreach (n; 0 .. Arity)
1483                     {
1484                         const Node1 = EAG.NodeBuf[Node + n + 1];
1485                         const NeedVar = !(UseConst && AffixPlace[P] > 0)
1486                             && UseRefCnt
1487                             && (Var == AffixName[P] || n + 1 != Arity)
1488                             && Node1 >= 0
1489                             && EAG.MAlt[EAG.NodeBuf[Node1]].Arity > 0;
1490                         int Var1;
1491 
1492                         if (NeedVar)
1493                         {
1494                             Var1 = GetFreeVar;
1495                             ++RefCnt[Var1];
1496                         }
1497                         else
1498                         {
1499                             Var1 = Var;
1500                         }
1501                         ApplPos(Node1, Var1);
1502                         if (NeedVar)
1503                             Dispose(Var1);
1504                     }
1505                 }
1506             }
1507 
1508             P1 = P;
1509             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1510             {
1511                 if (!EAG.ParamBuf[P].isDef)
1512                 {
1513                     Tree = EAG.ParamBuf[P].Affixform;
1514                     if (Tree < 0 && VarName[-Tree] < 0)
1515                     {
1516                         V = -Tree;
1517                         VarName[V] = AffixName[P];
1518                         ++RefCnt[VarName[V]];
1519                     }
1520                     if (!(UseConst && AffixPlace[P] > 0) && Repetition && Tree >= 0)
1521                     {
1522                         NodeName[Tree] = GetFreeVar;
1523                         ++RefCnt[NodeName[Tree]];
1524                         ApplPos(Tree, NodeName[Tree]);
1525                     }
1526                     else
1527                     {
1528                         ApplPos(Tree, AffixName[P]);
1529                     }
1530                 }
1531                 ++P;
1532             }
1533             if (Repetition)
1534             {
1535                 while (EAG.ParamBuf[P1].Affixform != EAG.nil)
1536                 {
1537                     if (!EAG.ParamBuf[P1].isDef && !(UseConst && AffixPlace[P1] > 0))
1538                     {
1539                         Tree = EAG.ParamBuf[P1].Affixform;
1540                         if (Tree >= 0)
1541                             Dispose(NodeName[Tree]);
1542                     }
1543                     ++P1;
1544                 }
1545             }
1546         }
1547 
1548         void GetFormalParamNames(size_t N, int P)
1549         {
1550             const Repetition = !EAG.Pred[N] && cast(EAG.Rep) EAG.HNont[N].Def;
1551             int Dom = EAG.HNont[N].Sig;
1552             int Tree;
1553             int V;
1554 
1555             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1556             {
1557                 if (Repetition)
1558                 {
1559                     AffixName[P] = ActualName[Dom];
1560                 }
1561                 else
1562                 {
1563                     AffixName[P] = FormalName[Dom];
1564                     Tree = EAG.ParamBuf[P].Affixform;
1565                     if (!EAG.ParamBuf[P].isDef && Tree < 0)
1566                     {
1567                         V = -Tree;
1568                         VarName[V] = AffixName[P];
1569                         ++RefCnt[VarName[V]];
1570                     }
1571                 }
1572                 ++P;
1573                 ++Dom;
1574             }
1575         }
1576 
1577         void GetActualParamNames(size_t N, int P)
1578         {
1579             int FindVarName(int P, int VarName)
1580             {
1581                 while (AffixName[P] != VarName)
1582                     ++P;
1583                 return P;
1584             }
1585 
1586             const Repetition = !EAG.Pred[N] && cast(EAG.Rep) EAG.HNont[N].Def;
1587             int P1 = P;
1588             int Tree;
1589             int V;
1590 
1591             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1592             {
1593                 Tree = EAG.ParamBuf[P].Affixform;
1594                 if (AffixName[P] < 0)
1595                 {
1596                     if (Tree < 0 && VarName[-Tree] >= 0)
1597                     {
1598                         V = -Tree;
1599                         if (!EAG.ParamBuf[P].isDef)
1600                         {
1601                             if (Repetition && VarDeps[V] > 1)
1602                             {
1603                                 AffixName[P] = GetFreeVar;
1604                             }
1605                             else if (!EAG.Pred[N] && EAG.HNont[N].anonymous)
1606                             {
1607                                 AffixName[P] = VarName[V];
1608                                 if (FindVarName(P1, VarName[V]) != P)
1609                                     AffixName[P] = GetFreeVar;
1610                             }
1611                             else
1612                             {
1613                                 AffixName[P] = VarName[V];
1614                             }
1615                         }
1616                         else
1617                         {
1618                             AffixName[P] = VarName[V];
1619                             if (EAG.Var[V].Def || FindVarName(P1, VarName[V]) != P)
1620                                 AffixName[P] = GetFreeVar;
1621                         }
1622                     }
1623                     else
1624                     {
1625                         AffixName[P] = GetFreeVar;
1626                     }
1627                 }
1628                 ++RefCnt[AffixName[P]];
1629                 if (isPred && EAG.ParamBuf[P].isDef)
1630                     ++RefCnt[AffixName[P]];
1631                 ++P;
1632             }
1633         }
1634 
1635         void FreeActualParamNames(int P)
1636         {
1637             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1638             {
1639                 Dispose(AffixName[P]);
1640                 ++P;
1641             }
1642         }
1643 
1644         void FreeAllDefPosVarNames(EAG.Alt A)
1645         {
1646             EAG.Factor F;
1647 
1648             void FreeVarNames(int P)
1649             {
1650                 while (EAG.ParamBuf[P].Affixform != EAG.nil)
1651                 {
1652                     if (EAG.ParamBuf[P].isDef)
1653                         Dispose(AffixName[P]);
1654                     ++P;
1655                 }
1656             }
1657 
1658             F = A.Sub;
1659             while (F !is null)
1660             {
1661                 if (auto nont = cast(EAG.Nont) F)
1662                     FreeVarNames(nont.Actual.Params);
1663                 F = F.Next;
1664             }
1665             if (cast(EAG.Rep) Node)
1666                 FreeVarNames(A.Actual.Params);
1667         }
1668 
1669         void InitComputation(EAG.ScopeDesc Scope)
1670         {
1671             trace!"RC: enter";
1672             InitScope(Scope);
1673             foreach (i; Scope.Beg .. Scope.End)
1674             {
1675                 VarDeps[i] = VarCnt[i];
1676                 if (EAG.Var[i].Neg != EAG.nil)
1677                     ++VarDeps[i];
1678             }
1679         }
1680 
1681         void FinitComputation(EAG.ScopeDesc Scope)
1682         {
1683             trace!"RC: exit";
1684             foreach (i; Scope.Beg .. Scope.End)
1685             {
1686                 VarRefCnt[i] = VarAppls[i];
1687                 if (VarDepPos[i] >= 0)
1688                     ++VarRefCnt[i];
1689                 trace!`RC: "%s" %s V%s (%s)`(EAG.VarRepr(i), VarDeps[i], VarName[i], RefCnt[VarName[i]]);
1690             }
1691         }
1692 
1693         Prepare(N);
1694         trace!`RC: begin "%s": RefCnt=%s`(EAG.HNontRepr(N), RefCnt[0 .. NextFreeVar + 1]);
1695         scope (exit)
1696             trace!`RC: end "%s": RefCnt=%s`(EAG.HNontRepr(N), RefCnt[0 .. NextFreeVar + 1]);
1697         Node = EAG.HNont[N].Def;
1698         isPred = EAG.Pred[N];
1699 
1700         const Repetition = !isPred && cast(EAG.Rep) Node;
1701         int Dom = EAG.HNont[N].Sig;
1702 
1703         while (EAG.DomBuf[Dom] != EAG.nil)
1704         {
1705             if (FormalName[Dom] < 0)
1706                 FormalName[Dom] = GetFreeVar;
1707             ++RefCnt[FormalName[Dom]];
1708             ++Dom;
1709         }
1710         if (Repetition)
1711         {
1712             Dom = EAG.HNont[N].Sig;
1713             P = (cast(EAG.Rep) Node).Formal.Params;
1714             while (EAG.DomBuf[Dom] != EAG.nil)
1715             {
1716                 ActualName[Dom] = FormalName[Dom];
1717                 if (!EAG.ParamBuf[P].isDef)
1718                 {
1719                     ActualName[Dom] = GetFreeVar;
1720                     ++RefCnt[ActualName[Dom]];
1721                 }
1722                 ++Dom;
1723                 ++P;
1724             }
1725         }
1726         A = Node.Sub;
1727         do
1728         {
1729             InitComputation(A.Scope);
1730             trace!"RC: RefCnt=%s"(RefCnt[0 .. NextFreeVar + 1]);
1731             GetFormalParamNames(N, A.Formal.Params);
1732             if (Repetition)
1733             {
1734                 Dom = EAG.HNont[N].Sig;
1735                 P = A.Actual.Params;
1736                 while (EAG.ParamBuf[P].Affixform != EAG.nil)
1737                 {
1738                     if (EAG.ParamBuf[P].isDef)
1739                     {
1740                         AffixName[P] = ActualName[Dom];
1741                         if (EAG.ParamBuf[P].Affixform < 0)
1742                         {
1743                             VarName[-EAG.ParamBuf[P].Affixform] = AffixName[P];
1744                             ++RefCnt[AffixName[P]];
1745                         }
1746                     }
1747                     ++P;
1748                     ++Dom;
1749                 }
1750             }
1751             CheckDefPos(A.Formal.Params);
1752             F = A.Sub;
1753             while (F !is null)
1754             {
1755                 if (auto nont = cast(EAG.Nont) F)
1756                 {
1757                     GetActualParamNames(nont.Sym, nont.Actual.Params);
1758                     CheckApplPos(nont.Actual.Params, false);
1759                     if (embed && EAG.Prod[nont.Sym] && !EAG.Pred[nont.Sym] && EAG.HNont[nont.Sym].anonymous)
1760                     {
1761                         Dom = EAG.HNont[nont.Sym].Sig;
1762                         P = nont.Actual.Params;
1763                         while (EAG.DomBuf[Dom] != EAG.nil)
1764                         {
1765                             FormalName[Dom] = AffixName[P];
1766                             ++Dom;
1767                             ++P;
1768                         }
1769                         Traverse(nont.Sym);
1770                     }
1771                     CheckDefPos(nont.Actual.Params);
1772                     FreeActualParamNames(nont.Actual.Params);
1773                 }
1774                 F = F.Next;
1775             }
1776             if (cast(EAG.Rep) Node)
1777             {
1778                 GetActualParamNames(N, A.Actual.Params);
1779                 CheckApplPos(A.Actual.Params, false);
1780                 CheckDefPos(A.Actual.Params);
1781                 FreeActualParamNames(A.Actual.Params);
1782             }
1783             CheckApplPos(A.Formal.Params, Repetition);
1784             if (isPred)
1785                 FreeAllDefPosVarNames(A);
1786             FinitComputation(A.Scope);
1787             trace!"RC: RefCnt=%s"(RefCnt[0 .. NextFreeVar + 1]);
1788             A = A.Next;
1789         }
1790         while (A !is null);
1791         if (auto rep = cast(EAG.Rep) Node)
1792         {
1793             InitComputation(rep.Scope);
1794             GetFormalParamNames(N, rep.Formal.Params);
1795             CheckDefPos(rep.Formal.Params);
1796             CheckApplPos(rep.Formal.Params, true);
1797             FinitComputation(rep.Scope);
1798         }
1799         else if (auto opt = cast(EAG.Opt) Node)
1800         {
1801             InitComputation(opt.Scope);
1802             GetFormalParamNames(N, opt.Formal.Params);
1803             CheckDefPos(opt.Formal.Params);
1804             CheckApplPos(opt.Formal.Params, false);
1805             FinitComputation(opt.Scope);
1806         }
1807         if (Repetition)
1808         {
1809             P = (cast(EAG.Rep) Node).Formal.Params;
1810             while (EAG.ParamBuf[P].Affixform != EAG.nil)
1811             {
1812                 if (!EAG.ParamBuf[P].isDef)
1813                     Dispose(AffixName[P]);
1814                 ++P;
1815             }
1816         }
1817         Dom = EAG.HNont[N].Sig;
1818         while (EAG.DomBuf[Dom] != EAG.nil)
1819         {
1820             Dispose(FormalName[Dom]);
1821             ++Dom;
1822         }
1823     }
1824 
1825     void ComputeRepAppls(size_t N)
1826     {
1827         if (cast(EAG.Rep) EAG.HNont[N].Def)
1828         {
1829             EAG.Alt A = EAG.HNont[N].Def.Sub;
1830 
1831             do
1832             {
1833                 foreach (param; A.Actual.params)
1834                     if (param.isDef)
1835                         RepAppls[N] = RepAppls[N] && VarAppls[-param.Affixform] == 1;
1836                 A = A.Next;
1837             }
1838             while (A !is null);
1839         }
1840     }
1841 
1842     FreeVar = new int[63];
1843     RefCnt = new int[63];
1844     ComputeRepAppls(N);
1845     NextFreeVar = 0;
1846     Top = 0;
1847     Traverse(N);
1848     HNontVars[N] = NextFreeVar;
1849     HNontDef[N] = true;
1850 }
1851 
1852 public void GenFormalParams(size_t N, Flag!"parNeeded" parNeeded)
1853 {
1854     int Dom = EAG.HNont[N].Sig;
1855     int i = 1;
1856 
1857     if (parNeeded)
1858         output.write("(");
1859     if (EAG.DomBuf[Dom] != EAG.nil)
1860     {
1861         if (!parNeeded)
1862             output.write(", ");
1863         while (true)
1864         {
1865             if (EAG.DomBuf[Dom] > 0)
1866                 output.write("ref ");
1867             output.write("HeapType ");
1868             GenVar(i);
1869             ++i;
1870             ++Dom;
1871             if (EAG.DomBuf[Dom] == EAG.nil)
1872                 break;
1873             output.write(", ");
1874         }
1875     }
1876     if (parNeeded)
1877         output.write(")");
1878     HNontFVars[N] = i;
1879 }
1880 
1881 public void GenVarDecl(size_t N)
1882 {
1883     if (HNontVars[N] - HNontFVars[N] >= 0)
1884     {
1885         foreach (i; HNontFVars[N] .. HNontVars[N] + 1)
1886         {
1887             output.write("HeapType ");
1888             GenVar(i);
1889             output.writeln(";");
1890         }
1891     }
1892     if (EAG.Pred[N])
1893         output.writeln("bool Failed;");
1894 }
1895 
1896 public void InitScope(EAG.ScopeDesc Scope) @nogc nothrow @safe
1897 {
1898     foreach (i; Scope.Beg .. Scope.End)
1899         EAG.Var[i].Def = false;
1900 }
1901 
1902 public void GenPredCall(int N, int ActualParams)
1903 in (EAG.Pred[N])
1904 {
1905     output.write("Check", N, `("`);
1906     if (EAG.HNont[N].anonymous)
1907         output.write("in ");
1908     output.write("'", EAG.NamedHNontRepr(N), `'"`);
1909     GenActualParams(ActualParams, false);
1910     output.writeln(");");
1911 }
1912 
1913 public void GenActualParams(int P, bool ParNeeded) @safe
1914 {
1915     if (ParNeeded)
1916         output.write("(");
1917     if (EAG.ParamBuf[P].Affixform != EAG.nil)
1918     {
1919         if (!ParNeeded)
1920             output.write(", ");
1921         while (true)
1922         {
1923             assert(AffixName[P] >= 0);
1924 
1925             GenVar(AffixName[P]);
1926             ++P;
1927             if (EAG.ParamBuf[P].Affixform == EAG.nil)
1928                 break;
1929             output.write(", ");
1930         }
1931     }
1932     if (ParNeeded)
1933         output.write(")");
1934 }
1935 
1936 public void GenSynPred(size_t Sym, int P)
1937 {
1938     int Next;
1939     bool IsPred = EAG.Pred[Sym];
1940 
1941     if (!UseRefCnt)
1942         GetAffixSpace(P);
1943     while (EAG.ParamBuf[P].Affixform != EAG.nil)
1944     {
1945         if (!EAG.ParamBuf[P].isDef)
1946         {
1947             const Tree = EAG.ParamBuf[P].Affixform;
1948 
1949             if (SavePos)
1950                 output.writeln("PopPos(", EAG.MAlt[EAG.NodeBuf[Tree]].Arity, ");");
1951             if (UseConst && AffixPlace[P] >= 0)
1952             {
1953                 GenVar(AffixName[P]);
1954                 output.writeln(" = ", AffixPlace[P], ";");
1955                 if (UseRefCnt)
1956                     GenIncRefCnt(-AffixPlace[P], 1);
1957             }
1958             else if (Tree < 0)
1959             {
1960                 const V = -Tree;
1961 
1962                 if (UseRefCnt && IsPred)
1963                     GenIncRefCnt(VarName[V], 1);
1964                 if (AffixName[P] != VarName[V])
1965                 {
1966                     GenVar(AffixName[P]);
1967                     output.write(" = ");
1968                     GenVar(VarName[V]);
1969                     output.writeln(";");
1970                 }
1971             }
1972             else
1973             {
1974                 if (UseRefCnt)
1975                 {
1976                     output.write("GetHeap(", EAG.MAlt[EAG.NodeBuf[Tree]].Arity, ", ");
1977                     GenVar(NodeName[Tree]);
1978                     output.write("); ");
1979                     Gen1SynTree(Tree, EmptySet, IsPred);
1980                     output.writeln;
1981                 }
1982                 else
1983                 {
1984                     GenVar(AffixName[P]);
1985                     output.write(" = NextHeap; ");
1986                     Next = 0;
1987                     GenSynTree(Tree, EmptySet, Next);
1988                     GenHeapInc(Next);
1989                 }
1990             }
1991         }
1992         ++P;
1993     }
1994 }
1995 
1996 private void GetAffixSpace(int P) @safe
1997 {
1998     int Heap = 0;
1999 
2000     while (EAG.ParamBuf[P].Affixform != EAG.nil)
2001     {
2002         if (!EAG.ParamBuf[P].isDef && (!UseConst || UseConst && AffixPlace[P] < 0))
2003             Heap += AffixSpace[P];
2004         ++P;
2005     }
2006     GenOverflowGuard(Heap);
2007 }
2008 
2009 // RepVar is to be understood only in the context of generating repetition code
2010 private void GenSynTree(int Node, BitArray RepVar, ref int Next)
2011 {
2012     const Alt = EAG.NodeBuf[Node];
2013     const Next1 = Next;
2014 
2015     GenHeap(0, Next);
2016     output.write(" = ", NodeIdent[Alt], "; ");
2017     Next += 1 + EAG.MAlt[Alt].Arity;
2018     foreach (n; 0 .. EAG.MAlt[Alt].Arity)
2019     {
2020         const Node1 = EAG.NodeBuf[Node + n + 1];
2021 
2022         if (Node1 < 0)
2023         {
2024             const V = -Node1;
2025 
2026             if (RepVar[V])
2027             {
2028                 GenVar(VarName[V]);
2029                 output.write(" = NextHeap + ", Next1 + n + 1);
2030             }
2031             else
2032             {
2033                 GenHeap(0, Next1 + n + 1);
2034                 output.write(" = ");
2035                 GenVar(VarName[V]);
2036             }
2037             output.write("; ");
2038         }
2039         else
2040         {
2041             GenHeap(0, Next1 + n + 1);
2042             output.write(" = ");
2043             if (UseConst && EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
2044             {
2045                 output.write(Leaf[EAG.NodeBuf[Node1]], "; ");
2046             }
2047             else
2048             {
2049                 output.write("NextHeap + ", Next, "; ");
2050                 GenSynTree(Node1, RepVar, Next);
2051             }
2052         }
2053     }
2054 }
2055 
2056 // RepVar is to be understood only in the context of generating repetition code
2057 private void Gen1SynTree(int Node, BitArray RepVar, bool IsPred)
2058 {
2059     GenHeap(NodeName[Node], 0);
2060     output.write(" = ", NodeIdent[EAG.NodeBuf[Node]], "; ");
2061     foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
2062     {
2063         const Node1 = EAG.NodeBuf[Node + n + 1];
2064 
2065         if (Node1 < 0)
2066         {
2067             const V = -Node1;
2068 
2069             if (RepVar[V])
2070             {
2071                 GenVar(VarName[V]);
2072                 output.write(" = ");
2073                 GenVar(NodeName[Node]);
2074                 output.write(" + ", n + 1, "; ");
2075             }
2076             else
2077             {
2078                 GenHeap(NodeName[Node], n + 1);
2079                 output.write(" = ");
2080                 GenVar(VarName[V]);
2081                 output.write("; ");
2082                 if (IsPred)
2083                     GenIncRefCnt(VarName[V], 1);
2084             }
2085         }
2086         else if (EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
2087         {
2088             if (UseConst)
2089             {
2090                 GenHeap(NodeName[Node], n + 1);
2091                 output.write(" = ", Leaf[EAG.NodeBuf[Node1]], "; ");
2092                 GenIncRefCnt(-Leaf[EAG.NodeBuf[Node1]], 1);
2093             }
2094             else
2095             {
2096                 output.write("GetHeap(0, ");
2097                 GenHeap(NodeName[Node], n + 1);
2098                 output.write("); Heap[");
2099                 GenHeap(NodeName[Node], n + 1);
2100                 output.write("] = ", NodeIdent[EAG.NodeBuf[Node1]], ";");
2101             }
2102         }
2103         else
2104         {
2105             output.write("GetHeap(", EAG.MAlt[EAG.NodeBuf[Node1]].Arity, ", ");
2106             if (NodeName[Node] == NodeName[Node1])
2107             {
2108                 GenHeap(NodeName[Node], n + 1);
2109                 output.write("); ");
2110                 GenVar(NodeName[Node1]);
2111                 output.write(" = ");
2112                 GenHeap(NodeName[Node], n + 1);
2113             }
2114             else
2115             {
2116                 GenVar(NodeName[Node1]);
2117                 output.write("); ");
2118                 GenHeap(NodeName[Node], n + 1);
2119                 output.write(" = ");
2120                 GenVar(NodeName[Node1]);
2121             }
2122             output.writeln(";");
2123             Gen1SynTree(Node1, RepVar, IsPred);
2124         }
2125     }
2126 }
2127 
2128 public void GenAnalPred(size_t Sym, int P)
2129 {
2130     bool MakeRefCnt;
2131     bool IsPred;
2132 
2133     void Comp()
2134     {
2135         if (UseRefCnt)
2136             output.write(".MOD(refConst)");
2137         output.write(IsPred ? " == " : " != ");
2138     }
2139 
2140     void GenEqualErrMsg(size_t Sym, int Var)
2141     {
2142         output.write(`"'`, EAG.VarRepr(Var), "' failed in '", EAG.NamedHNontRepr(Sym), `'"`);
2143     }
2144 
2145     void GenAnalErrMsg(size_t Sym)
2146     {
2147         output.write(`"`, EAG.NamedHNontRepr(Sym), `"`);
2148     }
2149 
2150     void GenEqualPred(int VarName1, int Var2, bool Eq)
2151     {
2152         if (IsPred)
2153         {
2154             output.write("if (");
2155             if (!Eq)
2156                 output.write("!");
2157             output.write("Equal(");
2158             GenVar(VarName1);
2159             output.write(", ");
2160             GenVar(VarName[Var2]);
2161             output.writeln("))");
2162             output.writeln("{");
2163             ++IfLevel;
2164         }
2165         else
2166         {
2167             if (!Eq)
2168                 output.write("Un");
2169             output.write("Eq(");
2170             GenVar(VarName1);
2171             output.write(", ");
2172             GenVar(VarName[Var2]);
2173             output.write(", ");
2174             GenEqualErrMsg(Sym, Var2);
2175             output.write("); ");
2176         }
2177     }
2178 
2179     void GenAnalTree(int Node)
2180     {
2181         output.write("if (");
2182         GenHeap(NodeName[Node], 0);
2183         Comp;
2184         output.write(NodeIdent[EAG.NodeBuf[Node]]);
2185         output.write(")");
2186         if (IsPred)
2187         {
2188             output.writeln;
2189             output.writeln("{");
2190             ++IfLevel;
2191         }
2192         else
2193         {
2194             output.write(" AnalyseError(");
2195             GenVar(NodeName[Node]);
2196             output.write(", ");
2197             GenAnalErrMsg(Sym);
2198             output.writeln(");");
2199         }
2200         foreach (n; 0 .. EAG.MAlt[EAG.NodeBuf[Node]].Arity)
2201         {
2202             const Node1 = EAG.NodeBuf[Node + n + 1];
2203 
2204             if (Node1 < 0)
2205             {
2206                 const V = -Node1;
2207 
2208                 if (EAG.Var[V].Def)
2209                 {
2210                     if (IsPred)
2211                     {
2212                         output.write("if (Equal(");
2213                         GenHeap(NodeName[Node], n + 1);
2214                         output.write(", ");
2215                         GenVar(VarName[V]);
2216                         output.writeln("))");
2217                         output.writeln("{");
2218                         ++IfLevel;
2219                     }
2220                     else
2221                     {
2222                         output.write("Eq(");
2223                         GenHeap(NodeName[Node], n + 1);
2224                         output.write(", ");
2225                         GenVar(VarName[V]);
2226                         output.write(", ");
2227                         GenEqualErrMsg(Sym, V);
2228                         output.write("); ");
2229                     }
2230                 }
2231                 else
2232                 {
2233                     EAG.Var[V].Def = true;
2234                     GenVar(VarName[V]);
2235                     output.write(" = ");
2236                     GenHeap(NodeName[Node], n + 1);
2237                     output.write("; ");
2238                     if (EAG.Var[EAG.Var[V].Neg].Def)
2239                     {
2240                         const Vn = EAG.Var[V].Neg;
2241 
2242                         GenEqualPred(VarName[Vn], V, false);
2243                         if (MakeRefCnt)
2244                         {
2245                             if (VarDepPos[Vn] == P)
2246                             {
2247                                 GenFreeHeap(VarName[Vn]);
2248                                 VarDepPos[Vn] = -2;
2249                             }
2250                         }
2251                     }
2252                     if (MakeRefCnt && VarRefCnt[V] > 0)
2253                         GenIncRefCnt(VarName[V], VarRefCnt[V]);
2254                 }
2255                 if (MakeRefCnt)
2256                 {
2257                     if (VarDepPos[V] == P)
2258                     {
2259                         GenFreeHeap(VarName[V]);
2260                         VarDepPos[V] = -2;
2261                     }
2262                 }
2263             }
2264             else
2265             {
2266                 if (EAG.MAlt[EAG.NodeBuf[Node1]].Arity == 0)
2267                 {
2268                     if (UseConst)
2269                     {
2270                         output.write("if (");
2271                         GenHeap(NodeName[Node], n + 1);
2272                         Comp;
2273                         output.write(Leaf[EAG.NodeBuf[Node1]]);
2274                     }
2275                     else
2276                     {
2277                         output.write("if (Heap[");
2278                         GenHeap(NodeName[Node], n + 1);
2279                         output.write("]");
2280                         Comp;
2281                         output.write(NodeIdent[EAG.NodeBuf[Node1]]);
2282                     }
2283                     output.write(")");
2284                     if (IsPred)
2285                     {
2286                         output.writeln;
2287                         output.writeln("{");
2288                         ++IfLevel;
2289                     }
2290                     else
2291                     {
2292                         output.write(" AnalyseError(");
2293                         GenHeap(NodeName[Node], n + 1);
2294                         output.write(", ");
2295                         GenAnalErrMsg(Sym);
2296                         output.write(");");
2297                     }
2298                     output.writeln;
2299                 }
2300                 else
2301                 {
2302                     GenVar(NodeName[Node1]);
2303                     output.write(" = ");
2304                     GenHeap(NodeName[Node], n + 1);
2305                     output.write("; ");
2306                     GenAnalTree(Node1);
2307                 }
2308             }
2309         }
2310     }
2311 
2312     IsPred = EAG.Pred[Sym];
2313     IfLevel = 0;
2314     MakeRefCnt = UseRefCnt && !IsPred;
2315     while (EAG.ParamBuf[P].Affixform != EAG.nil)
2316     {
2317         if (EAG.ParamBuf[P].isDef)
2318         {
2319             const Tree = EAG.ParamBuf[P].Affixform;
2320 
2321             if (Tree < 0)
2322             {
2323                 const V = -Tree;
2324 
2325                 if (EAG.Var[V].Def)
2326                 {
2327                     assert(AffixName[P] != VarName[V]);
2328 
2329                     GenEqualPred(AffixName[P], V, true);
2330                     if (MakeRefCnt)
2331                         GenFreeHeap(AffixName[P]);
2332                 }
2333                 else
2334                 {
2335                     EAG.Var[V].Def = true;
2336                     if (AffixName[P] != VarName[V])
2337                     {
2338                         GenVar(VarName[V]);
2339                         output.write(" = ");
2340                         GenVar(AffixName[P]);
2341                         output.writeln(";");
2342                     }
2343                     if (EAG.Var[EAG.Var[V].Neg].Def)
2344                     {
2345                         const Vn = EAG.Var[V].Neg;
2346 
2347                         GenEqualPred(VarName[Vn], V, false);
2348                         if (MakeRefCnt)
2349                         {
2350                             if (VarDepPos[Vn] == P)
2351                             {
2352                                 GenFreeHeap(VarName[Vn]);
2353                                 VarDepPos[Vn] = -2;
2354                             }
2355                         }
2356                     }
2357                     if (MakeRefCnt)
2358                     {
2359                         if (VarRefCnt[V] > 1)
2360                             GenIncRefCnt(VarName[V], VarRefCnt[V] - 1);
2361                         else if (VarRefCnt[V] == 0)
2362                             GenFreeHeap(AffixName[P]);
2363                     }
2364                 }
2365                 if (MakeRefCnt)
2366                 {
2367                     if (VarDepPos[V] == P)
2368                     {
2369                         GenFreeHeap(VarName[V]);
2370                         VarDepPos[V] = -2;
2371                     }
2372                 }
2373             }
2374             else
2375             {
2376                 if (EAG.MAlt[EAG.NodeBuf[Tree]].Arity == 0)
2377                 {
2378                     output.write("if (");
2379                     GenHeap(AffixName[P], 0);
2380                     Comp;
2381                     output.write(NodeIdent[EAG.NodeBuf[Tree]], ")");
2382                     if (IsPred)
2383                     {
2384                         output.writeln;
2385                         output.writeln("{");
2386                         ++IfLevel;
2387                     }
2388                     else
2389                     {
2390                         output.write(" AnalyseError(");
2391                         GenVar(AffixName[P]);
2392                         output.write(", ");
2393                         GenAnalErrMsg(Sym);
2394                         output.write(");");
2395                     }
2396                     output.writeln;
2397                 }
2398                 else
2399                 {
2400                     GenAnalTree(Tree);
2401                 }
2402                 if (MakeRefCnt)
2403                     GenFreeHeap(AffixName[P]);
2404             }
2405         }
2406         ++P;
2407     }
2408     if (SavePos)
2409         output.writeln("PushPos;");
2410 }
2411 
2412 private void GenHeap(int Var, int Offset) @safe
2413 {
2414     output.write("Heap[");
2415     if (Var <= 0)
2416         output.write("NextHeap");
2417     else
2418         GenVar(Var);
2419     if (Offset > 0)
2420     {
2421         output.write(" + ", Offset);
2422     }
2423     else if (Offset < 0)
2424     {
2425         output.write(" - ", -Offset);
2426     }
2427     output.write("]");
2428 }
2429 
2430 private void GenIncRefCnt(int Var, int n) @safe
2431 {
2432     output.write("Heap[");
2433     if (Var < 0)
2434         output.write(-Var);
2435     else
2436         GenVar(Var);
2437     output.write("] += ");
2438     if (n != 1)
2439         output.write(n, " * ");
2440     output.writeln("refConst;");
2441 }
2442 
2443 private void GenOverflowGuard(int n) @safe
2444 {
2445     if (n > 0)
2446     {
2447         output.writeln("if (NextHeap >= Heap.length - ", n, ")");
2448         output.writeln("EvalExpand;");
2449     }
2450 }
2451 
2452 private void GenFreeHeap(int Var) @safe
2453 {
2454     output.write("FreeHeap(");
2455     GenVar(Var);
2456     output.writeln(");");
2457 }
2458 
2459 private void GenHeapInc(int n) @safe
2460 {
2461     if (n != 0)
2462     {
2463         if (n == 1)
2464             output.writeln("++NextHeap;");
2465         else
2466             output.writeln("NextHeap += ", n, ";");
2467     }
2468 }
2469 
2470 private void GenVar(int Var) @safe
2471 {
2472     output.write("V", Var);
2473 }
2474 
2475 static this() @nogc nothrow @safe
2476 {
2477     Testing = false;
2478     Generating = false;
2479 }