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