1 module epsilon.soag.visitseq;
2 
3 import EAG = epsilon.eag;
4 import runtime;
5 import hash = epsilon.soag.hash;
6 import SOAG = epsilon.soag.soag;
7 import std.range;
8 
9 const noVisit = -1;
10 int[] InDeg;
11 
12 /**
13  * IN:  -
14  * OUT: -
15  * SEM: Berechnung der maximalen Visits in Sym[X].MaxPart
16  *      und der Visit-Nummer der Affixpositionen in PartNum[AffPos].
17  */
18 void ComputeVisitNo()
19 {
20     import std.conv : to;
21     import std.exception : enforce;
22     import std.format: format;
23 
24     int AP;
25     int MaxPart;
26     int PartNum;
27 
28     foreach (S; EAG.All.bitsSet)
29         if (!EAG.Pred[S])
30         {
31             MaxPart = DIV(SOAG.Sym[S].MaxPart + 1, 2).to!int;
32             SOAG.Sym[S].MaxPart = MaxPart;
33             for (AP = SOAG.Sym[S].AffPos.Beg; AP <= SOAG.Sym[S].AffPos.End; ++AP)
34             {
35                 enforce(SOAG.PartNum[AP] >= 0,
36                         format!"partition number for affix position %d at symbol %s not determined"
37                             (AP, EAG.HNontRepr(S)));
38 
39                 PartNum = DIV(SOAG.PartNum[AP] + 1, 2).to!int;
40                 SOAG.PartNum[AP] = MaxPart - PartNum + 1;
41             }
42         }
43 }
44 
45 /**
46  * IN:  Affixparameter
47  * OUT: Visit-Nummer des Affixparameters
48  * SEM: Auslesen der Visit-Nummer des Affixparameters, Schnittstellenprozedur
49  */
50 int GetVisitNo(int AP) @nogc nothrow @safe
51 {
52     const S = SOAG.SymOcc[SOAG.AffOcc[AP].SymOccInd].SymInd;
53 
54     return SOAG.PartNum[SOAG.Sym[S].AffPos.Beg + SOAG.AffOcc[AP].AffOccNum.InSym];
55 }
56 
57 /**
58  * IN:  Symbolvorkommen, die keine Prädikate sind
59  * OUT: die maximale Visit-Nummer dieses Symbols
60  * SEM: Auslesen der maximalen Visit-Nummer des Symbolvorkommens, Schnittstellenprozedur
61  */
62 int GetMaxVisitNo(int SO) @nogc nothrow @safe
63 {
64     return SOAG.Sym[SOAG.SymOcc[SO].SymInd].MaxPart;
65 }
66 
67 /**
68  * IN:  aktueller Visit, Regel, aktuller Visit, Symbolvorkommen, Visitnummer
69  * OUT: Nummer des Eintrages in der Visitsequenz der Regel
70  * SEM: Durchsucht die Visitsequenz nach dem Visit des Symbolvorkommens mit entsprechender Besuchsnummer.
71  */
72 int GetNextVisit(int V, int R, int SO, int VN) @nogc nothrow @safe
73 {
74     while (V <= SOAG.Rule[R].VS.End)
75     {
76         if (auto visit = cast(SOAG.Visit) SOAG.VS[V])
77         {
78             if (visit.SymOcc == SO && visit.VisitNo == VN)
79                 return V;
80         }
81         else if (auto call = cast(SOAG.Call) SOAG.VS[V])
82         {
83             if (call.SymOcc == SO)
84                 return V;
85         }
86         else if (auto leave = cast(SOAG.Leave) SOAG.VS[V])
87         {
88             if (leave.VisitNo == VN && SOAG.Rule[R].SymOcc.Beg == SO)
89                 return V;
90         }
91         ++V;
92     }
93     return noVisit;
94 }
95 
96 /**
97  * IN:  Regel, Symbolvorkommen, Visitnummer
98  * OUT: Nummer des Eintrages in der Visitsequenz der Regel
99  * SEM: Durchsucht die Visitsequenz nach dem Visit des Symbolvorkommens mit entsprechender Besuchsnummer.
100  */
101 int GetVisit(int R, int SO, int VN) @nogc nothrow @safe
102 {
103     return GetNextVisit(SOAG.Rule[R].VS.Beg, R, SO, VN);
104 }
105 
106 /**
107  * IN:  Affixparameter
108  * OUT: Instruktion oder NIL für NOP
109  * SEM: Erzeugung einer Instruktion in Abhäengigkeit vom übergebenen Affixparameter
110  */
111 SOAG.Instruction MapVS(int AO) nothrow
112 {
113     if (!EAG.ParamBuf[SOAG.AffOcc[AO].ParamBufInd].isDef)
114         return null;
115 
116     const SO = SOAG.AffOcc[AO].SymOccInd;
117 
118     if (SOAG.IsPredNont(SO))
119     {
120         SOAG.Call Call = new SOAG.Call;
121 
122         Call.SymOcc = SO;
123         return Call;
124     }
125 
126     const R = SOAG.SymOcc[SO].RuleInd;
127 
128     if (SOAG.Rule[R].SymOcc.Beg == SO)
129     {
130         if (GetVisitNo(AO) - 1 > 0)
131         {
132             SOAG.Leave Leave = new SOAG.Leave;
133 
134             Leave.VisitNo = GetVisitNo(AO) - 1;
135             return Leave;
136         }
137         return null;
138     }
139     else
140     {
141         SOAG.Visit Visit = new SOAG.Visit;
142 
143         Visit.SymOcc = SO;
144         Visit.VisitNo = GetVisitNo(AO);
145         return Visit;
146     }
147 }
148 
149 /**
150  * IN:  Symbolvorkommen
151  * OUT: Instruktion
152  * SEM: Berechnung der abschliessenden Instruktionen für ein Symbolvorkommen
153  */
154 SOAG.Instruction CompleteTraversal(int SO) nothrow
155 {
156     if (SOAG.IsPredNont(SO))
157     {
158         SOAG.Call Call = new SOAG.Call;
159 
160         Call.SymOcc = SO;
161         return Call;
162     }
163 
164     const R = SOAG.SymOcc[SO].RuleInd;
165 
166     if (SOAG.Rule[R].SymOcc.Beg == SO)
167     {
168         SOAG.Leave Leave = new SOAG.Leave;
169 
170         Leave.VisitNo = GetMaxVisitNo(SO);
171         return Leave;
172     }
173 
174     SOAG.Visit Visit = new SOAG.Visit;
175 
176     Visit.SymOcc = SO;
177     Visit.VisitNo = GetMaxVisitNo(SO);
178     return Visit;
179 }
180 
181 /**
182  * IN:  Regel
183  * OUT: -
184  * SEM: topologische Sortierung der Affixparameter anhand ihrer Abhängigkeiten
185  */
186 void TopSort(int R)
187 {
188     int AO;
189     int AN;
190     int BO;
191     int BN;
192     SOAG.Instruction Instr;
193     int[] ZeroInDeg;
194 
195     for (BO = SOAG.Rule[R].AffOcc.End; BO >= SOAG.Rule[R].AffOcc.Beg; --BO)
196     {
197         BN = SOAG.AffOcc[BO].AffOccNum.InRule;
198         InDeg[BN] = 0;
199         for (AO = SOAG.Rule[R].AffOcc.Beg; AO <= SOAG.Rule[R].AffOcc.End; ++AO)
200         {
201             AN = SOAG.AffOcc[AO].AffOccNum.InRule;
202             if (SOAG.Rule[R].TDP[AN][BN])
203                 ++InDeg[BN];
204         }
205         if (InDeg[BN] == 0)
206             ZeroInDeg ~= BO;
207     }
208     while (!ZeroInDeg.empty)
209     {
210         AO = ZeroInDeg.back;
211         ZeroInDeg.popBack;
212         Instr = MapVS(AO);
213         AN = SOAG.AffOcc[AO].AffOccNum.InRule;
214         if (!hash.IsIn(Instr))
215         {
216             hash.Enter(Instr);
217             SOAG.AppVS(Instr);
218         }
219         for (BO = SOAG.Rule[R].AffOcc.End; BO >= SOAG.Rule[R].AffOcc.Beg; --BO)
220         {
221             BN = SOAG.AffOcc[BO].AffOccNum.InRule;
222             if (SOAG.Rule[R].TDP[AN][BN])
223             {
224                 --InDeg[BN];
225                 if (InDeg[BN] == 0)
226                     ZeroInDeg ~= BO;
227             }
228         }
229     }
230 }
231 
232 /**
233  * SEM: Generierung der Visit-Sequenzen
234  */
235 void Generate()
236 {
237     int SO;
238     SOAG.Instruction Instr;
239 
240     ComputeVisitNo;
241     // hash.Init(SOAG.MaxAffNumInRule); // does not work if (MaxAffNumInRule == 0)
242     hash.Init(SOAG.MaxAffNumInRule + 1);
243     InDeg = new int[SOAG.MaxAffNumInRule + 1];
244     for (int R = SOAG.firstRule; R < SOAG.NextRule; ++R)
245     {
246         SOAG.Rule[R].VS.Beg = SOAG.NextVS;
247         if (SOAG.IsEvaluatorRule(R))
248         {
249             hash.Reset;
250             TopSort(R);
251             for (SO = SOAG.Rule[R].SymOcc.Beg + 1; SO <= SOAG.Rule[R].SymOcc.End; ++SO)
252             {
253                 Instr = CompleteTraversal(SO);
254                 if (!hash.IsIn(Instr))
255                     SOAG.AppVS(Instr);
256             }
257             Instr = CompleteTraversal(SOAG.Rule[R].SymOcc.Beg);
258             if (!hash.IsIn(Instr))
259                 SOAG.AppVS(Instr);
260         }
261         SOAG.Rule[R].VS.End = SOAG.NextVS - 1;
262     }
263 }