/************************************************************************
-------------------
begin : Fri Dec 8 2000
copyright : (C) 2000 by Waldemar Baraldi
email : baraldi@lacasilla.com.ar
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
%{
#include "level.h"
#include "pipe.h"
#include "elbowupleft.h"
#include "elbowupright.h"
#include "elbowdownleft.h"
#include "elbowdownright.h"
#include "vertical.h"
#include "horizontal.h"
#include "verticalbowl.h"
#include "horizontalbowl.h"
#include "cross.h"
#include "entry.h"
#include "exit.h"
#define NUMBER 1
#define LEVEL 2
#define SPEED 3
#define GRAPH_DIR 4
#define PIPENIGHTDREAMS 5
#define ENTRY 6
#define EXIT 7
#define ROW 8
#define COLUMN 9
#define SIDE 10
#define O_BLOCK 11
#define C_BLOCK 12
#define DOUBLE_COUTE 13
#define EQUAL 15
#define SEMICOLON 16
#define EOFILE 17
#define NORTH 18
#define SOUTH 19
#define WEST 20
#define EAST 21
#define STRING 22
#define START_DELAY 23
#define RESTRICT_COEF 24
#define FIXED_COEF 25
#define PIPE 26
#define REQUIRED 150
#define TYPE 27
// Possible values for TYPE
#define ELBOW_NW 28
#define ELBOW_NE 29
#define ELBOW_SW 30
#define ELBOW_SE 31
#define BOWL_H 32
#define BOWL_V 33
#define HORIZONTAL 34
#define VERTICAL 35
#define CROSS 36
#define RESTRICTED_OUTPUT 37
#define BONUS 38
// Possible values for BONUS
#define NORMAL 40
#define SUPER 41
#define ULTRA 42
#define HYPER 43
#define EXTRA_LIFE 44
#define EXTRA_TIME 45
#define FIXED 46
#define TRUE 47
#define FALSE 48
#define BACKGROUND 49
//Posibles valores para background
#define WALLPAPER 50
#define MOSAIC 51
#define INVALID 100
int nline;
%}
%option noyywrap
%option nounput
DIGIT [0-9]
SEP [ \t]+
%%
#.+\n nline++;
\n nline++;
{DIGIT}+ return NUMBER;
level return LEVEL;
speed return SPEED;
entry return ENTRY;
exit return EXIT;
row return ROW;
column return COLUMN;
side return SIDE;
graph_dir return GRAPH_DIR;
pipenightdreams return PIPENIGHTDREAMS;
start_delay return START_DELAY;
restrict_coef return RESTRICT_COEF;
fixed_coef return FIXED_COEF;
= return EQUAL;
\{ return O_BLOCK;
\} return C_BLOCK;
\" return DOUBLE_COUTE;
; return SEMICOLON;
<<EOF>> return EOF;
north return NORTH;
south return SOUTH;
west return WEST;
east return EAST;
pipe return PIPE;
type return TYPE;
elbow_nw return ELBOW_NW;
elbow_ne return ELBOW_NE;
elbow_sw return ELBOW_SW;
elbow_se return ELBOW_SE;
bowl_h return BOWL_H;
bowl_v return BOWL_V;
horizontal return HORIZONTAL;
vertical return VERTICAL;
cross return CROSS;
restricted_output return RESTRICTED_OUTPUT;
bonus return BONUS;
normal return NORMAL;
super return SUPER;
ultra return ULTRA;
hyper return HYPER;
life return EXTRA_LIFE;
time return EXTRA_TIME;
fixed return FIXED;
background return BACKGROUND;
wallpaper return WALLPAPER;
mosaic return MOSAIC;
required return REQUIRED;
yes return TRUE;
true return TRUE;
no return FALSE;
false return FALSE;
\".+\" return STRING;
{SEP}
. return INVALID;
%%
Level::Level(){
level_number=0;
error=false;
entry_ready=false;
npipes=0;
start_delay=-1;
restrict_coef=-1;
fixed_coef=-1;
speed=1;
required=0;
graph_dirs=NULL;
background=MosaicBackground;
}
Level::~Level(){
if (graph_dirs){
graph_dirs->empty(true);
delete graph_dirs;
}
}
void Level::printError(Str * s){
error=true;
printf("Level error:%i:%s\n", nline, s->get());
delete s;
}
CardinalPoint Level::sideAssignment(){
int aux_token;
if (yylex()==EQUAL){
aux_token=yylex();
token=yylex();
switch (aux_token){
case NORTH: return North;
case SOUTH: return South;
case WEST: return West;
case EAST: return East;
default: printError(new Str("Invalid side"));
}
}else
printError(new Str("'=' expected"));
return Void;
}
int Level::numberAssignment(){
int aux;
if (yylex()==EQUAL)
if (yylex()==NUMBER){
aux=atoi(yytext);
token=yylex();
return aux;
}else printError(new Str("number expected"));
else printError(new Str("'=' expected"));
return 0;
}
Str * Level::stringAssignment(){
Str * s;
if (yylex()==EQUAL)
if (yylex()==STRING){
s=new Str(yytext);
token=yylex();
return s;
}else printError(new Str("string expected"));
else printError(new Str("'=' expected"));
return NULL;
}
Level::PipeType Level::pipeTypeAssignment(){
int aux_token;
if (yylex()==EQUAL){
aux_token=yylex();
token=yylex();
switch (aux_token){
case ELBOW_NW : return ElbowNW;
case ELBOW_NE : return ElbowNE;
case ELBOW_SW : return ElbowSW;
case ELBOW_SE : return ElbowSE;
case BOWL_H : return BowlH;
case BOWL_V : return BowlV;
case VERTICAL : return Vert;
case HORIZONTAL: return Horiz;
case CROSS : return CrossPipe;
default:{
printError(new Str("pipe type not valid"));
}
}
}else printError(new Str("'=' expected"));
return ElbowNW;
}
Bonus Level::bonusAssignment(){
int aux_token;
if (yylex()==EQUAL){
aux_token=yylex();
token=yylex();
switch (aux_token){
case NORMAL : return NormalBonus;
case SUPER : return SuperBonus;
case ULTRA : return UltraBonus;
case HYPER : return HyperBonus;
case EXTRA_LIFE: return LifeBonus;
case EXTRA_TIME: return TimeBonus;
default:{
printError(new Str("bonus type not valid"));
break;
}
}
}else printError(new Str("'=' expected"));
return NormalBonus;
}
bool Level::boolAssignment(){
bool aux;
if (yylex()==EQUAL){
switch (yylex()){
case TRUE : {aux=true;break;}
case FALSE : {aux=false;break;}
default:{
printError(new Str("not boolean type"));
break;
}
}
token=yylex();
return aux;
}else printError(new Str("'=' expected"));
return false;
}
BackgroundType Level::backgroundAssignment(){
int aux_token;
if (yylex()==EQUAL){
aux_token=yylex();
token=yylex();
switch (aux_token){
case WALLPAPER : return WallpaperBackground;
case MOSAIC : return MosaicBackground;
default:break;
}
}else printError(new Str("'=' expected"));
return MosaicBackground;
}
Entry * Level::getEntry(int& row, int& column){
Entry * entry= new Entry(pipetable[0].restricted_output1);
row=pipetable[0].row;
column=pipetable[0].column;
return entry;
}
Exit * Level::getExit(int& row, int& column){
Exit * exit= new Exit(pipetable[1].restricted_output1);
row=pipetable[1].row;
column=pipetable[1].column;
return exit;
}
int Level::getFixedCoef(){
return fixed_coef;
}
int Level::getRestrictionCoef(){
return restrict_coef;
}
int Level::getStartDelay(){
return start_delay;
}
int Level::getSpeed(){
return speed;
}
int Level::getRequired(){
return required;
}
BackgroundType Level::getBackgroundType(){
return background;
}
List * Level::getGraphDirs(){
List * list=new List();
Index * ind=graph_dirs->getFirst();
while (!graph_dirs->isEnd(ind)){
list->insert(list->getEnd(), new Str((Str*)(graph_dirs->getObject(ind))));
ind=graph_dirs->getNext(ind);
}
return list;
}
int Level::getPipeIndex(){
return 2;
}
Pipe * Level::getPipe(int& i, int& row, int& column){
Pipe * pipe;
if (i < npipes && i > 1){
switch (pipetable[i].type){
case ElbowNW:{
pipe=new ElbowUpLeft();
break;
}
case ElbowNE:{
pipe=new ElbowUpRight();
break;
}
case ElbowSW:{
pipe=new ElbowDownLeft();
break;
}
case ElbowSE:{
pipe=new ElbowDownRight();
break;
}
case Vert:{
pipe=new Vertical();
break;
}
case Horiz:{
pipe=new Horizontal();
break;
}
case BowlH:{
pipe=new HorizontalBowl();
break;
}
case BowlV:{
pipe=new VerticalBowl();
break;
}
case CrossPipe:{
pipe=new Cross();
break;
}
}
pipe->setBonus(pipetable[i].bonus);
if (pipetable[i].restricted_output1 != Void)
pipe->restrictAsOutput(pipetable[i].restricted_output1);
if (pipetable[i].restricted_output2 != Void)
pipe->restrictAsOutput(pipetable[i].restricted_output2);
pipe->setFixed(pipetable[i].fixed);
row=pipetable[i].row;
column=pipetable[i].column;
i++;
return pipe;
}
return NULL;
}
void Level::ee(){
int row=0, column=0;
CardinalPoint con=North;
int aux_token=token;
if (token==ENTRY || token==EXIT){
if (yylex()==O_BLOCK){
token=yylex();
while (token!=C_BLOCK && !error){
switch (token){
case ROW:{
row=numberAssignment();
break;
}
case COLUMN:{
column=numberAssignment();
break;
}
case SIDE:{
con=sideAssignment();
break;
}
default:{
if (aux_token==ENTRY)
printError(new Str("invalid word in entry structure"));
else
printError(new Str("invalid word in exit structure"));
}
}
}
if (!error) {
token=yylex();
if (aux_token==ENTRY){
pipetable[0].row=row;
pipetable[0].column=column;
pipetable[0].restricted_output1=con;
entry_ready=true;
}else{
pipetable[1].row=row;
pipetable[1].column=column;
pipetable[1].restricted_output1=con;
exit_ready=true;
}
}
}else printError(new Str("'{' expected"));
}else printError(new Str("'entry' or 'exit' expected"));
}
void Level::pipe(){
pipetable[npipes].row=0;
pipetable[npipes].column=0;
pipetable[npipes].type=ElbowNW;
pipetable[npipes].restricted_output1=Void;
pipetable[npipes].restricted_output2=Void;
pipetable[npipes].bonus=NormalBonus;
pipetable[npipes].fixed=false;
if (token==PIPE){
if (yylex()==O_BLOCK){
token=yylex();
while (token!=C_BLOCK && !error){
switch (token){
case ROW:{
pipetable[npipes].row=numberAssignment();
break;
}
case COLUMN:{
pipetable[npipes].column=numberAssignment();
break;
}
case TYPE:{
pipetable[npipes].type=pipeTypeAssignment();
break;
}
case RESTRICTED_OUTPUT:{
if (pipetable[npipes].restricted_output1!=Void){
if (pipetable[npipes].restricted_output2!=Void)
pipetable[npipes].restricted_output1=pipetable[npipes].restricted_output2;
pipetable[npipes].restricted_output2=sideAssignment();
}else pipetable[npipes].restricted_output1=sideAssignment();
break;
}
case BONUS:{
pipetable[npipes].bonus=bonusAssignment();
break;
}
case FIXED:{
pipetable[npipes].fixed=boolAssignment();
break;
}
default:printError(new Str("invalid word in pipe structure"));
}
}
npipes++;
token=yylex();
}else printError(new Str("'{' expected"));
}else printError(new Str("'pipe' expected"));
}
void Level::level(){
Str * s;
/** Default values for a level*/
entry_ready=false;
exit_ready=false;
level_number=0;
error=false;
npipes=2;
start_delay=0;
restrict_coef=0;
fixed_coef=0;
speed=1;
if (graph_dirs) graph_dirs->empty(true);
else graph_dirs=new List();
pipetable[0].row=0;
pipetable[0].column=0;
pipetable[0].restricted_output1=East;
pipetable[1].row=0;
pipetable[1].column=1;
pipetable[1].restricted_output1=West;
if ((token=yylex())==PIPENIGHTDREAMS){
if (yylex()==O_BLOCK){
token=yylex();
while (token!=C_BLOCK && !error){
switch (token){
case LEVEL:{
level_number=numberAssignment();
break;
}
case SPEED:{
speed=numberAssignment();
break;
}
case GRAPH_DIR:{
s=stringAssignment();
if (!error){
s->crop(1, s->lenght()-1);
graph_dirs->insert(graph_dirs->getEnd(), s);
}
break;
}
case START_DELAY:{
start_delay=numberAssignment();
break;
}
case RESTRICT_COEF:{
restrict_coef=numberAssignment();
break;
}
case FIXED_COEF:{
fixed_coef=numberAssignment();
break;
}
case BACKGROUND:{
background=backgroundAssignment();
break;
}
case REQUIRED:{
required=numberAssignment();
break;
}
case ENTRY:case EXIT:{
ee();
break;
}
case PIPE:{
pipe();
break;
}
default:printError(new Str("invalid word in level structure"));
}
}
if (!entry_ready && !error) printError(new Str("no entry available"));
if (!exit_ready && !error) printError(new Str("no exit available"));
}else printError(new Str("'{' expected"));
}else printError(new Str("'pipenightdreams' not found"));
}
int Level::load(Str * filename){
YY_FLUSH_BUFFER;
nline=1;
if (!(yyin=fopen(filename->get(), "r"))){
delete filename;
return 1;
}
delete filename;
level();
fclose(yyin);
if (error) return -1;
return 0;
}