1 /***************************************************************************
2                           knoten.cpp  -  description
3                              -------------------
4     begin                : Mit Jul 12 22:54:51 MEST 2000
5     copyright            : (C) 2000 by Immi
6     email                : cuyo@pcpool.mathematik.uni-freiburg.de
7 
8 Modified 2002,2003,2005,2006,2008-2011,2014 by the cuyo developers
9 Maintenance modifications 2012 by Bernhard R. Link
10 Maintenance modifications 2012 by the cuyo developers
11 
12  ***************************************************************************/
13 
14 /***************************************************************************
15  *                                                                         *
16  *   This program is free software; you can redistribute it and/or modify  *
17  *   it under the terms of the GNU General Public License as published by  *
18  *   the Free Software Foundation; either version 2 of the License, or     *
19  *   (at your option) any later version.                                   *
20  *                                                                         *
21  ***************************************************************************/
22 
23 #include <cstdlib>
24 #include <cstdio>
25 
26 #include "cuyointl.h"
27 #include "knoten.h"
28 #include "sorte.h"
29 #include "leveldaten.h"
30 #include "blop.h"
31 #include "global.h"
32 #include "layout.h"
33 
34 
35 /*************************************************************************/
36 /* Was von vornerein so im Namespace rumliegt */
37 
38 
39 /* xxx_anz wird in blop.h definiert. */
40 
41 char spezvar_namen[spezvar_anz][22] = {
42   "file", "pos", "kind", "version", "qu",
43   "out1", "out2",
44   "", // kind_beim_letzten_draw_aufruf; ist nicht f�r den User gedacht.
45   "inhibit", "weight", "behaviour",
46   "falling_speed", "falling_fast_speed",
47   "" // am_platzen; kriegt der Cual-Code (im Moment) nur als Konstante
48      // "exploding" zu sehen (0 = nicht am platzen; sonst 1 - 8)
49 };
50 
51 int spezvar_default[spezvar_anz] = {
52   0, 0, blopart_ausserhalb, 0, viertel_alle,
53   spezvar_out_nichts, spezvar_out_nichts,
54   blopart_ausserhalb,
55   0, 1, 0,
56   6, gric,
57   0
58 };
59 
60 int spezvar_defaultart[spezvar_anz] = {
61   da_event, da_event, da_keinblob, da_keinblob, da_event,
62   da_event, da_event,
63   da_init,
64   da_init, da_init, da_nie,
65   da_init, da_init,
66   da_init
67 };
68 
69 
70 /* Reihenfolge -1, -2, -3, ... */
71 char spezconst_namen[spezconst_anz][22] = {
72   "turn", "connect", "falling", "size", "loc_x", "loc_y", "loc_p",
73   "players", "falling_fast", "exploding", "loc_xx", "loc_yy", "basekind", "time",
74   "informational"
75 };
76 
77 int spezconst_default[spezconst_anz] = {
78   0, 0, 0, 0, -1, -1, 0,
79   0, 0, 0, -1, -1, blopart_ausserhalb, 0,
80   0
81 };
82 
83 
84 #define const_anz (21+5+2*9+6+nachbarschaft_letzte+1)
85 //int const_anz = feste_konst_anz;
86 char const_namen[const_anz][27] = {
87   /* Viertelst�ckchen */
88   "Q_ALL",
89   "Q_TL", "Q_TR", "Q_BL", "Q_BR",
90   "Q_TL_TL", "Q_TR_TL", "Q_BL_TL", "Q_BR_TL",
91   "Q_TL_TR", "Q_TR_TR", "Q_BL_TR", "Q_BR_TR",
92   "Q_TL_BL", "Q_TR_BL", "Q_BL_BL", "Q_BR_BL",
93   "Q_TL_BR", "Q_TR_BR", "Q_BL_BR", "Q_BR_BR",
94 
95   /* Sortennamen */
96   "nothing", "outside", "global", "semiglobal", "info",
97   /* Buchstaben, die in den Strings in Nachbariterator verwendet werden. */
98   /*   A        B         C        D         E          F          G          H          I */
99   "DIR_U", "DIR_UR", "DIR_R", "DIR_DR", "DIR_UUL", "DIR_UUR", "DIR_RRU", "DIR_RRD", "DIR_F",
100   "DIR_D", "DIR_DL", "DIR_L", "DIR_UL", "DIR_DDR", "DIR_DDL", "DIR_LLD", "DIR_LLU", "DIR_B",
101 
102   /* spezvar_verhalten */
103   "explodes_on_size", "explodes_on_explosion", "explodes_on_chain_reaction",
104   "calculate_size", "goalblob", "floats",
105 
106   /* Nachbarschaften */
107   "neighbours_rect", "neighbours_diagonal", "neighbours_hex6",
108   "neighbours_hex4", "neighbours_knight", "neighbours_eight", "neighbours_3D",
109   "neighbours_none", "neighbours_horizontal", "neighbours_vertical"
110 };
111 
112 /* Eigentlich sollten hier die Konstanten aus bilddatei.h verwendet werden;
113    das w�re aber so viel Tipparbeit... */
114 int const_werte[const_anz] = {
115   /* Viertelst�ckchen */
116   viertel_alle,
117   0, 5, 10, 15,
118   0, 1, 2, 3,
119   4, 5, 6, 7,
120   8, 9, 10, 11,
121   12, 13, 14, 15,
122 
123   /* Sortennamen */
124   blopart_keins, blopart_ausserhalb, blopart_global, blopart_semiglobal, blopart_info,
125 
126   /* Richtungskonstanten f�r inhibit */
127   0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100,
128   0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000,
129 
130   /* Bits f�rs spezvar_verhalten */
131   platzt_bei_gewicht, platzt_bei_platzen, platzt_bei_kettenreaktion,
132   berechne_kettengroesse, verhindert_gewinnen, schwebt,
133 
134   /* Nachbarschaften */
135   nachbarschaft_normal, nachbarschaft_schraeg, nachbarschaft_6,
136   nachbarschaft_6_schraeg, nachbarschaft_springer, nachbarschaft_dame,
137   nachbarschaft_6_3d, nachbarschaft_garnichts, nachbarschaft_horizontal,
138   nachbarschaft_vertical
139 };
140 
141 
142 
143 /* F�r den internen Gebrauch in Schleifen: Die pics-artigen keys. */
144 const char * gPicsetc[] = {
145   "pics",
146   "greypic",
147   "startpic",
148   0
149 };
150 
151 
152 
153 
154 /*************************************************************************/
155 /* Knoten */
156 
157 
158 /** Liefert einen String zur�ck, der angibt, wo dieser Code
159     definiert wurde (f�r Fehlermeldungen) */
getDefString() const160 Str Knoten::getDefString() const {
161   return _sprintf("%s:%d", mDateiName.data(), mZeilenNr);
162 }
163 
164 
165 
166 
167 /*************************************************************************/
168 /* DefKnoten */
169 
170 
171 /** Erzeugt den Top-Knoten. */
DefKnoten()172 DefKnoten::DefKnoten():
173   Knoten("?", 0),
174   mVater(0), mTiefe(tiefe_global),
175   mErstLevelDannCual(0),
176   mVarNrBei(0),
177   mBoolNrBei(-1),
178   mDefaultWerte(std::vector<int>()),
179   mDefaultArten(std::vector<int>()),
180   mSortenAnfaenge()
181 {
182   /* Die vordefinierten Namespace-Dinge einf�gen. */
183   speicherGlobaleVordefinierte();
184 }
185 
186 
187 /** Erzeugt einen Unter-Knoten. */
DefKnoten(Str datna,int znr,DefKnoten * vater)188 DefKnoten::DefKnoten(Str datna, int znr, DefKnoten * vater):
189   Knoten(datna, znr),
190   mVater(vater), mTiefe(vater->mTiefe + 1),
191   mErstLevelDannCual(0),
192   /* Das ganze Variablen-Zeug vom Vater �bernehmen...: */
193   mVarNrBei(vater->mVarNrBei),
194   mBoolNrBei(vater->mBoolNrBei),
195   mDefaultWerte(vater->mDefaultWerte),
196   mDefaultArten(vater->mDefaultArten),
197   mSortenAnfaenge()
198 {
199 }
200 
~DefKnoten()201 DefKnoten::~DefKnoten() {
202   tKnotenMap::Index it(mKinder);
203   for(; !it.ende(); ++it)
204     delete it.datum();
205 }
206 
207 
208 
209 
toString() const210 Str DefKnoten::toString() const {
211   Str ret = "{\n";
212   tKnotenMap::constIndex it(mKinder);
213   for(; !it.ende(); ++it) {
214     ret += it.schluessel() + it.version().toString()
215         + "=" + it.datum()->toString() + "\n";
216   }
217   ret += "}\n";
218   return ret;
219 }
220 
221 
fuegeEin(const Str & na,const Version & version,Knoten * wert)222 void DefKnoten::fuegeEin(const Str & na, const Version & version,
223 			 Knoten * wert) {
224   if (mKinder.enthaelt(na,version))
225     throw Fehler("\"%s\" already defined.", na.data());
226   mKinder.neuerEintrag(na,version,wert);
227 
228   /* Wenn ein neuer Level geparst wird, will das ld evtl. wissen.
229      (Falls der Benutzer neu gemachte Level ausprobieren will,
230      die noch nicht in "level=..." stehen.) */
231   if (mTiefe == tiefe_global && wert->type() == type_DefKnoten) {
232     ld->levelGefunden(na);
233 
234     /* Und bei der Gelegenheit merken wir uns gleich noch, dass schon
235        ein Level in diesem Knoten ist. Wenn jetzt noch Cual-Code kommt,
236        ist das gef�hrlich, und es soll eine Warnung ausgegeben werden. */
237     mErstLevelDannCual |= 1;
238   }
239 
240   /* Auf Level-Ebene evtl. noch ein paar Konstanten einf�gen... */
241   if (mTiefe == tiefe_level) {
242     /* pics-Eintrag? Dann k�nnen ja jetzt die pics-Konstanten erzeugt
243        werden. */
244 
245     /* Achtung, verwirrend: wert ist nicht der Wert der Konstante,
246        sondern das, was rechts vom "=" in der ld-Datei steht. */
247     for (const char ** i=gPicsetc; *i; i++)
248       if (na==*i)
249 	speicherPicsConst(version, wert, *i);
250     /* Wenn es den Namen schon gab, sind wir ganz still, denn das ist OK. */
251     try {
252       if (na == "emptypic")
253 	speicherKnotenConst(version, wert, blopart_keins);
254     } catch (Fehler f) {}
255   }
256 
257   /* Wenn es eine Konstante ist, wird auch noch eine Variable draus gemacht. */
258   const DatenKnoten * wert_;
259   switch (wert->type()) {
260     case type_DatenKnoten:
261       wert_ = (const DatenKnoten *) wert;
262       break;
263     case type_ListenKnoten:
264       if (((ListenKnoten*) wert)->getImpliziteLaenge() == 1)
265         wert_ = ((ListenKnoten*) wert)->getDatum(0);
266       else
267         wert_ = 0;
268       break;
269     default:
270       wert_ = 0;
271   }
272   if (wert_)
273     if (wert_->datatype() == type_ZahlDatum)
274       speicherDefinition(namespace_variable, na, version,
275         new VarDefinition(na, wert_->getZahl(), vd_konstante, da_keinblob, 0));
276 }
277 
278 
279 /** L�scht alle Kinder raus, die DefKnoten sind und nicht
280     "Title" hei�en.
281     Wird von LevelDaten::ladLevelSummary() gebraucht. */
loeschAlleLevel()282 void DefKnoten::loeschAlleLevel() {
283   tKnotenMap::Index it(mKinder);
284   while (!it.ende()) {
285     Knoten * k = it.datum();
286     tKnotenMap::Index nae=it;  ++nae;
287     if (k->type() == type_DefKnoten && it.schluessel() != "Title") {
288       delete k;
289       mKinder.loescheEintrag(it);
290     }
291     it = nae;
292   }
293 }
294 
295 
296 /***** Methoden f�r den Codespeicher *****/
297 
298 
299 
300 /** Speichert alle vordefinierten Variablen in den
301     Namespace, au�er die pics-Konstanten. Wird vom Constructor
302     des WurzelKnotens aufgerufen. */
speicherGlobaleVordefinierte()303 void DefKnoten::speicherGlobaleVordefinierte() {
304 
305   Version vallg = Version();
306 
307   /* Spezial-Variablen (z. B. file); Nummern ab 0 */
308   /* Das sollten die ersten Variablen sein, die erzeugt werden;
309      sonst stimmen nachher die Nummern nicht. */
310   CASSERT(mVarNrBei == 0);
311   for (int i = 0; i < spezvar_anz; i++) {
312     /* Nicht direkt mit speicherDefinition() erzeugen; sonst
313        werden die Default-Werte nicht nochmal in mDefaultWerte
314        gespeichert. */
315     neueVarDefinition(spezvar_namen[i], vallg,
316 		      spezvar_default[i], spezvar_defaultart[i]);
317   }
318 
319   /* Spezial-Konstanten (d. h. Variablen, die nur gelesen werden
320      werden k�nnen), z. B. verbindung; Nummern < 0 */
321   for (int i = 0; i < spezconst_anz; i++)
322     speicherDefinition(namespace_variable, spezconst_namen[i], vallg,
323         new VarDefinition(spezconst_namen[i], spezconst_default[i],
324                           vd_spezconst, da_nie, -i-1)
325       );
326 
327   /* Ganz normale feste Konstanten (z. B. nochange) werden so abgespeichert,
328      da� auch au�erhalb von cual darauf zugegriffen werden kann. */
329   for (int i = 0; i < const_anz; i++)
330     fuegeEin(const_namen[i], vallg, new ZahlKnoten("",0,const_werte[i]));
331 
332 }
333 
334 
335 
336 /** Speichert die Pics-Konstanten. (picsliste sollte der pics-Knoten sein.)
337     Wird von fuegeEin(...) aufgerufen, wenn es die pics bekommt.
338     Alternativ auch bei greypic und startpic.
339     Welches davon steht in schluessel */
speicherPicsConst(const Version & version,Knoten * picsliste,const char * schluessel)340 void DefKnoten::speicherPicsConst(const Version& version, Knoten * picsliste,
341 				  const char* schluessel) {
342   /* Eigentlich k�nnten wir gleich eine Fehlermeldung
343      ausspucken, wenn der Typ von picsliste falsch ist, aber die anderen
344      entsprechenden Typ-Fehlermeldungen kommen auch erst beim Starten des
345      Levels. Also hier erst mal ruhig sein. */
346   if (picsliste->type() == type_ListenKnoten) {
347 
348     /* Erstmal den Anfang ermitteln (wenn wir das noch nicht getan haben).
349        Das ist die Summe der impliziten Listenl�ngen zu den anderen
350        Schl�sseln, die schon vorkamen.
351        Und zwar in der korrekten, das hei�t globalen Version.
352        Da� wir die schon jetzt kennen, stellt VersionMap automatisch sicher,
353        indem ein Aufruf von Bestapproximierende die VersionMap f�r sp�tere
354        Eintr�ge sperrt. */
355     int anfang;
356     std::map<Str,int>::const_iterator i = mSortenAnfaenge.find(schluessel),
357                                       e = mSortenAnfaenge.end();
358     if (i==e) {
359       anfang = getSortenAnzahl();
360       mSortenAnfaenge[schluessel] = anfang;
361     } else
362       anfang = i->second;
363 
364     ListenKnoten * lki = (ListenKnoten*) picsliste;
365     int nummer=anfang;
366     for (int i = 0; i < lki->getLaenge(); i++) {
367       /* picsEndungWeg() steht in global.* */
368       Str varna = picsEndungWeg(lki->getKernDatum(i,type_WortDatum)
369 				     ->getWort());
370       /* Wenn es den Namen schon gab, sind wir ganz still, denn das ist OK. */
371       if (!mCodeSpeicher[namespace_variable].enthaelt(varna,version))
372         speicherDefinition(namespace_variable, varna, version,
373             new VarDefinition(varna, nummer, vd_konstante, da_nie, 0));
374       nummer += lki->getVielfachheit(i);
375     }
376   }
377 }
378 
379 
380 /** Speichert eine Konstante mit dem Namen, der in nameKnoten steht und
381     dem angegebenen Wert. nameKnoten ist hoffentlich ein ListenKnoten
382     mit genau einem Eintrag. Wird von fuegeEin() aufgerufen, um die
383     Gras-, die Grau- und die nix-Konstante abzuspeichern, wenn es die
384     bekommt. */
speicherKnotenConst(const Version & version,Knoten * nameKnoten,int wert)385 void DefKnoten::speicherKnotenConst(const Version & version,
386 				    Knoten * nameKnoten, int wert) {
387   /* Keine Fehlermeldung bei falschem Typ; siehe speicherPicsConst() */
388   if (nameKnoten->type() == type_ListenKnoten) {
389     ListenKnoten * lk = (ListenKnoten*) nameKnoten;
390     if (lk->getLaenge() == 1) {
391       Str varna = picsEndungWeg(lk->getDatum(0,type_WortDatum)
392 				     ->getWort());
393       speicherDefinition(namespace_variable, varna, version,
394           new VarDefinition(varna, wert, vd_konstante, da_nie, 0)
395         );
396     }
397   }
398 }
399 
400 
401 
402 /* Erzeugt eine neue Var-Definition und speichert sie ab. Dabei
403    bekommt sie auch gleich eine Nummer. (Aufzurufen, wenn eine
404    VarDefinition geparst wurde.) def ist der Default-Wert. */
neueVarDefinition(const Str & na,const Version & version,int def,int defart)405 void DefKnoten::neueVarDefinition(const Str & na, const Version & version,
406 				  int def, int defart) {
407   //print_to_stderr(_sprintf("Define %s\n", na.data()));
408   if (na == "") {
409     /* Wenn kein Name angegeben wurde, handelt es sich wohl um eine
410        Spez-Var, die f�r den User unsichtbar sein soll. Dann nur
411        die Variable erzeugen, aber keine Definition abspeichern. */
412     neueVariable(def,defart);
413   } else {
414     speicherDefinition(namespace_variable, na, version,
415       new VarDefinition(na, def, vd_variable, defart,
416 			neueVariable(def,defart)));
417   }
418 }
419 
420 
421 /* Speichert eine neue Definition - Code oder Variable. Noch unsch�n:
422    Sollte von au�en nur f�r Code aufgerufen werden. Bei Variablen immer
423    neueVarDefinition verwenden! */
speicherDefinition(int ns,const Str & na,const Version & version,Definition * f)424 void DefKnoten::speicherDefinition(int ns, const Str & na,
425 				   const Version & version, Definition * f) {
426 /*  print_to_stderr(_sprintf("Speichere %s = %s\n", na.data(),
427          f->toString().data()));*/
428   if (mCodeSpeicher[ns].enthaelt(na,version))
429     throw Fehler("\"%s\" already defined.", na.data());
430 
431   /* (Vielleicht kennt Papi den Code schon, aber das kann man
432      �berschreiben.) */
433 
434   mCodeSpeicher[ns].neuerEintrag(na,version,f);
435 
436   /* Wenn wir der globale Knoten sind und schon eine Level-Definition kam,
437      dann Warnung ausgeben. */
438   if (gDebug && mErstLevelDannCual == 1) {
439     /* TRANSLATORS: "Cual" is a programming language's name */
440     print_to_stderr("Warning: There's global Cual code _after_ some level definitions. Be sure\n"
441               "not to use that Cual code in the levels before it. (Due to a bug, this will\n"
442 	      "sometimes not result in an error message but in strange behaviour.)\n");
443     mErstLevelDannCual |= 2;
444   }
445 }
446 
447 
448 
449 /** Liefert eine Code-Definition aus diesem Speicher oder von
450     weiter oben. Throwt bei Nichtexistenz.
451     Achtung: Beh�lt den Besitz an der Defintion. */
getDefinition(int ns,const Str & na,const Version & version,bool defaultVorhanden)452 Definition * DefKnoten::getDefinition(int ns, const Str & na,
453 				      const Version & version,
454 				      bool defaultVorhanden) {
455 
456   Definition * ret;
457 
458   if (!mCodeSpeicher[ns].enthaelt(na)) {
459     /* Wir kennen den Code nicht. Also Papi fragen. */
460     if (mVater)
461       return mVater->getDefinition(ns, na, version, defaultVorhanden);
462 
463     /* Ups, wir haben ja gar keinen Papi. */
464     if (defaultVorhanden)
465       return 0;
466     else
467       /* TRANSLATORS: "<<" and ">>" are programming keywords
468 	 and should not be translated. */
469       throw Fehler("\"%s\" not defined inside << >>.", na.data());
470   }
471 
472   ret = mCodeSpeicher[ns].Bestapproximierende(na,version,defaultVorhanden);
473 
474   return ret;
475 }
476 
477 
478 
479 /** Liefert ein Kind von hier oder von weiter oben. */
getVerwandten(const Str & na,const Version & version,bool defaultVorhanden)480 Knoten * DefKnoten::getVerwandten(const Str & na, const Version & version,
481 				  bool defaultVorhanden) {
482 
483   Knoten * ret;
484 
485   if (!mKinder.enthaelt(na)) {
486     /* Das ist nicht mein Kind. Also Papi fragen. */
487     if (mVater)
488       return mVater->getVerwandten(na,version,defaultVorhanden);
489 
490     /* Ups, wir haben ja gar keinen Papi. */
491     if (defaultVorhanden)
492       return 0;
493     else
494       throw Fehler("\"%s\" not defined.", na.data());
495   }
496 
497   ret = mKinder.Bestapproximierende(na,version,defaultVorhanden);
498 
499   return ret;
500 }
501 
502 
503 
504 
505 /***** Variablen-Nummern-Verwaltung *****/
506 
507 
508 /** Erzeugt eine unbenannte Variable
509     und liefert die Nummer zur�ck. */
neueVariable(int def,int defart)510 int DefKnoten::neueVariable(int def, int defart) {
511   /* Sorten-Variablen gibt's nicht (wirklich). Die kommen in den
512      Level-Knoten */
513   if (mTiefe == tiefe_sorte)
514     return mVater->neueVariable(def,defart);
515 
516   CASSERT((int) mDefaultWerte.size() == mVarNrBei);
517   CASSERT((int) mDefaultArten.size() == mVarNrBei);
518   //print_to_stderr(_sprintf("t=%d  %d %d\n", mTiefe, mDefaultWerte.size(), mVarNrBei));
519   /* Das kann man auch schneller machen... (immer mehr auf einmal
520      reservieren) falls das QT nicht eh tut */
521   mDefaultWerte.resize(mVarNrBei + 1);
522   mDefaultArten.resize(mVarNrBei + 1);
523   mDefaultWerte[mVarNrBei] = def;
524   mDefaultArten[mVarNrBei] = defart;
525 
526   return mVarNrBei++;
527 }
528 
529 
530 
neuerDefault(int var,int def,int defart)531 void DefKnoten::neuerDefault(int var, int def, int defart) {
532   CASSERT(mVarNrBei>var);
533   mDefaultWerte[var]=def;
534   mDefaultArten[var]=defart;
535 }
536 
537 
538 
539 /** Erzeugt eine unbenannte Bool-Variable und liefert
540     die Nummer zur�ck. */
neueBoolVariable()541 int DefKnoten::neueBoolVariable() {
542   /* Sorten-Variablen gibt's nicht (wirklich). Die kommen in den
543      Level-Knoten */
544   if (mTiefe == tiefe_sorte)
545     return mVater->neueBoolVariable();
546 
547   if (mBoolNrBei == -1) {
548     /* Grad kein Platz mehr f�r Bools. Also neuen
549        Platz erzeugen. */
550     mBoolNrBei = bits_pro_int * neueVariable(0,da_init);
551   }
552 
553   int ret = mBoolNrBei;
554   mBoolNrBei++;
555 
556   /* Ist das aktuelle int voll mit Bools? */
557   if (mBoolNrBei % bits_pro_int == 0) {
558     mBoolNrBei = -1;
559   }
560 
561   return ret;
562 }
563 
564 
565 
getDatenLaenge() const566 int DefKnoten::getDatenLaenge() const {
567   CASSERT(mTiefe == tiefe_level);
568   return mVarNrBei;
569 }
570 
571 
572 
573 /** Liefert den Default-Wert der Variable mit Nummer nr. Es
574     muss aber eine richtige Variable sein, die echten Blop-
575     Speicherplatz verbraucht. (Sonst soll man sich den Default-
576     Wert aus der VarDefinition holen. Das hier ist nur f�r
577     Variablen-Anfangs-Initialisierung.) */
getDefaultWert(int nr) const578 int DefKnoten::getDefaultWert(int nr) const {
579   if (mVarNrBei<=nr) {
580     CASSERT(mVater);
581     return mVater->getDefaultWert(nr);
582   }
583   else
584     return mDefaultWerte[nr];
585 }
586 
getDefaultArt(int nr) const587 int DefKnoten::getDefaultArt(int nr) const {
588   if (mVarNrBei<=nr) {
589     CASSERT(mVater);
590     return mVater->getDefaultArt(nr);
591   }
592   else
593     return mDefaultArten[nr];
594 }
595 
596 
597 /** Liest mSortenAnfaenge aus. Throwt bei Nichtexistenz. */
getSortenAnfang(const Str & schluessel) const598 int DefKnoten::getSortenAnfang(const Str & schluessel) const {
599   std::map<Str,int>::const_iterator i = mSortenAnfaenge.find(schluessel);
600   CASSERT(i!=mSortenAnfaenge.end());
601   return i->second;
602 }
603 
604 
605 /** Liefert zurueck, wie viele Sortennummern insgesamt schon
606     von mSortenAnfaenge belegt sind. */
getSortenAnzahl() const607 int DefKnoten::getSortenAnzahl() const {
608   std::map<Str,int>::const_iterator i;
609     /* Anzahl der Sorten ermitteln
610        Das ist die Summe der impliziten Listenl�ngen zu den anderen
611        Schl�sseln, die schon vorkamen.
612        Und zwar in der korrekten, das hei�t globalen Version.
613        Da� wir die schon jetzt kennen, stellt VersionMap automatisch sicher,
614        indem ein Aufruf von Bestapproximierende die VersionMap f�r sp�tere
615        Eintr�ge sperrt. */
616 
617   /* Zu refaktorisieren:
618      Eigentlich sollte man den Wert irgendwo zwischenspeichern statt
619      ihn jedes mal neu auszurechnen... falls das moeglich ist, in
620      Anbetracht der Versionierung. Damit kenne ich mich nicht aus. */
621 
622   int anzahl = 0;
623   for (i=mSortenAnfaenge.begin(); i!=mSortenAnfaenge.end(); i++) {
624     CASSERT(mKinder.enthaelt(i->first));
625     Knoten* eintrag = mKinder.Bestapproximierende(i->first,
626 						  ld->getVersion(),
627 						  false);
628     CASSERT(eintrag->type()==type_ListenKnoten);
629     anzahl += ((ListenKnoten*) eintrag)->getImpliziteLaenge();
630   }
631   return anzahl;
632 }
633 
634 
635 
636 /*************************************************************************/
637 /* ListenKnoten */
638 
639 
ListenKnoten(Str datna,int znr)640 ListenKnoten::ListenKnoten(Str datna, int znr): Knoten(datna, znr) {}
641 
642 
~ListenKnoten()643 ListenKnoten::~ListenKnoten() {
644   for (int i = 0; i < (int) mKinder.size(); i++)
645     delete(mKinder[i]);
646 }
647 
648 
toString() const649 Str ListenKnoten::toString() const {
650   Str ret;
651   bool mitte = false;
652   for (int i = 0; i < (int) mKinder.size(); i++) {
653     if (mitte) ret += ", ";
654     mitte = true;
655 
656     ret += mKinder[i]->toString();
657   }
658   return ret;
659 }
660 
661 
662 
663 
getVielfachheit(int nr) const664 int ListenKnoten::getVielfachheit(int nr) const {
665   DatenKnoten * k = (DatenKnoten *) (mKinder[nr]);
666   CASSERT(k->type() == type_DatenKnoten);
667   if (k->datatype()==type_VielfachheitDatum)
668     return k->getZahl();
669   else
670     return 1;
671 }
672 
673 
674 
getImpliziteLaenge() const675 int ListenKnoten::getImpliziteLaenge() const {
676   return getLaengeBis(getLaenge());
677 }
678 
679 
680 
getLaengeBis(int nr) const681 int ListenKnoten::getLaengeBis(int nr) const {
682   int ret=0;
683   for (int i=0; i<nr; i++)
684     ret += getVielfachheit(i);
685   return ret;
686 }
687 
688 
getDatum(int nr,int solltyp)689 const DatenKnoten * ListenKnoten::getDatum(int nr,
690 					   int solltyp /*= type_EgalDatum*/) {
691   Knoten * k = mKinder[nr];
692   CASSERT(k->type() == type_DatenKnoten);
693   return ((DatenKnoten *) k)->assert_datatype(solltyp);
694 }
695 
696 
697 
getKernDatum(int nr,int solltyp)698 const DatenKnoten * ListenKnoten::getKernDatum(int nr,
699 					       int solltyp
700 					       /*= type_EgalDatum*/) {
701   const DatenKnoten * d = getDatum(nr);
702   if (d->datatype() == type_VielfachheitDatum)
703     d = ((VielfachheitKnoten *) d)->getNurDasWort();
704   return d->assert_datatype(solltyp);
705 }
706 
707 
708 
getImplizitesDatum(int nr,int solltyp)709 const DatenKnoten * ListenKnoten::getImplizitesDatum(int nr,
710 						     int solltyp
711 						     /*= type_EgalDatum*/) {
712   int nr_ = 0;
713   int vielfachheit = getVielfachheit(0);
714   while (nr>=vielfachheit) {
715     nr -= vielfachheit;
716     nr_++;
717     vielfachheit = getVielfachheit(nr_);
718   }
719   return getKernDatum(nr_,solltyp);
720 }
721 
722 
723 /** Setzt voraus, da� es nur einen Eintrag gibt. Gibt diesen Eintrag. */
getEinzigesDatum(int solltyp)724 const DatenKnoten * ListenKnoten::getEinzigesDatum(int solltyp
725                                              /*= type_EgalDatum*/) {
726   if (getImpliziteLaenge()!=1)
727     throw Fehler("%s","Value is a list and should not.");
728   return getDatum(solltyp);
729 }
730 
731 
732 /*************************************************************************/
733 /* DatenKnoten */
734 
assert_datatype(int solltyp) const735 const DatenKnoten * DatenKnoten::assert_datatype(int solltyp) const {
736   if ((solltyp != datatype()) && (solltyp!=type_EgalDatum)) {
737     Str solltyp_Darstellung = "<unknown type, please report>";
738     if (solltyp==type_WortDatum)
739       solltyp_Darstellung = "string";
740     if (solltyp==type_ZahlDatum)
741       solltyp_Darstellung = "int";
742     if (solltyp==type_VielfachheitDatum)
743       solltyp_Darstellung = "string * int";
744     throw Fehler("%s is of wrong type. %s expected",
745 		 toString().data(),
746 		 solltyp_Darstellung.data());
747   }
748   return this;
749 }
750 
751 
752 
753 
754 /*************************************************************************/
755 /* WortKnoten */
756 
getWort(int rolle) const757 Str WortKnoten::getWort(int rolle /*= wortrolle_einziges*/) const {
758   CASSERT(rolle==wortrolle_einziges);
759   return mWort;
760 }
761 
toString() const762 Str WortKnoten::toString() const {
763   return mWort;
764 }
765 
766 
767 
768 
769 /*************************************************************************/
770 /* ZahlKnoten */
771 
getZahl(int rolle) const772 int ZahlKnoten::getZahl(int rolle /*= zahlrolle_einziges*/) const {
773   CASSERT(rolle==zahlrolle_einzige);
774   return mZahl;
775 }
776 
toString() const777 Str ZahlKnoten::toString() const {
778   return _sprintf("%d", mZahl);
779 }
780 
781 
782 
783 
784 /*************************************************************************/
785 /* VielfachheitKnoten */
786 
getZahl(int rolle) const787 int VielfachheitKnoten::getZahl(int rolle /*= zahlrolle_einzige*/) const {
788   CASSERT(rolle==zahlrolle_einzige);
789   return mZahl;
790 }
791 
getWort(int rolle) const792 Str VielfachheitKnoten::getWort(int rolle
793 				     /*= wortrolle_einziges*/) const {
794   CASSERT(rolle==wortrolle_einziges);
795   return mWort;
796 }
797 
toString() const798 Str VielfachheitKnoten::toString() const {
799   return _sprintf("%s * %d",mWort.data(),mZahl);
800 }
801 
802