summaryrefslogtreecommitdiff
path: root/src/parser/parse_ini.yy
blob: 4fb00d80fce8b717564f523bcb81bb72e5035425 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
%{
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <stdint.h>

#include "parser.h"

extern FILE *yyin;
extern int yylineno;
extern char *yytext;
extern int yyparse(gameIni_t *gIni);
 
int yylex();
void yyerror(gameIni_t *gIni, char *s);
void yyassert(int condition, char what[], char why[]);
void callocIfNull(void **ptr, size_t nmemb, size_t size);

%}

%parse-param { gameIni_t *gIni }

%union {char* str; int num; uint32_t uint32; uint32_t *p_uint32;}

%token LEXERROR EOL

%token STYLE NAME SLEM
%token TILES FRAMES ANIM TYPE SOUND
%token BGCOLOR DEBRISCOLOR PARTICLECOLOR
%token XPOS OBJECT TERRAIN STEEL RELEASERATE NUMLEMMINGS NUMTORESCUE TIMELIMIT
%token NUMCLIMBERS NUMFLOATERS NUMBOMBERS NUMBLOCKERS NUMBUILDERS NUMBASHERS NUMMINERS  NUMDIGGERS
%token MAXFALLDISTANCE CODESEED MUSIC LEVEL DIFFICULTY

%token AFF
%token VIR

%token <str> STR
%token <num> INT
%token <uint32> INTHEX

%type <p_uint32> particles

%start ini 
%%

ini: /*epsilon*/
| decl ini
| EOL ini

	/* styles/...ini */
decl: BGCOLOR AFF INTHEX	{ gIni->style.bgColor = $3; }
| DEBRISCOLOR AFF INTHEX	{ gIni->style.debrisColor = $3; }
| PARTICLECOLOR AFF particles	{
					gIni->style.particleColorCount=16;
					gIni->style.particleColor = $3;
				}
| TILES AFF INT			{
				 	yyassert($3>0 && $3<100,"tiles", OUT_OF_BOUNDS);
					gIni->style.tiles = $3;
					//TODO check coherence par  rapport aux fichiers trouvés
				}
| FRAMES INT AFF INT		{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_OBJECT_TYPES, "frame_ index", OUT_OF_BOUNDS);
						yyassert($4>0 && $4<MAX_OBJECT_FRAMES, "frame_ value", OUT_OF_BOUNDS);
						gIni->style.objectCount++;
					} else {
						yyassert($2<gIni->style.objectCount, "frame_ index", OUT_OF_BOUNDS);
						gIni->style.objects[$2].frames = $4;
					}
				}
| ANIM INT AFF INT		{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_OBJECT_TYPES, "anim_ index", OUT_OF_BOUNDS);
						yyassert($4>=0 && $4<=3, "anim_ value", BAD_VALUE);
					} else {
						yyassert($2<gIni->style.objectCount, "anim_ index", OUT_OF_BOUNDS);
						gIni->style.objects[$2].anim = $4;
					}
				}
| TYPE INT AFF INT		{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_OBJECT_TYPES, "type_ index", OUT_OF_BOUNDS);
						yyassert($4==0 || $4==32 || ($4>=3 && $4<=8), "type_ value", BAD_VALUE);
					} else {
						yyassert($2<gIni->style.objectCount, "type_ index", OUT_OF_BOUNDS);
						gIni->style.objects[$2].type = $4;
					}
				}
| SOUND INT AFF INT		{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_OBJECT_TYPES, "sound_ index", OUT_OF_BOUNDS);
						yyassert($4>=-1 && $4<=MAX_SOUNDS_COUNT, "sound_ value", OUT_OF_BOUNDS);
					} else {
						yyassert($2<gIni->style.objectCount, "sound_ index", OUT_OF_BOUNDS);
						gIni->style.objects[$2].sound = $4;
					}
				}

	/*lvl_xxxx.ini*/
| RELEASERATE AFF INT		{
					yyassert($3>=0 && $3<=99, "releaseRate", OUT_OF_BOUNDS);
					gIni->level.initSkills.releaseRate = $3;
				}
