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