1 %{
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "../config.h"
7 #include "zmachine.h"
8 #include "rc.h"
9 #include "rcp.h"
10 #include "hash.h"
11
12 #define YYERROR_VERBOSE 1
13
14 extern int _rc_line;
15 extern hash rc_hash;
16
17 extern void rc_error(char*);
18 extern int rc_lex(void);
19
20 int rc_merging = 0;
21
22 #define EMPTY_GAME(x) x.fg_col = -1; x.bg_col = -1; x.interpreter = -1; x.revision = -1; x.name = NULL; x.fonts = NULL; x.n_fonts = -1; x.colours = NULL; x.n_colours = -1; x.gamedir = x.savedir = x.sounds = x.graphics = NULL; x.xsize = x.ysize = -1; x.antialias = -1;
23
merge_games(const rc_game * a,const rc_game * b)24 static inline rc_game merge_games(const rc_game* a, const rc_game* b)
25 {
26 rc_game r;
27
28 if (a->fg_col == -1)
29 r.fg_col = b->fg_col;
30 else
31 r.fg_col = a->fg_col;
32 if (a->bg_col == -1)
33 r.bg_col = b->bg_col;
34 else
35 r.bg_col = a->bg_col;
36
37 if (a->interpreter == -1)
38 r.interpreter = b->interpreter;
39 else
40 r.interpreter = a->interpreter;
41
42 if (a->antialias == -1)
43 r.antialias = b->antialias;
44 else
45 r.antialias = a->antialias;
46
47 if (a->revision == -1)
48 r.revision = b->revision;
49 else
50 r.revision = a->revision;
51
52 if (a->name == NULL)
53 r.name = b->name;
54 else
55 r.name = a->name;
56
57 if (a->fonts == NULL)
58 {
59 r.fonts = b->fonts;
60 r.n_fonts = b->n_fonts;
61 }
62 else if (b->fonts == NULL)
63 {
64 r.fonts = a->fonts;
65 r.n_fonts = a->n_fonts;
66 }
67 else
68 {
69 int x;
70
71 r.n_fonts = a->n_fonts + b->n_fonts;
72 r.fonts = malloc(r.n_fonts*sizeof(rc_font));
73
74 for (x=0; x<a->n_fonts; x++)
75 r.fonts[x] = a->fonts[x];
76 for (x=0; x<b->n_fonts; x++)
77 r.fonts[x+a->n_fonts] = b->fonts[x];
78
79 free(a->fonts);
80 free(b->fonts);
81 }
82
83 if (a->colours == NULL)
84 {
85 r.colours = b->colours;
86 r.n_colours = b->n_colours;
87 }
88 else if (b->colours == NULL)
89 {
90 r.colours = a->colours;
91 r.n_colours = a->n_colours;
92 }
93 else
94 rc_error("Can only have one set of colours per block");
95
96 if (a->gamedir == NULL)
97 r.gamedir = b->gamedir;
98 else
99 r.gamedir = a->gamedir;
100
101 if (a->savedir == NULL)
102 r.savedir = b->savedir;
103 else
104 r.savedir = a->savedir;
105
106 if (a->sounds == NULL)
107 r.sounds = b->sounds;
108 else
109 r.sounds = a->sounds;
110 if (a->graphics == NULL)
111 r.graphics = b->graphics;
112 else
113 r.graphics = a->graphics;
114
115 if (a->xsize == -1)
116 r.xsize = b->xsize;
117 else
118 r.xsize = a->xsize;
119 if (a->ysize == -1)
120 r.ysize = b->ysize;
121 else
122 r.ysize = a->ysize;
123
124 return r;
125 }
126 %}
127
128 %union {
129 char* str;
130 int num;
131 char chr;
132
133 rc_font font;
134 rc_game game;
135 rc_colour col;
136 stringlist* slist;
137 }
138
139 %token DEFAULT
140 %token INTERPRETER
141 %token REVISION
142 %token FONT
143 %token COLOURS
144 %token GAME
145 %token ROMAN
146 %token BOLD
147 %token ITALIC
148 %token FIXED
149 %token SYMBOLIC
150 %token GAMEDIR
151 %token SAVEDIR
152 %token SOUNDS
153 %token GRAPHICS
154 %token SIZE
155 %token ANTIALIAS
156 %token YES
157 %token NO
158
159 %token <str> GAMEID
160 %token <num> NUMBER
161 %token <str> STRING
162 %token <chr> CHARACTER
163
164 %type <col> ColourDefn
165 %type <game> ColourList
166 %type <slist> RevisionList
167 %type <slist> GoodRevisionList
168 %type <num> FontQual
169 %type <num> FontDefn
170 %type <font> FontType
171 %type <game> RCOption
172 %type <game> RCOptionList
173 %type <game> RCBlock
174 %type <num> YesOrNo
175
176 %{
check_collision(char * ourid,char * name)177 static int check_collision(char* ourid, char* name)
178 {
179 rc_game* game;
180
181 game = hash_get(rc_hash, ourid, strlen(ourid));
182 if (game != NULL && strcmp(name, game->name) != 0)
183 {
184 if (!rc_merging)
185 zmachine_info("Namespace collision: identifier '%s' (for game '%s') already used for game '%s'", ourid, name, game->name);
186 return 0;
187 }
188
189 return 1;
190 }
191 %}
192
193 %%
194
195 RCFile: RCDefn
196 | RCFile RCDefn
197 ;
198
199 RCDefn: DEFAULT STRING RCBlock
200 {
201 rc_game* game;
202
203 if (!rc_merging)
204 {
205 game = malloc(sizeof(rc_game));
206 *game = $3;
207 game->name = $2;
208 hash_store(rc_hash,
209 (unsigned char*)"default",
210 7,
211 game);
212 }
213 }
214 | DEFAULT RCBlock
215 {
216 rc_game* game;
217
218 if (!rc_merging)
219 {
220 game = malloc(sizeof(rc_game));
221 *game = $2;
222 game->name = "%s";
223 hash_store(rc_hash,
224 (unsigned char*)"default",
225 7,
226 game);
227 }
228
229 }
230 | GAME STRING RevisionList
231 {
232 if ($3 != NULL)
233 {
234 rc_game* game;
235 stringlist* next;
236
237 game = malloc(sizeof(rc_game));
238 EMPTY_GAME((*game));
239 game->name = $2;
240
241 next = $3;
242 while (next != NULL)
243 {
244 if (check_collision(next->string, game->name))
245 {
246 hash_store(rc_hash,
247 (unsigned char*)next->string,
248 strlen(next->string),
249 game);
250 }
251 next = next->next;
252 }
253 }
254 else
255 {
256 zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line);
257 }
258 }
259 | GAME STRING RevisionList RCBlock
260 {
261 if ($3 != NULL)
262 {
263 rc_game* game;
264 stringlist* next;
265
266 game = malloc(sizeof(rc_game));
267 *game = $4;
268 game->name = $2;
269
270 next = $3;
271 while (next != NULL)
272 {
273 if (check_collision(next->string, game->name))
274 {
275 hash_store(rc_hash,
276 (unsigned char*)next->string,
277 strlen(next->string),
278 game);
279 }
280 next = next->next;
281 }
282 }
283 else
284 {
285 zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line);
286 }
287 }
288 ;
289
290 RCBlock: '{' RCOptionList '}'
291 {
292 $$ = $2;
293 }
294 | '{' '}'
295 {
296 EMPTY_GAME($$);
297 }
298 | '{' ErrorList
299 {
300 yyerrok;
301 zmachine_info(".zoomrc options block ending at line %i makes no sense", _rc_line);
302 EMPTY_GAME($$);
303 }
304 | '{' RCOptionList ErrorList
305 {
306 yyerrok;
307 $$ = $2;
308
309 zmachine_info(".zoomrc options block at line %i has syntax errors", _rc_line);
310 }
311 ;
312
313 RCOptionList: RCOption
314 | RCOptionList RCOption
315 {
316 $$ = merge_games(&$1, &$2);
317 }
318 ;
319
320 YesOrNo: YES { $$ = 1; }
321 | NO { $$ = 0; }
322 ;
323
324 RCOption: INTERPRETER NUMBER
325 {
326 EMPTY_GAME($$);
327 $$.interpreter = $2;
328 }
329 | ANTIALIAS YesOrNo
330 {
331 EMPTY_GAME($$);
332 $$.antialias = $2;
333 }
334 | REVISION CHARACTER
335 {
336 EMPTY_GAME($$);
337 $$.revision = $2;
338 }
339 | FONT NUMBER STRING FontType
340 {
341 EMPTY_GAME($$);
342 $$.fonts = malloc(sizeof(rc_font));
343 $$.n_fonts = 1;
344 $$.fonts[0] = $4;
345
346 $$.fonts[0].name = $3;
347 $$.fonts[0].num = $2;
348 }
349 | COLOURS ColourList
350 {
351 $$ = $2;
352 }
353 | GAMEDIR STRING
354 {
355 EMPTY_GAME($$);
356 $$.gamedir = $2;
357 }
358 | SAVEDIR STRING
359 {
360 EMPTY_GAME($$);
361 $$.savedir = $2;
362 }
363 | SOUNDS STRING
364 {
365 EMPTY_GAME($$);
366 $$.sounds = $2;
367 }
368 | GRAPHICS STRING
369 {
370 EMPTY_GAME($$);
371 $$.graphics = $2;
372 }
373 | SIZE NUMBER ',' NUMBER
374 {
375 EMPTY_GAME($$);
376 $$.xsize = $2;
377 $$.ysize = $4;
378 }
379 ;
380
381 FontType: FontDefn
382 {
383 $$.name = NULL;
384 $$.attributes[0] = $1;
385 $$.n_attr = 1;
386 $$.num = 0;
387 }
388 | FontType ',' FontDefn
389 {
390 $$ = $1;
391 $$.n_attr++;
392 $$.attributes[$$.n_attr-1] = $3;
393 }
394 ;
395
396 FontDefn: FontQual
397 {
398 $$ = $1;
399 }
400 | FontDefn '-' FontQual
401 {
402 $$ = $1|$3;
403 }
404 ;
405
406 FontQual: ROMAN { $$ = 0; }
407 | BOLD { $$ = 1; }
408 | ITALIC { $$ = 2; }
409 | FIXED { $$ = 4; }
410 | SYMBOLIC { $$ = 8; }
411 ;
412
413 ColourList: ColourDefn
414 {
415 EMPTY_GAME($$);
416 $$.colours = malloc(sizeof(rc_colour));
417 $$.colours[0] = $1;
418 $$.n_colours = 1;
419 }
420 | ColourList ',' ColourDefn
421 {
422 $$ = $1;
423 $$.n_colours++;
424 $$.colours = realloc($$.colours,
425 sizeof(rc_colour)*$$.n_colours);
426 $$.colours[$$.n_colours-1]=$3;
427 }
428 ;
429
430 ColourDefn: '(' NUMBER ',' NUMBER ',' NUMBER ')'
431 {
432 $$.r = $2&0xff;
433 $$.g = $4&0xff;
434 $$.b = $6&0xff;
435 }
436 ;
437
438 RevisionList: GoodRevisionList
439 | BadRevisionList
440 { $$ = NULL; }
441 ;
442
443 BadRevisionList: ErrorList
444 { yyerrok; }
445 ;
446
447 GoodRevisionList: GAMEID
448 {
449 $$ = malloc(sizeof(stringlist));
450 $$->next = NULL;
451 $$->string = $1;
452 }
453 | RevisionList ',' GAMEID
454 {
455 if ($1 == NULL)
456 {
457 $$ = NULL;
458 }
459 else
460 {
461 $$ = malloc(sizeof(stringlist));
462 $$->next = $1;
463 $$->string = $3;
464 }
465 }
466 ;
467
468 ErrorList: error '}' { yyerrok; }
469 ;
470
471 %%
472