1
2%{
3
4/***************************************************************************
5                          parser.yy  -  description
6                             -------------------
7    begin                : Mit Jul 12 22:54:51 MEST 2000
8    copyright            : (C) 2000 by Immi
9    email                : cuyo@pcpool.mathematik.uni-freiburg.de
10
11Modified 2002,2003,2005,2006,2008,2010,2011,2014 by the cuyo developers
12
13 ***************************************************************************/
14
15/***************************************************************************
16 *                                                                         *
17 *   This program is free software; you can redistribute it and/or modify  *
18 *   it under the terms of the GNU General Public License as published by  *
19 *   the Free Software Foundation; either version 2 of the License, or     *
20 *   (at your option) any later version.                                   *
21 *                                                                         *
22 ***************************************************************************/
23
24#include <cstdlib>
25
26#include "cuyointl.h"
27#include "code.h"
28#include "fehler.h"
29#include "knoten.h"
30#include "variable.h"
31#include "ort.h"
32#include "version.h"
33#include "global.h"
34#include "leveldaten.h"
35#include "sound.h"
36
37#define YYMALLOC malloc
38#define YYFREE free
39
40
41/***********************************************************************/
42/* Globale Parse-Variablen */
43
44/** F�r Fehlerausgabe: Aktueller Dateiname */
45Str gDateiName;
46/** F�r Fehlerausgabe: Aktuelle Zeilen-Nummer */
47int gZeilenNr;
48
49/** True, wenn es w�hrend des Parsens (mindestens) einen Fehler gab. */
50bool gGabFehler;
51
52
53/** Wenn der Parser aufgerufen wird, muss in DefKnoten schon ein DefKnoten
54    stehen, an den alles geparste angef�gt wird. Normalerweise erzeugt man
55    einen neuen Defknoten. Beim Includen will man da aber schon was drin
56    haben.
57    Siehe auch %type <defknoten> alles */
58static DefKnoten * gAktDefKnoten;
59
60//#define MAX_INCLUDE_TIEFE 16
61/** YY_BUFFER_STATE ist ein flex-Datentyp f�r eine Datei, an der grade
62    geparst wird. */
63//static YY_BUFFER_STATE gIncludeStack[MAX_INCLUDE_TIEFE];
64/** Aktuelle Include-Tiefe. (0 bei Hauptdatei) */
65//static int gIncludeTiefe;
66
67//static DefKnoten * gIncludeMerk;
68
69
70/* Beim Erzeugen eines Codes m�ssen einige Variablen jedes Mal �bergeben
71   werden:
72   - der zugeh�rige DefKnoten, damit ggf. noch Variablen reserviert werden
73     k�nnen (genauer: die Busy-Variable).
74   - Dateiname und Zeilennummer, damit der Code sch�nere Fehlermeldungen
75     ausgeben kann.
76   Damit ich das aber nicht jedes Mal eintippen muss, hier ein paar Macros:
77 */
78#define newCode0(ART) new Code(\
79  gAktDefKnoten, gDateiName, gZeilenNr, ART)
80#define newCode1(ART, X1) new Code(\
81  gAktDefKnoten, gDateiName, gZeilenNr, ART, X1)
82#define newCode2(ART, X1, X2) new Code(\
83  gAktDefKnoten, gDateiName, gZeilenNr, ART, X1, X2)
84#define newCode3(ART, X1, X2, X3) new Code(\
85  gAktDefKnoten, gDateiName, gZeilenNr, ART, X1, X2, X3)
86#define newCode4(ART, X1, X2, X3, X4) new Code(\
87  gAktDefKnoten, gDateiName, gZeilenNr, ART, X1, X2, X3, X4)
88
89
90
91/***********************************************************************/
92
93
94#define VIEL 32767
95
96
97/* PBEGIN_TRY und PEND_TRY() fangen Fehler ab und geben sie aus, damit
98   weitergeparst werden kann und mehrere Fehler gleichzeitig ausgegeben
99   werden k�nnen. Sie werden in fehler.h definiert. */
100
101
102#define YYDEBUG 1
103
104
105/* Bug in Bison? Er scheint den Stack nicht automatisch vergr��ern zu wollen,
106   wenn er voll ist. Es sieht so aus, als h�tte er angst, dass da c++-Variablen
107   vorkommen, wo er (wegen constructor und so) nicht einfach so rumalloziieren
108   kann. (Ich wei� nicht, was der LTYPE ist, von dem er nicht festgestellt hat,
109   das er trivial ist.) */
110#define YYLTYPE_IS_TRIVIAL 1
111
112%}
113
114
115
116%union {
117  Code * code;
118  Code * codepaar[2];
119  Str * str;
120  int zahl;
121  int zahlpaar[2];
122  Knoten * knoten;
123  DefKnoten * defknoten;
124  ListenKnoten * listenknoten;
125  WortKnoten * wortknoten;
126  Variable * variable;
127  Ort * ort;
128  Version * version;
129  CodeArt codeart;
130  OrtHaelfte haelfte;
131}
132
133
134
135%pure_parser
136
137%left ';'
138%nonassoc ']'
139%nonassoc IF_PREC
140%nonassoc ELSE_TOK
141%left ','
142%left OR_TOK
143%left AND_TOK
144%left EQ_TOK NE_TOK '<' '>' GE_TOK LE_TOK
145%nonassoc BIS_TOK
146  // x==-3..-2 bedeutet *nicht* (x==-3..)-2
147  // und x==y==2..3 bedeutet nicht (x==y)==2..3, weil das konstant 0 w�re
148  // und willk�rlicher auch nicht x==(y==2)..3
149%nonassoc '!'
150%left '+' '-'
151%nonassoc ':'
152%left '*' '/' '%'
153%left '&' '|' BITSET_ATOK BITUNSET_ATOK
154%nonassoc NEG_PREC
155%nonassoc '.'
156%nonassoc error
157
158%token INCLUDE_TOK
159%token BEGIN_CODE_TOK END_CODE_TOK
160%token SWITCH_TOK IF_TOK BIS_TOK VAR_TOK BUSY_TOK
161%token ADD_TOK SUB_TOK MUL_TOK DIV_TOK MOD_TOK BITSET_TOK BITUNSET_TOK
162%token RND_TOK GGT_TOK BONUS_TOK MESSAGE_TOK SOUND_TOK EXPLODE_TOK VERLIER_TOK
163%token DEFAULT_TOK DA_KIND_TOK
164%token FREMD_TOK BITSET_ATOK BITUNSET_ATOK
165%token <str> REINWORT_TOK WORT_TOK NACHBAR8_TOK NACHBAR6_TOK
166%token <zahl> NULLEINS_TOK ZAHL_TOK HALBZAHL_TOK BUCHSTABE_TOK PFEIL_TOK
167
168%type <codeart> zuweisungs_operator
169%type <zahl> zahl halbzahl vorzeichen_zahl
170%type <str> wort punktwort proc_def_wort var_def_wort versionsmerkmal
171%type <code> code code_1 stern_at buch_stern auswahl_liste set_zeile
172%type <code> ausdruck halbort
173%type <codepaar> intervall
174%type <ort> ort absort_klammerfrei absort_geklammert absort
175%type <ort> relort_klammerfrei relort_geklammert relort
176/*%type <bed> bedingung*/
177%type <haelfte> haelften_spez
178
179%type <zahl> ld_konstante konstante
180%type <zahlpaar> echter_default unechter_default
181%type <knoten> rechts_von_def def_liste_eintrag
182%type <listenknoten> def_liste
183
184%type <version> version versionierung
185
186/* Eigentlich w�re es naheliegend und sch�n, wenn alles einen DefKnoten
187   zur�ckliefern w�rde. Statt dessen wird das �ber die globale Variable
188   gAktDefKnoten gemanaget. Das hat mehrere Gr�nde:
189   - Am Ende muss sowieso das Parse-Ergebnis irgendwo weggepeichert werden,
190     damit man es bekommt.
191   - <<>>-Definitionen m�ssen auf den aktuellen DefKnoten zugreifen k�nnen.
192     Dazu m�sste er sowieso in einer globalen Variable stehen.
193   - Beim Includen soll das neu geparste an einen schon vorhandenen DefKnoten
194     angeh�ngt werden. Das ginge anders auch nicht. */
195/*%type <defknoten> alles*/
196
197%type <variable> variable lokale_variable
198
199/*
200Erklaerung zu den Vorrangsregeln:
201Bei einem Vorrangskonflikt muss entschieden werden zwischen eine Regel
202R anwenden oder ein Token T shiften. Sowohl Regeln alsauch token haben
203Prioritaeten. Dasjenige mit hoeherer Prioritaet (R oder T) wird
204gemacht. Bei gleichstand entscheidet %left oder %right
205
206Beispiel: Stack = "exp exp", gefunden: "(". "exp exp -> exp" und "("
207haben gleiche Prioritaet; wegen right wird "(" geshiftet.
208 */
209
210
211%{
212int yyerror(const char * s);
213int yylex(YYSTYPE * lvalPtr);
214
215/** Wechselt die Lex-Datei tempor�r. Liefert was zur�ck, was an popLex
216    �bergeben werden muss, um wieder zur�ckzuschalten. Throwt evtl.
217    setzdefault wird an den Pfaditerator �bergeben.
218    Wird in lex.ll definiert, weil da die n�tigen Lex-Dinge definiert sind. */
219void * pushLex(const char * na, bool setzdefault = false);
220void popLex(void * merkBuf);
221%}
222
223
224%%
225/*****************************************************************************/
226
227
228/***** Normaler Level-Def-Bereich *****/
229
230
231
232alles:                 { /* Nix zu tun. */ }
233  | alles punktwort version '=' rechts_von_def   {
234
235      PBEGIN_TRY
236        gAktDefKnoten->fuegeEin(*$2, *$3, $5);
237        delete $2;
238        delete $3;
239      PEND_TRY(;);
240    }
241  | alles BEGIN_CODE_TOK code_modus END_CODE_TOK  {
242
243      /* Nix zu tun; die Codes speichern sich von alleine nach
244         gAktDefKnoten */
245    }
246/* Wenn man nach Fehlern sinnvoll weitermachen zu k�nnen glaubt,
247   kann man das hier wieder dekommentieren. Aber wenn man recht hat,
248   ist vielleicht die Produktion "code_zeile: error" ein besserer
249   Kandidat.
250  | alles BEGIN_CODE_TOK error END_CODE_TOK
251*/
252  | alles INCLUDE_TOK punktwort {
253      PBEGIN_TRY
254
255        /* Lex auf neue Datei umschalten */
256	void * merkBuf = pushLex($3->data());
257
258
259        /***** Bison-Aufruf f�r include-Datei *****/
260        /* Hier muss man aufpassen, dass mit allen globalen Variablen
261	   das richtige passiert. Nichts zu tun ist bei:
262	   - gGabFehler (Fehler in include-Datei ist halt auch Fehler)
263	   - gAktDefKnoten (Die Include-Datei speichert ihre Ergebnisse
264	     auch einfach da mit rein.)
265	   */
266
267
268	/* Datei und Zeilennummer zwischenspeichern. */
269	Str merkDat = gDateiName;
270	gDateiName = *$3;
271	int merkZNr = gZeilenNr;
272	gZeilenNr = 1;
273
274	/* Der rekursive Aufruf! Hier! Live! (Die Ergebnisse werden in
275	   gAktDefKnoten eingef�gt.) */
276	if ((yyparse()) && !gGabFehler) {
277	  print_to_stderr("Unknown error during file inclusion!\n");
278	  gGabFehler = true;
279	}
280
281	gDateiName = merkDat;
282	gZeilenNr = merkZNr;
283
284	/* Lex auf alte Datei zur�ckschalten */
285	popLex(merkBuf);
286
287      PEND_TRY(;);
288    }
289;
290
291
292
293
294versionsmerkmal:
295    wort { $$ = $1; }
296  | zahl { $$ = new Str(_sprintf("%d",$1)); }   /* Etwas h��lich, aber wir
297                                                        brauchen's f�r die
298                                                        Versionen 1 und 2. */
299  ;
300
301versionierung:
302    versionsmerkmal                   {
303      $$ = new Version();
304      $$->nochEinMerkmal(*$1);
305      delete $1;
306    }
307  | versionsmerkmal ',' versionierung {
308      $$ = $3;
309      $$->nochEinMerkmal(*$1);
310      delete $1;
311    }
312;
313
314version:
315                          { $$ = new Version(); }
316  | '[' versionierung ']' { $$ = $2; }
317;
318
319ld_konstante:
320    vorzeichen_zahl    { $$ = $1; }
321  | '<' konstante '>'  { $$ = $2; }
322;
323
324rechts_von_def: '{' {
325      /* OK, hier wird ein neuer Defknoten er�ffnet. Der alte wird
326         auf dem Bison-Stack zwischengespeichert... */
327      DefKnoten * merk = gAktDefKnoten;
328      /* Neuen Defknoten erzeugen, mit dem alten als Vater */
329      gAktDefKnoten = new DefKnoten(gDateiName, gZeilenNr, merk);
330      $<defknoten>$ = merk;
331
332                    } alles '}'  {
333
334      /* Jetzt wurde gAktDefKnoten mit Inhalt gef�llt, den wir
335         zur�ckliefern */
336      $$ = gAktDefKnoten;
337      /* POP DefKnoten */
338      gAktDefKnoten = $<defknoten>2;
339    }
340  | def_liste                   { $$ = $1; }
341;
342
343def_liste: def_liste_eintrag    {
344      $$ = new ListenKnoten(gDateiName, gZeilenNr);
345      $$->fuegeEin($1);
346    }
347  | def_liste ',' def_liste_eintrag   {
348      $$ = $1;
349      $$->fuegeEin($3);
350    }
351;
352
353def_liste_eintrag: punktwort   {
354      $$ = new WortKnoten(gDateiName, gZeilenNr, *$1); delete $1;
355    }
356  | ld_konstante          {
357      $$ = new ZahlKnoten(gDateiName, gZeilenNr, $1);
358    }
359  | punktwort '*' ld_konstante {
360      $$ = new VielfachheitKnoten(gDateiName, gZeilenNr, *$1, $3); delete $1;
361    }
362;
363
364konstante:
365    zahl                          { $$ = $1; }
366  | wort                          {
367      Knoten * def = gAktDefKnoten->getVerwandten(*$1, ld->mVersion, false);
368      const DatenKnoten * datum = 0;
369      switch (def->type()) {
370        case type_DatenKnoten:
371          datum=(const DatenKnoten *) def;
372          break;
373        case type_ListenKnoten:
374          datum=((ListenKnoten*) def)->getEinzigesDatum();
375          break;
376        default: throw Fehler("%s not a number",$1->data());
377      }
378      $$ = datum->assert_datatype(type_ZahlDatum)->getZahl();
379      delete $1;
380    }
381  | '(' konstante ')'             { $$ = $2; }
382  | '-' konstante %prec NEG_PREC  { $$ = -$2; }
383  | konstante '+' konstante       { $$ = $1 + $3; }
384  | konstante '-' konstante       { $$ = $1 - $3; }
385  | konstante '*' konstante       { $$ = $1 * $3; }
386  | konstante '/' konstante       { $$ = divv($1,$3); }
387  | konstante '%' konstante       { $$ = modd($1,$3); }
388;
389
390
391
392
393/***** Bereich in << >> *****/
394
395
396code_modus:
397  | code_modus code_zeile
398;
399
400code_zeile: proc_def_wort version '=' code_1 ';'    {
401      gAktDefKnoten->speicherDefinition(namespace_prozedur, *$1,
402                                        *$2, $4);
403      delete $1; delete $2;
404    }
405  | VAR_TOK var_liste ';'
406  | DEFAULT_TOK default_liste ';'
407/* Wenn man nach Fehlern sinnvoll weitermachen zu k�nnen glaubt,
408   kann man das hier wieder dekommentieren.
409  | error ';'
410*/
411;
412
413
414/* Der nachfolgende Zustand existiert nur, um die Fehlermeldung
415   zu verbessern. */
416proc_def_wort: punktwort    { $$ = $1; }
417    | BUCHSTABE_TOK {
418      /* Wie gibt man einen Fehler m�glichst umst�ndlich aus?
419         (Aber so, dass er genauso aussieht wie die anderen Fehler. */
420      PBEGIN_TRY
421        throw Fehler("%s","Procedure names can't be single letters.");
422      PEND_TRY($$ = new Str());
423    }
424;
425
426
427var_liste: var_def
428  | var_liste ',' var_def
429;
430
431echter_default:
432    konstante                 { $$[0]=$1; $$[1]=da_init; }
433  | konstante ':' DA_KIND_TOK { $$[0]=$1; $$[1]=da_kind; }
434  ;
435
436unechter_default:
437                       { $$[0]=0;  $$[1]=da_init; }
438  | '=' echter_default { $$[0]=$2[0];  $$[1]=$2[1];}
439  ;
440
441var_def:
442    var_def_wort version unechter_default    {
443      PBEGIN_TRY
444        gAktDefKnoten->neueVarDefinition(*$1, *$2, $3[0], $3[1]);
445        delete $1; delete $2;
446      PEND_TRY(;)
447    }
448  ;
449
450/* Der nachfolgende Zustand existiert nur, um die Fehlermeldung
451   zu verbessern. */
452var_def_wort: wort    { $$ = $1; }
453    | BUCHSTABE_TOK {
454      /* Wie gibt man einen Fehler m�glichst umst�ndlich aus?
455         (Aber so, dass er genauso aussieht wie die anderen Fehler. */
456      PBEGIN_TRY
457        throw Fehler("%s","Variable names can't be single letters.");
458      PEND_TRY($$ = new Str());
459    }
460;
461
462
463default_liste:
464    default_def
465  | default_liste ',' default_def
466  ;
467
468default_def:
469    var_def_wort version '=' echter_default  {
470      PBEGIN_TRY
471        gAktDefKnoten->neuerDefault(
472          ((VarDefinition*)
473              (gAktDefKnoten->getDefinition(namespace_variable,*$1,*$2,false)))
474            -> mNummer,
475          $4[0], $4[1]);
476        delete $1; delete $2;
477      PEND_TRY(;)
478    }
479  ;
480
481
482
483/***** Code *****/
484/* Bemerkung: newCode*() (siehe oben) ruft new Code auf und �bergibt
485   noch ein paar Parameter, die jedes Mal �bergeben werden m�ssen
486   (gAktDefKnoten, gDateiName, gZeilenNr) */
487
488code: code_1              { $$ = $1; }
489  | code_1 ';' code       { $$ = newCode2(stapel_code, $1, $3);}
490;
491
492/* Code_1 darf kein Semikolon enthalten. ({} verwenden.) */
493code_1: SWITCH_TOK '{' auswahl_liste '}' { $$ = $3; }
494  | IF_TOK ausdruck PFEIL_TOK code_1   %prec IF_PREC {
495      $$ = newCode4(bedingung_code, $2, $4,
496                     newCode0(nop_code),
497                     $3 + 2 * ohne_merk_pfeil);
498    }
499  | IF_TOK ausdruck PFEIL_TOK code_1 ELSE_TOK code_1   %prec IF_PREC {
500      if ($3==ohne_merk_pfeil)
501        $$ = newCode4(bedingung_code, $2, $4,
502                      $6,
503                      3*ohne_merk_pfeil);
504      else
505	/* TRANSLATORS: The text in the literal strings should not be translated. */
506        throw Fehler("%s","Please specify \"else ->\" or \"else =>\"");
507    }
508  | IF_TOK ausdruck PFEIL_TOK code_1 ELSE_TOK PFEIL_TOK code_1  %prec IF_PREC {
509      /* Nach else kann, muss aber kein Pfeil stehen.
510         (Kein Pfeil will man vermutlich, wenn dann gleich das
511	 n�chste if kommt.) */
512      $$ = newCode4(bedingung_code, $2, $4,
513                     $7,
514                     $3 + 2 * $6);
515    }
516  | '{' code '}'          { $$ = $2; }
517  | code_1 ',' code_1     { $$ = newCode2(folge_code, $1, $3);}
518  | zahl                  { $$ = newCode1(zahl_code, $1); }
519  | buch_stern            { $$ = $1; }
520  | zahl buch_stern       {
521      $$ = newCode2(stapel_code, newCode1(zahl_code, $1), $2);
522    }
523  | punktwort                  {
524      PBEGIN_TRY
525        /* Kopie erzeugen...) */
526        $$ = new Code(gAktDefKnoten, * (Code*)
527               gAktDefKnoten->getDefinition(namespace_prozedur, *$1,
528                                            ld->mVersion, false), true);
529        delete $1;
530      PEND_TRY($$ = newCode0(undefiniert_code))
531    }
532  | '&' punktwort              {
533      PBEGIN_TRY
534        /* Kopie erzeugen...) */
535        $$ = newCode1(weiterleit_code,
536	      new Code(gAktDefKnoten, * (Code*)
537                gAktDefKnoten->getDefinition(namespace_prozedur, *$2,
538                                             ld->mVersion, false), false));
539        delete $2;
540      PEND_TRY($$ = newCode0(undefiniert_code))
541    }
542  |                       { $$ = newCode0(nop_code); }
543  | set_zeile             { $$ = $1; }
544  | '[' lokale_variable '=' ausdruck ']' code_1   {
545      PBEGIN_TRY
546        if ($2->istKonstante())
547          throw Fehler(_sprintf("%s is a constant. (Variable expected.)",
548                     $2->getName().data()));
549        $$ = newCode3(push_code, $4, $6, $2);
550
551      PEND_TRY($$ = newCode0(undefiniert_code))
552    }
553  | BUSY_TOK              { $$ = newCode0(busy_code); }
554  | BONUS_TOK '(' ausdruck ')'  {
555      $$ = newCode1(bonus_code, $3);
556    }
557  | MESSAGE_TOK '(' punktwort ')' {
558      $$ = newCode1(message_code, _($3->data()));
559      delete $3;
560    }
561  | SOUND_TOK '(' punktwort ')' {
562      $$ = newCode1(sound_code, Sound::ladSample(*$3));
563      delete $3;
564    }
565  | VERLIER_TOK {
566      $$ = newCode0(verlier_code);
567    }
568  | EXPLODE_TOK {
569      $$ = newCode0(explode_code);
570    }
571;
572
573
574set_zeile: variable zuweisungs_operator ausdruck  {
575      PBEGIN_TRY
576        if ($1->istKonstante())
577          throw Fehler(_sprintf("%s is a constant. (Variable expected.)",
578                     $1->getName().data()));
579        $$ = newCode2($2, $3, $1);
580      PEND_TRY($$ = newCode0(undefiniert_code))
581    }
582;
583
584zuweisungs_operator: '=' { $$ = set_code; }
585  | ADD_TOK              { $$ = add_code; }
586  | SUB_TOK              { $$ = sub_code; }
587  | MUL_TOK              { $$ = mul_code; }
588  | DIV_TOK              { $$ = div_code; }
589  | MOD_TOK              { $$ = mod_code; }
590  | BITSET_TOK           { $$ = bitset_code; }
591  | BITUNSET_TOK         { $$ = bitunset_code; }
592;
593
594/* * oder *@(x,y) oder @(x,y)* */
595stern_at:
596    '*'       { $$ = newCode0(mal_code); }
597  | '*' ort   { $$ = newCode2(mal_code_fremd, $2, 1); }
598  | ort '*'   { $$ = newCode2(mal_code_fremd, $1, -1); }
599;
600
601/* Buchtabe oder Buchstabe* oder *; und evtl. @(bla, blub) */
602buch_stern: BUCHSTABE_TOK { $$ = newCode1(buchstabe_code, $1); }
603  | BUCHSTABE_TOK stern_at    {
604      $$ = newCode2(stapel_code, newCode1(buchstabe_code, $1),
605                     $2);
606    }
607  | stern_at                   { $$ = $1; }
608;
609
610
611
612auswahl_liste: ausdruck PFEIL_TOK code_1 ';'   {
613      $$ = newCode4(bedingung_code, $1, $3,
614                     newCode0(nop_code),
615                     $2 + 2 * ohne_merk_pfeil);
616    }
617  | ausdruck PFEIL_TOK code_1 ';' PFEIL_TOK code_1 ';'     {
618      $$ = newCode4(bedingung_code, $1, $3,
619                     $6,
620                     $2 + 2 * $5);
621    }
622  | ausdruck PFEIL_TOK code_1 ';' auswahl_liste     {
623      $$ = newCode4(bedingung_code, $1, $3,
624                     $5,
625                     $2 + 2 * mit_merk_pfeil);
626    }
627;
628
629
630
631
632punktwort:
633    wort                         { $$ = $1; }
634  | punktwort '.' wort           {
635      *$1 += '.';  *$1 += *$3;  $$ = $1;
636      delete $3;
637    }
638  | punktwort '.' BUCHSTABE_TOK  {
639      *$1 += '.';  *$1 += ($3>=26 ? 'a'+$3-26 : 'A'+$3);  $$ = $1;
640    }
641;
642
643
644wort: WORT_TOK     { $$ = $1; }
645  | REINWORT_TOK   { $$ = $1; }
646;
647
648
649
650/***** Ausdr�cke *****/
651
652ausdruck: variable            {
653      if ($1->istKonstante()) {
654        /* Wenn die Variable in Wirklichkeit eine Konstante ist,
655           dann gleich die Konstante einsetzen. */
656        $$ = newCode1(zahl_acode, $1->getDefaultWert());
657        delete $1;
658      } else
659        $$ = newCode1(variable_acode, $1);
660    }
661  | zahl                      { $$ = newCode1(zahl_acode, $1); }
662  | '(' ausdruck ')'          { $$ = $2; }
663  | NACHBAR8_TOK              {
664      $$ = newNachbarCode(gAktDefKnoten, gDateiName, gZeilenNr, $1);
665    }
666  | NACHBAR6_TOK              {
667      $$ = newNachbarCode(gAktDefKnoten, gDateiName, gZeilenNr, $1);
668    }
669/*  | wort '~' NACHBAR_TOK      {
670      print_to_stderr("~ geht noch nicht!!!");
671      $$ = newNachbarCode(gAktDefKnoten, $3);
672    }*/
673  | ausdruck ':' ausdruck       { $$ = newCode2(manchmal_acode, $1, $3);}
674  | ausdruck '+' ausdruck       { $$ = newCode2(add_acode, $1, $3);}
675  | '-' ausdruck %prec NEG_PREC { $$ = newCode1(neg_acode, $2);}
676  | ausdruck '-' ausdruck       { $$ = newCode2(sub_acode, $1, $3);}
677  | ausdruck '*' ausdruck       { $$ = newCode2(mul_acode, $1, $3);}
678  | ausdruck '/' ausdruck       { $$ = newCode2(div_acode, $1, $3);}
679  | ausdruck '%' ausdruck       { $$ = newCode2(mod_acode, $1, $3);}
680  | ausdruck BITSET_ATOK ausdruck   { $$ = newCode2(bitset_acode, $1, $3);}
681  | ausdruck BITUNSET_ATOK ausdruck { $$ = newCode2(bitunset_acode, $1, $3);}
682  | ausdruck '.' ausdruck       { $$ = newCode2(bittest_acode, $1, $3);}
683  | ausdruck EQ_TOK ausdruck    { $$ = newCode2(eq_acode, $1, $3);}
684  | ausdruck NE_TOK ausdruck    { $$ = newCode2(ne_acode, $1, $3);}
685  | ausdruck GE_TOK ausdruck    { $$ = newCode2(ge_acode, $1, $3);}
686  | ausdruck LE_TOK ausdruck    { $$ = newCode2(le_acode, $1, $3);}
687  | ausdruck '>' ausdruck       { $$ = newCode2(gt_acode, $1, $3);}
688  | ausdruck '<' ausdruck       { $$ = newCode2(lt_acode, $1, $3);}
689  | ausdruck '&' ausdruck       { $$ = newCode2(bitand_acode, $1, $3);}
690  | ausdruck '|' ausdruck       { $$ = newCode2(bitor_acode, $1, $3);}
691  | '!' ausdruck                { $$ = newCode1(not_acode, $2);}
692  | ausdruck AND_TOK ausdruck   { $$ = newCode2(und_acode, $1, $3);}
693  | ausdruck OR_TOK ausdruck    { $$ = newCode2(oder_acode, $1, $3);}
694  | ausdruck EQ_TOK intervall {
695      $$ = newCode3(intervall_acode, $1, $3[0], $3[1]);
696    }
697  | RND_TOK '(' ausdruck ')' {
698      $$ = newCode1(rnd_acode, $3);
699    }
700  | GGT_TOK '(' ausdruck ',' ausdruck ')' {
701      $$ = newCode2(ggt_acode, $3, $5);
702    }
703;
704
705
706intervall:
707    ausdruck BIS_TOK { $$[0]=$1; $$[1]=newCode1(zahl_acode, VIEL); }
708  | BIS_TOK ausdruck { $$[0]=newCode1(zahl_acode, -VIEL); $$[1]=$2; }
709  | ausdruck BIS_TOK ausdruck { $$[0]=$1; $$[1]=$3; }
710  ;
711
712
713lokale_variable:  wort       {
714      PBEGIN_TRY
715        $$ = new Variable(//gDateiName, gZeilenNr,
716               (VarDefinition*) gAktDefKnoten->
717                     getDefinition(namespace_variable, *$1,
718                                   ld->mVersion, false),
719               0
720             );
721      PEND_TRY($$ = new Variable())
722      delete $1;
723    }
724    | BUCHSTABE_TOK {
725      /* Wie gibt man einen Fehler m�glichst umst�ndlich aus?
726         (Aber so, dass er genauso aussieht wie die anderen Fehler. */
727      PBEGIN_TRY
728        throw Fehler("%s","Variable names can't be single letters.");
729      PEND_TRY($$ = new Variable());
730    }
731;
732
733variable:
734    lokale_variable   { $$ = $1; }
735  | wort ort   {
736      PBEGIN_TRY
737        $$ = new Variable(//gDateiName, gZeilenNr,
738               (VarDefinition*) gAktDefKnoten->
739                     getDefinition(namespace_variable, *$1,
740                                   ld->mVersion, false),
741               $2);
742      PEND_TRY($$ = new Variable())
743      delete $1;
744    }
745;
746
747halbort:
748    ausdruck   { $$ = $1; }
749  | halbzahl   { $$ = newCode1(zahl_acode, $1); }
750;
751
752haelften_spez:
753    '=' { $$ = haelfte_hier; }
754  | '!' { $$ = haelfte_drueben; }
755  | '<' { $$ = haelfte_links; }
756  | '>' { $$ = haelfte_rechts; }
757;
758
759absort_klammerfrei:
760                  { $$ = new Ort(absort_semiglobal); }
761  | NULLEINS_TOK  { $$ = new Ort(absort_fall, newCode1(zahl_acode, $1)); }
762;
763
764absort_geklammert:
765                         { $$ = new Ort(absort_semiglobal); }
766  | ausdruck             { $$ = new Ort(absort_fall, $1); }
767  | halbort ',' halbort  { $$ = new Ort(absort_feld, $1, $3); }
768;
769
770absort:
771    absort_klammerfrei                           { $$ = $1; }
772  | '(' absort_geklammert ')'                    { $$ = $2; }
773  | '(' absort_geklammert ';' haelften_spez ')'  {
774      $2->setzeHaelfte($4);
775      $$ = $2;
776    }
777;
778
779relort_klammerfrei:
780                  { $$ = new Ort(absort_global); }
781  | NULLEINS_TOK  { $$ = new Ort(newCode1(zahl_acode, $1)); }
782;
783
784relort_geklammert:
785                         { $$ = new Ort(absort_global); }
786  | ausdruck             { $$ = new Ort($1); }
787  | halbort ',' halbort  { $$ = new Ort($1, $3); }
788;
789
790relort:
791    relort_klammerfrei                           { $$ = $1; }
792  | '(' relort_geklammert ')'                    { $$ = $2; }
793  | '(' relort_geklammert ';' haelften_spez ')'  {
794      $2->setzeHaelfte($4);
795      $$ = $2;
796    }
797;
798
799ort:
800    '@' relort         { $$ = $2; }
801  | FREMD_TOK absort   { $$ = $2; }
802;
803
804
805
806
807
808zahl: ZAHL_TOK      { $$ = $1; }
809   | NULLEINS_TOK   { $$ = $1; }
810;
811
812/* Bei relativen Koordinaten f�r Variablenangaben d�rfen in Y-Richtung
813   auch Halbganze Zahlen angegeben werden... (f�r Hex-Level) */
814halbzahl:
815     HALBZAHL_TOK                      {
816       /* Halbzahlen sollen intern aufgerundet gespeichert werden... */
817       $$ = $1 + 1;
818     }
819   | '-' HALBZAHL_TOK                  { $$ = -$2; }
820;
821
822vorzeichen_zahl: zahl           { $$ = $1; }
823   | '-' zahl                   { $$ = -$2; }
824;
825
826
827%%
828/*****************************************************************************/
829
830
831
832
833
834
835extern FILE * yyin;
836int yyparse();
837//void initLex();
838
839
840
841int yyerror (const char * s)  /* Called by yyparse on error */
842{
843  PBEGIN_TRY
844   throw Fehler(Str(s));
845  PEND_TRY(;)
846  return 0;
847}
848
849
850/* �ffnet die Datei mit dem angegebenen Namen und parst sie. Das
851   Ergebnis wird in den Defknoten erg geschrieben. */
852/** Komplettbeschreibung vom Parse-Vorgang siehe leveldaten.h */
853void parse(const Str & name, DefKnoten * erg) {
854
855  /* Datei �ffnen, Lex initialisieren. Eigentlich br�uchte man
856     kein pushLex und popLex ganz au�en; aber es ist irgendwie
857     sauberer. Vor allem ist dann sicher, dass ein Fehler in einem
858     fr�heren Parsen keine Auswirkungen auf ein sp�teres Parsen
859     hat.
860     true = Default-Pfad merken f�r die Includes. (wird an den
861            Pfaditerator weitergegeben.) */
862  void * merkBuf = pushLex(name.data(), true);
863
864  gDateiName = name;
865  gZeilenNr = 1;
866  gGabFehler = false;  /* Wenn es denn mal ein bison-Fehler-recovery gibt,
867                         sollte gGabFehler dort auf true gesetzt werden */
868
869  /* Das Parse-Ergebnis soll in den Knoten erg geschrieben werden. */
870  gAktDefKnoten = erg;
871
872  /* Hier findet das Parsen statt. Man beachte: Um Flex und Bison nicht
873     zu verwirren, kann yyparse() nicht mit throw verlassen werden.
874     Deshalb brauchen wir nix zu catchen, um alles wieder aufr�umen zu
875     k�nnen. */
876  int perg = yyparse();
877
878  /* Datei schlie�en, lex zur�cksetzen. */
879  popLex(merkBuf);
880
881
882  /* Hier werden vermutlich mehr Bedingungen getestet als n�tig. */
883  if (perg || gGabFehler)
884    throw Fehler("%s","There have been errors parsing the level description files.");
885
886}
887
888