1 module epsilon.soag.partition;
2 
3 import EAG = epsilon.eag;
4 import log;
5 import runtime;
6 import ALists = epsilon.soag.alists;
7 import Protocol = epsilon.soag.protocol;
8 import SOAG = epsilon.soag.soag;
9 import std.bitmanip : BitArray;
10 import std.stdio;
11 
12 const unor = -1;
13 const nil = 0;
14 const element = 1;
15 const computeDPandIDP = 1;
16 const dynTopSort = 2;
17 const firstVarBuf = 0;
18 const firstChangeBuf = 0;
19 
20 struct VarBufDesc
21 {
22     int AffOcc;
23     int Sym;
24     int Num;
25     int VarInd;
26 }
27 
28 struct ChangeBufDesc
29 {
30     int RuleInd;
31     int AffOccInd1;
32     int AffOccInd2;
33 }
34 
35 VarBufDesc[] VarBuf;
36 int NextVarBuf;
37 ChangeBufDesc[] ChangeBuf;
38 int NextChangeBuf;
39 int[][] DS;
40 int[] Deg;
41 int Phase;
42 bool CyclicTDP;
43 bool OAG;
44 ALists.AList NUV;
45 ALists.AList MarkedEdges;
46 ALists.AList LastCur;
47 BitArray Cur;
48 BitArray Leave;
49 BitArray New;
50 int Seperator;
51 
52 void Expand() nothrow @safe
53 {
54     size_t NewLen(size_t ArrayLen)
55     {
56         assert(ArrayLen < DIV(size_t.max, 2));
57 
58         return 2 * ArrayLen + 1;
59     }
60 
61     if (NextVarBuf >= VarBuf.length)
62     {
63         auto VarBuf1 = new VarBufDesc[NewLen(VarBuf.length)];
64 
65         for (size_t i = firstVarBuf; i < VarBuf.length; ++i)
66             VarBuf1[i] = VarBuf[i];
67         VarBuf = VarBuf1;
68     }
69     if (NextChangeBuf >= ChangeBuf.length)
70     {
71         auto ChangeBuf1 = new ChangeBufDesc[NewLen(ChangeBuf.length)];
72 
73         for (size_t i = firstChangeBuf; i < ChangeBuf.length; ++i)
74             ChangeBuf1[i] = ChangeBuf[i];
75         ChangeBuf = ChangeBuf1;
76     }
77 }
78 
79 void Push(ref ALists.AList Stack, int S, int A1, int A2) nothrow pure @safe
80 {
81     ALists.Append(Stack, S);
82     ALists.Append(Stack, A1);
83     ALists.Append(Stack, A2);
84 }
85 
86 /**
87  * IN:  Regel, zwei Affixparameter
88  * OUT: boolscher Wert
89  * SEM: Test, ob eine Abhängigkeit zwischen den beiden Affixparametern besteht
90  */
91 bool EdgeInTDP(int R, int A1, int A2) @nogc nothrow
92 {
93     return SOAG.Rule[R].TDP[SOAG.AffOcc[A1].AffOccNum.InRule][SOAG.AffOcc[A2].AffOccNum.InRule];
94 }
95 
96 /**
97  * IN:  Regel, 2 Affixparameter
98  * OUT: -
99  * SEM: Fügt ein Tripel in das Feld ChangeBuf ein - Speicherung einer in TDP eingefügten Abhängigkeit.
100  */
101 void AddTDPChange(int R, int AO1, int AO2) nothrow @safe
102 {
103     ChangeBuf[NextChangeBuf].RuleInd = R;
104     ChangeBuf[NextChangeBuf].AffOccInd1 = AO1;
105     ChangeBuf[NextChangeBuf].AffOccInd2 = AO2;
106     ++NextChangeBuf;
107     if (NextChangeBuf >= ChangeBuf.length)
108         Expand;
109 }
110 
111 /**
112  * IN:  Index in ChangeBuf
113  * OUT: -
114  * SEM: Rücksetzen,der in ChangeBuf gespeicherten Abhängigkeiten in den TDP's
115  */
116 void ResetTDPChanges(int End) @nogc nothrow
117 {
118     for (int i = firstChangeBuf; i <= End; ++i)
119     {
120         SOAG.Rule[ChangeBuf[i].RuleInd].TDP[SOAG.AffOcc[ChangeBuf[i].AffOccInd1].AffOccNum.InRule]
121             [SOAG.AffOcc[ChangeBuf[i].AffOccInd2].AffOccNum.InRule] = false;
122     }
123 }
124 
125 /**
126  * IN:  Regel; zwei Affixparameter
127  * OUT: -
128  * SEM: fügt die Kante (AO1,AO2) in den TDP ein und bildet den transitiven Abschluss TDP+;
129  *      die eingefügte Abhängigkeit lautet: AO2 hängt ab von AO1, AO1->AO2 im Sinne des Datenflusses;
130  *      markiert alle neu eingefügten Kanten, indem sie auf einen Stack gelegt werden
131  * SEF: NUV: AList ist global
132  * MarkedEdges falls Phase = computeDPandIDP
133  * ChangeBuf, CyclicTDP falls Phase = dynTopSort
134  */
135 void AddTDPTrans(int R, int AO1, int AO2)
136 {
137     int AO3;
138     int AO4;
139     int AN1;
140     int AN2;
141     int AN3;
142     int AN4;
143 
144     ALists.Reset(NUV);
145     if (!EdgeInTDP(R, AO1, AO2))
146     {
147         AN1 = SOAG.AffOcc[AO1].AffOccNum.InRule;
148         AN2 = SOAG.AffOcc[AO2].AffOccNum.InRule;
149         for (AO4 = SOAG.Rule[R].AffOcc.Beg; AO4 <= SOAG.Rule[R].AffOcc.End; ++AO4)
150         {
151             AN4 = SOAG.AffOcc[AO4].AffOccNum.InRule;
152             if ((AN4 == AN2 || SOAG.Rule[R].TDP[AN2][AN4]) && !SOAG.Rule[R].TDP[AN1][AN4])
153                 ALists.Append(NUV, AO4);
154         }
155         for (AO3 = SOAG.Rule[R].AffOcc.Beg; AO3 <= SOAG.Rule[R].AffOcc.End; ++AO3)
156         {
157             AN3 = SOAG.AffOcc[AO3].AffOccNum.InRule;
158             if ((AN3 == AN1 || SOAG.Rule[R].TDP[AN3][AN1]) && !SOAG.Rule[R].TDP[AN3][AN2])
159             {
160                 for (size_t i = ALists.firstIndex; i <= NUV.Last; ++i)
161                 {
162                     AO4 = NUV.Elem[i];
163                     if (!EdgeInTDP(R, AO3, AO4))
164                     {
165                         SOAG.Rule[R].TDP[AN3][SOAG.AffOcc[AO4].AffOccNum.InRule] = true;
166                         if (SOAG.AffOcc[AO3].SymOccInd == SOAG.AffOcc[AO4].SymOccInd
167                                 && !SOAG.IsPredNont(SOAG.AffOcc[AO3].SymOccInd))
168                         {
169                             Push(MarkedEdges, SOAG.SymOcc[SOAG.AffOcc[AO3].SymOccInd].SymInd,
170                                     SOAG.AffOcc[AO3].AffOccNum.InSym,
171                                     SOAG.AffOcc[AO4].AffOccNum.InSym);
172                         }
173                         if (Phase == dynTopSort)
174                             AddTDPChange(R, AO3, AO4);
175                     }
176                 }
177             }
178             if (SOAG.Rule[R].TDP[AN3][AN3])
179             {
180                 if (Phase == computeDPandIDP)
181                 {
182                     Protocol.output.write("...a cyclic affix dependence was found!\n");
183                     Protocol.WriteRule(R);
184                     Protocol.output.writeln;
185                     Protocol.WriteAffOcc(AO3);
186                     Protocol.output.writeln;
187                     Protocol.output.write("Preorder  of ");
188                     Protocol.WriteAffOcc(AO1);
189                     Protocol.output.writeln;
190                     Protocol.output.write("Postorder of ");
191                     Protocol.WriteAffOcc(AO2);
192                     Protocol.output.writeln;
193                     Protocol.output.writeln;
194                     SOAG.Error(SOAG.cyclicTDP, "eSOAGVSGen.AddTDPTrans");
195                 }
196                 else if (Phase == dynTopSort)
197                 {
198                     CyclicTDP = true;
199                 }
200             }
201         }
202     }
203 }
204 
205 /**
206  * IN:  Affixparameter, Affixform, Affixparameter definierend oder applizierend ?
207  * OUT: -
208  * SEM: ordnet im Feld VarBuf[] jeder Variablen, die im Baum der Affixform gefunden wird,
209  *      den zugehörigen Affixparameter, sowie das Variablensymbol zu
210  * SEF: VarBuf[], NextVarBuf
211  */
212 void SetAffOccforVars(int AO, int Affixform, bool isDef) nothrow @safe
213 {
214     int MA;
215     if (Affixform < 0)
216     {
217         if (NextVarBuf + 1 >= VarBuf.length)
218             Expand;
219         VarBuf[NextVarBuf].AffOcc = AO;
220         if (isDef)
221             VarBuf[NextVarBuf].Sym = -EAG.Var[-Affixform].Sym;
222         else
223             VarBuf[NextVarBuf].Sym = EAG.Var[-Affixform].Sym;
224         VarBuf[NextVarBuf].Num = EAG.Var[-Affixform].Num;
225         VarBuf[NextVarBuf].VarInd = -Affixform;
226         ++NextVarBuf;
227     }
228     else if (EAG.MAlt[EAG.NodeBuf[Affixform]].Arity > 0)
229     {
230         for (MA = 1; MA <= EAG.MAlt[EAG.NodeBuf[Affixform]].Arity; ++MA)
231             SetAffOccforVars(AO, EAG.NodeBuf[Affixform + MA], isDef);
232     }
233 }
234 
235 /**
236  * IN:  Regel
237  * OUT: -
238  * SEM: berechnet für alle Affixvariablen einer Regel den Affixparameter des zugehörigen definierenden Affixes
239  *      und speichert  diesen in DefAffOcc[]
240  * SEF: Zugriffe auf VarBuf[]
241  */
242 void ComputeDefAffOcc(int R)
243 {
244     EAG.ScopeDesc Scope;
245 
246     if (auto ordRule = cast(SOAG.OrdRule) SOAG.Rule[R])
247     {
248         Scope = ordRule.Alt.Scope;
249     }
250     else if (auto emptyRule = cast(SOAG.EmptyRule) SOAG.Rule[R])
251     {
252         EAG.Rule EAGRule = emptyRule.Rule;
253 
254         if (auto opt = cast(EAG.Opt) EAGRule)
255             Scope = opt.Scope;
256         else if (auto rep = cast(EAG.Rep) EAGRule)
257             Scope = rep.Scope;
258     }
259     foreach (V; Scope.Beg .. Scope.End)
260     {
261         bool Found;
262         int i = firstVarBuf - 1;
263 
264         do
265         {
266             ++i;
267             Found = EAG.Var[V].Sym == -VarBuf[i].Sym && EAG.Var[V].Num == VarBuf[i].Num;
268         }
269         while (!Found && i < NextVarBuf - 1);
270         if (Found)
271         {
272             SOAG.DefAffOcc[V] = VarBuf[i].AffOcc;
273         }
274         else
275         {
276             writeln(EAG.Var[V].Pos);
277             SOAG.Error(SOAG.notLeftDefined, "epsilon.soag.partition.ComputeDefAffOcc");
278         }
279     }
280 }
281 
282 /**
283  * IN:  Regel
284  * OUT: -
285  * SEM: Berechnet in AffixApplCnt die Anzahl der Applikationen eines Affixes,
286  *      außerdem wird für jeden Vergleich eine Abhängigkeit in den DP aufgenommen
287  * PRE: DefAffOcc[] muss berechnet sein
288  */
289 void ComputeAffixApplCnt(int R) @nogc nothrow
290 {
291     EAG.ScopeDesc Scope;
292 
293     if (auto ordRule = cast(SOAG.OrdRule) SOAG.Rule[R])
294     {
295         Scope = ordRule.Alt.Scope;
296     }
297     else if (auto emptyRule = cast(SOAG.EmptyRule) SOAG.Rule[R])
298     {
299         EAG.Rule EAGRule = emptyRule.Rule;
300 
301         if (auto opt = cast(EAG.Opt) EAGRule)
302             Scope = opt.Scope;
303         else if (auto rep = cast(EAG.Rep) EAGRule)
304             Scope = rep.Scope;
305     }
306     foreach (A; Scope.Beg .. Scope.End)
307     {
308         int i = firstVarBuf;
309 
310         while (i < NextVarBuf)
311         {
312             if (EAG.Var[A].Sym == -VarBuf[i].Sym
313                     && (EAG.Var[A].Num == VarBuf[i].Num && SOAG.DefAffOcc[A] != VarBuf[i].AffOcc
314                         || EAG.Var[A].Num == -VarBuf[i].Num && SOAG.DefAffOcc[VarBuf[i].VarInd] == VarBuf[i].AffOcc))
315             {
316                 const AN = VarBuf[i].AffOcc - SOAG.Rule[R].AffOcc.Beg;
317                 const DAN = SOAG.DefAffOcc[A] - SOAG.Rule[R].AffOcc.Beg;
318 
319                 SOAG.Rule[R].DP[DAN][AN] = true;
320                 ++SOAG.AffixApplCnt[A];
321             }
322             else if (EAG.Var[A].Sym == VarBuf[i].Sym && EAG.Var[A].Num == VarBuf[i].Num)
323             {
324                 ++SOAG.AffixApplCnt[A];
325             }
326             ++i;
327         }
328     }
329 }
330 
331 /**
332  * SEM: Initialisierung des Abhängigkeitsgraphen für jeden Affixparamter
333  *      aller Regeln aus der Spezifikationsdatenstruktur
334  * SEF: auf alle globalen DSen
335  */
336 void ComputeDP()
337 {
338     int R;
339     int AO;
340     int SO;
341     int i;
342     int j;
343     int PBI;
344     int FirstSOVar;
345 
346     Phase = computeDPandIDP;
347     ALists.New(MarkedEdges, 256);
348     ALists.New(NUV, 56);
349     for (R = SOAG.firstRule; R < SOAG.NextRule; ++R)
350     {
351         if (SOAG.IsEvaluatorRule(R))
352         {
353             for (SO = SOAG.Rule[R].SymOcc.Beg; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
354             {
355                 FirstSOVar = NextVarBuf;
356                 for (AO = SOAG.SymOcc[SO].AffOcc.Beg; AO <= SOAG.SymOcc[SO].AffOcc.End;
357                         ++AO)
358                 {
359                     PBI = SOAG.AffOcc[AO].ParamBufInd;
360                     SetAffOccforVars(AO, EAG.ParamBuf[PBI].Affixform, EAG.ParamBuf[PBI].isDef);
361                 }
362                 if (SOAG.IsPredNont(SO))
363                 {
364                     for (i = FirstSOVar; i < NextVarBuf; ++i)
365                     {
366                         for (j = FirstSOVar; j < NextVarBuf; ++j)
367                         {
368                             if (VarBuf[j].Sym < 0 && VarBuf[i].Sym > 0)
369                             {
370                                 AddTDPTrans(R, VarBuf[i].AffOcc, VarBuf[j].AffOcc);
371                                 SOAG.Rule[R].DP[SOAG.AffOcc[VarBuf[i].AffOcc].AffOccNum.InRule]
372                                     [SOAG.AffOcc[VarBuf[j].AffOcc].AffOccNum.InRule] = true;
373                             }
374                         }
375                     }
376                 }
377             }
378             ComputeDefAffOcc(R);
379             ComputeAffixApplCnt(R);
380             if (SOAG.Rule[R].AffOcc.End >= SOAG.Rule[R].AffOcc.Beg)
381             {
382                 for (i = firstVarBuf; i < NextVarBuf; ++i)
383                 {
384                     if (VarBuf[i].Sym > 0)
385                     {
386                         AddTDPTrans(R, SOAG.DefAffOcc[VarBuf[i].VarInd], VarBuf[i].AffOcc);
387                         SOAG.Rule[R].DP[SOAG.AffOcc[SOAG.DefAffOcc[VarBuf[i].VarInd]].AffOccNum.InRule]
388                             [SOAG.AffOcc[VarBuf[i].AffOcc].AffOccNum.InRule] = true;
389                     }
390                 }
391                 NextVarBuf = firstVarBuf;
392             }
393         }
394     }
395 }
396 
397 /**
398  * SEM: bildet in TDP alle induzierten Abhängigkeiten solange MarkedEdges nicht leer ist
399  *      und die Ausgabeinvariante TDP = ind(TDP) gilt.
400  * SEF: MarkedEdges, TDP
401  */
402 void ComputeInducedTDP()
403 {
404     int SO;
405     int AN1;
406     int AN2;
407     int AO1;
408     int AO2;
409     while (MarkedEdges.Last >= ALists.firstIndex)
410     {
411         AN2 = MarkedEdges.Elem[MarkedEdges.Last];
412         ALists.Delete(MarkedEdges, MarkedEdges.Last);
413         AN1 = MarkedEdges.Elem[MarkedEdges.Last];
414         ALists.Delete(MarkedEdges, MarkedEdges.Last);
415         SO = MarkedEdges.Elem[MarkedEdges.Last];
416         ALists.Delete(MarkedEdges, MarkedEdges.Last);
417         SO = SOAG.Sym[SO].FirstOcc;
418         while (SO != SOAG.nil)
419         {
420             AO1 = SOAG.SymOcc[SO].AffOcc.Beg + AN1;
421             AO2 = SOAG.SymOcc[SO].AffOcc.Beg + AN2;
422             AddTDPTrans(SOAG.SymOcc[SO].RuleInd, AO1, AO2);
423             SO = SOAG.SymOcc[SO].Next;
424         }
425     }
426 }
427 
428 /**
429  * SEM: bildet in TDP alle induzierten Abhängigkeiten solange MarkedEdges nicht leer ist
430  *      und die Ausgabeinvariante TDP = ind(TDP) gilt, damit ist dann TDP = IDP+
431  * SEF: -
432  */
433 void ComputeIDPTrans()
434 {
435     ComputeInducedTDP;
436 }
437 
438 /**
439  * IN:  Affixpositionsnummern a und b, Symbol
440  * OUT: Liste von Paaren von Affixpositionsnummern des Symbols X
441  * SEM: findet für zwei Affixpositionen eines Symbols eine Orientierung,
442  *      fügt diese in alle Regelabhängigkeitsgraphen ein und liefert die Liste
443  *      aller bei der transitiven Vervollständigung neu entstandenen Abhängigkeiten zurück
444  * SEF: auf ChangeBuf[]
445  */
446 void Orient(int a, int b, int X, ref BitArray New)
447 {
448     int SO;
449     int i;
450     int a1;
451     int b1;
452     int AO1;
453     int AO2;
454 
455     New[] = false;
456     CyclicTDP = false;
457     NextChangeBuf = firstChangeBuf;
458     SO = SOAG.Sym[X].FirstOcc;
459     AddTDPTrans(SOAG.SymOcc[SO].RuleInd, SOAG.SymOcc[SO].AffOcc.Beg + b,
460             SOAG.SymOcc[SO].AffOcc.Beg + a);
461     ComputeInducedTDP;
462     if (CyclicTDP)
463     {
464         CyclicTDP = false;
465         OAG = false;
466         ResetTDPChanges(NextChangeBuf - 1);
467         NextChangeBuf = firstChangeBuf;
468         AddTDPTrans(SOAG.SymOcc[SO].RuleInd, SOAG.SymOcc[SO].AffOcc.Beg + a,
469                 SOAG.SymOcc[SO].AffOcc.Beg + b);
470         ComputeInducedTDP;
471     }
472     if (CyclicTDP)
473     {
474         error!"grammar is not SOAG";
475         SOAG.Error(SOAG.cyclicTDP, "eSOAGVSGen.Orient");
476     }
477     for (i = firstChangeBuf; i < NextChangeBuf; ++i)
478     {
479         AO1 = ChangeBuf[i].AffOccInd1;
480         AO2 = ChangeBuf[i].AffOccInd2;
481         if (SOAG.AffOcc[AO1].SymOccInd == SOAG.AffOcc[AO2].SymOccInd
482                 && SOAG.SymOcc[SOAG.AffOcc[AO1].SymOccInd].SymInd == X)
483         {
484             a1 = SOAG.AffOcc[AO1].AffOccNum.InSym;
485             b1 = SOAG.AffOcc[AO2].AffOccNum.InSym;
486             if (SOAG.IsOrientable(X, a1, b1))
487                 New[a1 * Seperator + b1] = true;
488         }
489     }
490 }
491 
492 /**
493  * IN:  Symbol
494  * OUT: -
495  * SEM: dynamisches topologisches Sortieren der Affxipositionsabhängigkeiten
496  *      unter Heranführung an eine erfolgreiche bzw. unmittelbar erfolgreiche Orientierung
497  * SEF: DS[][]
498  */
499 void DynTopSortSym(int X)
500 {
501     import std.conv : to;
502 
503     int XmaxAff;
504     int AO1;
505     int AO2;
506     int SO;
507     int Part = 0;
508     int i;
509     int a1;
510     int a;
511     int b;
512     int c;
513     int d;
514 
515     XmaxAff = SOAG.SymOcc[SOAG.Sym[X].FirstOcc].AffOcc.End - SOAG.SymOcc[SOAG.Sym[X].FirstOcc].AffOcc.Beg;
516     for (a = 0; a <= XmaxAff; ++a)
517         for (b = 0; b <= XmaxAff; ++b)
518             DS[a][b] = nil;
519     SO = SOAG.Sym[X].FirstOcc;
520     while (SO != SOAG.nil)
521     {
522         for (AO1 = SOAG.SymOcc[SO].AffOcc.Beg; AO1 <= SOAG.SymOcc[SO].AffOcc.End; ++AO1)
523         {
524             for (AO2 = SOAG.SymOcc[SO].AffOcc.Beg; AO2 <= SOAG.SymOcc[SO].AffOcc.End; ++AO2)
525             {
526                 if (EdgeInTDP(SOAG.SymOcc[SO].RuleInd, AO1, AO2))
527                 {
528                     a = SOAG.AffOcc[AO1].AffOccNum.InSym;
529                     b = SOAG.AffOcc[AO2].AffOccNum.InSym;
530                     if (SOAG.IsOrientable(X, a, b))
531                         DS[a][b] = element;
532                 }
533             }
534         }
535         SO = SOAG.SymOcc[SO].Next;
536     }
537     for (a = 0; a <= XmaxAff; ++a)
538     {
539         Deg[a] = 0;
540         for (b = 0; b <= XmaxAff; ++b)
541         {
542             if (DS[a][b] == element)
543             {
544                 ++Deg[a];
545             }
546             else if (DS[b][a] == nil && SOAG.IsOrientable(X, a, b))
547             {
548                 DS[a][b] = unor;
549                 DS[b][a] = unor;
550             }
551         }
552     }
553     Cur[] = false;
554     Leave[] = false;
555     for (a = 0; a <= XmaxAff; ++a)
556     {
557         if (Deg[a] == 0)
558         {
559             if (SOAG.IsSynthesized(X, a))
560                 Cur[a] = true;
561             else if (SOAG.IsInherited(X, a))
562                 Leave[a] = true;
563         }
564     }
565     trace!"compute partition for symbol %s"(EAG.HNontRepr(X));
566     trace!"initially: Cur=%s, Leave=%s"(Cur, Leave);
567     do
568     {
569         ALists.Reset(LastCur);
570         foreach (size_t elem; Cur.bitsSet)
571             ALists.Append(LastCur, elem.to!int);
572         for (b = 0; b <= XmaxAff; ++b)
573         {
574             for (a1 = ALists.firstIndex; a1 <= LastCur.Last; ++a1)
575             {
576                 a = LastCur.Elem[a1];
577                 if (Cur[a] && DS[a][b] == unor)
578                 {
579                     Orient(a, b, X, New);
580                     foreach (size_t elem; New.bitsSet)
581                     {
582                         c = DIV(elem, Seperator).to!int;
583                         d = MOD(elem, Seperator).to!int;
584                         DS[c][d] = element;
585                         ++Deg[c];
586                         if (DS[d][c] == unor)
587                             DS[d][c] = nil;
588                         if (Cur[c])
589                             Cur[c] = false;
590                         else if (Deg[c] == 1)
591                             Leave[c] = false;
592                     }
593                 }
594             }
595         }
596         ++Part;
597         trace!"partition %s: Cur=%s, Leave=%s"(Part, Cur, Leave);
598         foreach (size_t elem; Cur.bitsSet)
599         {
600             SOAG.PartNum[SOAG.Sym[X].AffPos.Beg + elem] = Part;
601             for (b = 0; b <= XmaxAff; ++b)
602             {
603                 if (DS[b][elem] == element)
604                 {
605                     --Deg[b];
606                     if (Deg[b] == 0)
607                         Leave[b] = true;
608                 }
609             }
610         }
611         trace!"afterwards: Cur=%s, Leave=%s"(Cur, Leave);
612 
613         BitArray tmp = Cur;
614 
615         Cur = Leave;
616         Leave = tmp;
617         Leave[] = false;
618     }
619     while (Cur.count > 0);
620     if (SOAG.Sym[X].MaxPart < Part)
621         SOAG.Sym[X].MaxPart = Part;
622     if (SOAG.MaxPart < Part)
623         SOAG.MaxPart = Part;
624 }
625 
626 /**
627  * SEM: dynamisches topologisches Sortieren aller Symbole der Grammatik
628  */
629 void DynTopSort()
630 {
631     Cur = BitArray();
632     Cur.length = SOAG.MaxAffNumInSym + 1;
633     Leave = BitArray();
634     Leave.length = SOAG.MaxAffNumInSym + 1;
635     Deg = new int[SOAG.MaxAffNumInSym + 1];
636     DS = new int[][SOAG.MaxAffNumInSym + 1];
637     foreach (ref row; DS)
638         row = new int[SOAG.MaxAffNumInSym + 1];
639     New = BitArray();
640     New.length = (SOAG.MaxAffNumInSym + 1) * (SOAG.MaxAffNumInSym + 1) + 1;
641     Seperator = SOAG.MaxAffNumInSym + 1;
642     ALists.New(LastCur, 16);
643     for (int S = EAG.firstHNont; S < EAG.NextHNont; ++S)
644     {
645         if (!EAG.Pred[S] && EAG.All[S])
646             DynTopSortSym(S);
647     }
648 }
649 
650 /**
651  * SEM: Treiber
652  */
653 void Compute()
654 {
655     const undefined = -1;
656 
657     SOAG.Init;
658     // initialize partition number of each affix position to finally enforce that it's defined
659     SOAG.PartNum[SOAG.firstPartNum .. SOAG.NextPartNum] = undefined;
660     VarBuf = new VarBufDesc[50];
661     ChangeBuf = new ChangeBufDesc[64];
662     NextVarBuf = firstVarBuf;
663     NextChangeBuf = firstChangeBuf;
664     OAG = true;
665     Phase = computeDPandIDP;
666     ComputeDP;
667     ComputeIDPTrans;
668     Phase = dynTopSort;
669     DynTopSort;
670     if (OAG)
671         info!"grammar is SOAG";
672     else
673         info!"grammar is SOAG (backtracked)";
674 }