| NUMLEMMINGS AFF INT		{
					yyassert($3>=0 && $3<=MAX_NUMLEMMINGS, "numLemmings", OUT_OF_BOUNDS);
					gIni->level.initSkills.numLemmings = $3; }
| NUMTORESCUE AFF INT		{
					yyassert($3>=0 && $3<=99, "numToRescue", OUT_OF_BOUNDS);
					gIni->level.initSkills.numToRescue = $3;
				}
| TIMELIMIT AFF INT		{
					yyassert($3>=0 && $3<=99, "timeLimit", OUT_OF_BOUNDS);
					gIni->level.initSkills.timeLimit = $3;
				}
| NUMCLIMBERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numClimbers", OUT_OF_BOUNDS);
					gIni->level.initSkills.numClimbers = $3;
				}
| NUMFLOATERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numFloaters", OUT_OF_BOUNDS);
					gIni->level.initSkills.numFloaters = $3;
				}
| NUMBOMBERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numBombers", OUT_OF_BOUNDS);
					gIni->level.initSkills.numBombers = $3;
				}
| NUMBLOCKERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numBlockers", OUT_OF_BOUNDS);
					gIni->level.initSkills.numBlockers = $3;
				}
| NUMBUILDERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numBuilders", OUT_OF_BOUNDS);
					gIni->level.initSkills.numBuilders = $3;
				}
| NUMBASHERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numBashers", OUT_OF_BOUNDS);
					gIni->level.initSkills.numBashers = $3;
				}
| NUMMINERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numMiners", OUT_OF_BOUNDS);
					gIni->level.initSkills.numMiners = $3;
				}
| NUMDIGGERS AFF INT		{
					yyassert($3>=0 && $3<=99, "numDiggers", OUT_OF_BOUNDS);
					gIni->level.initSkills.numDiggers = $3;
				}
| XPOS AFF INT			{
					yyassert($3>=0 && $3<=LEVEL_WIDTH, "xPos", OUT_OF_BOUNDS);
					gIni->level.xPos = $3;
				}
| STYLE AFF STR			{ gIni->level.style = $3; }
| SLEM AFF STR			{ gIni->level.superLemming = strcasecmp("true", $3)==0; }
| OBJECT INT AFF INT VIR INT VIR INT VIR INT VIR INT	{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_OBJECTS_COUNT, "object_ index", OUT_OF_BOUNDS);
						yyassert($4>=0 , "object_ id value", OUT_OF_BOUNDS);
						yyassert($6%2==0 , "object_ xpos is odd", BAD_VALUE);
						yyassert($8%2==0 , "object_ ypos is odd", BAD_VALUE);
						yyassert($10==0 || $10==4 || $10==8, "object_ paintMode value", BAD_VALUE);
						yyassert($12==0 || $12==1, "object_ ud value", BAD_VALUE);
						
						gIni->level.objectCount++;
					} else {
						yyassert($2<gIni->level.objectCount, "object_ index", OUT_OF_BOUNDS);
						gIni->level.objects[$2].id = $4;
						gIni->level.objects[$2].xpos = $6;
						gIni->level.objects[$2].ypos = $8;
						gIni->level.objects[$2].paintMode = $10;
						gIni->level.objects[$2].ud = $12;
					}
							}
| TERRAIN INT AFF INT VIR INT VIR INT VIR INT		{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_TERRAINS_COUNT, "terrain_ index", OUT_OF_BOUNDS);
						yyassert($4>=0 , "terrain_ id value", OUT_OF_BOUNDS);
						yyassert($6%2==0 , "terrain_ xpos is odd", BAD_VALUE);
						yyassert($8%2==0 , "terrain_ ypos is odd", BAD_VALUE);
						yyassert($10>=0 && $10<16, "terrain_ modifier value", BAD_VALUE);
						
						gIni->level.terrainCount++;
					} else {
						yyassert($2<gIni->level.terrainCount, "terrain_ index", OUT_OF_BOUNDS);
						gIni->level.terrains[$2].id = $4;
						gIni->level.terrains[$2].xpos = $6;
						gIni->level.terrains[$2].ypos = $8;
						gIni->level.terrains[$2].modifier = $10;
					}
							}
| STEEL INT AFF INT VIR INT VIR INT VIR INT 	{
					if ( gIni->firstPass==1 ) {
						yyassert($2>=0 && $2<MAX_STEELS_COUNT, "steel_ index", OUT_OF_BOUNDS);
						yyassert($4%2==0 , "steel_ xpos is odd", BAD_VALUE);
						yyassert($6%2==0 , "steel_ ypos is odd", BAD_VALUE);
						yyassert($4>=0 && $4<LEVEL_WIDTH , "steel_ xpos value", OUT_OF_BOUNDS);
						yyassert($6>=0 && $6<LEVEL_HEIGHT , "steel_ ypos value", OUT_OF_BOUNDS);
						yyassert($8>=0 && $8<=STEEL_MAX_WIDTH, "steel_ width value", BAD_VALUE);
						yyassert($10>=0 && $10<=STEEL_MAX_HEIGHT, "steel_ height value", BAD_VALUE);
						
						gIni->level.steelCount++;
					} else {
						yyassert($2<gIni->level.steelCount, "steel_ index", OUT_OF_BOUNDS);
						gIni->level.steels[$2].xpos = $4;
						gIni->level.steels[$2].ypos = $6;
						gIni->level.steels[$2].width = $8;
						gIni->level.steels[$2].height = $10;
					}
							}
| NAME AFF STR			{ gIni->level.name = $3; } /* TODO : attention, si fichier levelpack, name n'est pas le nom d'unniveau */
	/* levelpack.ini */
| MAXFALLDISTANCE AFF INT	{
					yyassert($3>=0, "maxFallDistance", OUT_OF_BOUNDS);
					gIni->levelPack.maxFallDistance = $3;
				}
| CODESEED AFF STR		{ gIni->levelPack.codeSeed = $3; }
| MUSIC INT AFF STR		{ }
| LEVEL INT AFF STR		{}
| DIFFICULTY INT AFF STR VIR INT	{}

particles: INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX VIR INTHEX {
					$$=malloc(16*sizeof(uint32_t));
					$$[0]=$1; $$[1]=$3; $$[2]=$5; $$[3]=$7; $$[4]=$9; $$[5]=$11; $$[6]=$13; $$[7]=$15 ;$$[8]=$17; $$[9]=$19; $$[10]=$21; $$[11]=$23; $$[12]=$25; $$[13]=$27; $$[14]=$29; $$[15]=$31;
				}
%%
int parse(gameIni_t *gIni) {
	int res=0;
	//FIXME : récupérer les valeurs de retour
	gIni->firstPass=1;
	yyparse(gIni);

	callocIfNull((void **)&gIni->style.objects, gIni->style.objectCount, sizeof(struct styleObjects));
	callocIfNull((void **)&gIni->level.objects, gIni->level.objectCount, sizeof(struct levelItem));
	callocIfNull((void **)&gIni->level.terrains, gIni->level.terrainCount, sizeof(struct levelItem));
	callocIfNull((void **)&gIni->level.steels, gIni->level.steelCount, sizeof(struct levelItem));

	rewind(yyin);
	gIni->firstPass=0;
	yyparse(gIni);

	return res;
}

void yyassert(int condition, char what[], char why[]){
	char msg[256];
	if (!condition) {
		sprintf(msg, "%s for %s", why, what);
		yyerror(NULL, msg);
	}
}

void yyerror(gameIni_t *gIni, char *s) {
	fprintf(stderr, "(stdin):%i: error: %s near '%s'\n", yylineno, s, yytext);
	gIni=NULL; /* Faire quelque chose de propre ici */
	exit(1);
}

void callocIfNull(void **ptr, size_t nmemb, size_t size) {
	if (*ptr==NULL && nmemb>0) {
		*ptr=calloc(nmemb, size);
	}	
}