2 /* NetHack 3.6 dgn_comp.y $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */
3 /* Copyright (c) 1989 by Jean-Christophe Collet */
4 /* Copyright (c) 1990 by M. Stephenson */
5 /* NetHack may be freely redistributed. See license for details. */
8 * This file contains the Dungeon Compiler code
11 /* In case we're using bison in AIX. This definition must be
12 * placed before any other C-language construct in the file
13 * excluding comments and preprocessor directives (thanks IBM
14 * for this wonderful feature...).
16 * Note: some cpps barf on this 'undefined control' (#pragma).
17 * Addition of the leading space seems to prevent barfage for now,
18 * and AIX will still see the directive in its non-standard locale.
22 #pragma alloca /* keep leading space! */
29 void FDECL
(yyerror, (const char *));
30 void FDECL
(yywarning
, (const char *));
33 int FDECL
(getchain
, (char *));
34 int NDECL
(check_dungeon
);
35 int NDECL
(check_branch
);
36 int NDECL
(check_level
);
37 void NDECL
(init_dungeon
);
38 void NDECL
(init_branch
);
39 void NDECL
(init_level
);
40 void NDECL
(output_dgn
);
42 #define Free(ptr) free((genericptr_t)ptr)
47 # define memset(addr,val,len) setmem(addr,len,val)
53 static struct couple couple
;
54 static struct tmpdungeon tmpdungeon
[MAXDUNGEON
];
55 static struct tmplevel tmplevel
[LEV_LIMIT
];
56 static struct tmpbranch tmpbranch
[BRANCH_LIMIT
];
58 static int in_dungeon
= 0, n_dgns
= -1, n_levs
= -1, n_brs
= -1;
60 extern
int fatal_error
;
61 extern
const char *fname
;
62 extern
FILE *yyin
, *yyout
; /* from dgn_lex.c */
73 %token
<i
> A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL
74 %token
<i
> UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC
75 %token
<i
> ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL
77 %type
<i
> optional_int direction branch_type bones_tag
98 dungeonline
: A_DUNGEON
':' STRING bones_tag rcouple optional_int
101 Strcpy
(tmpdungeon
[n_dgns
].name
, $3);
102 tmpdungeon
[n_dgns
].boneschar
= (char)$4;
103 tmpdungeon
[n_dgns
].lev.base
= couple.base
;
104 tmpdungeon
[n_dgns
].lev.rand
= couple.rand
;
105 tmpdungeon
[n_dgns
].chance
= $6;
110 optional_int
: /* nothing */
125 entry
: ENTRY
':' INTEGER
127 tmpdungeon
[n_dgns
].entry_lev
= $3;
134 desc
: DESCRIPTION
':' DESCRIPTOR
136 if
($
<i
>3 <= TOWN || $
<i
>3 >= D_ALIGN_CHAOTIC
)
137 yyerror("Illegal description - ignoring!");
139 tmpdungeon
[n_dgns
].flags |
= $
<i
>3 ;
141 | ALIGNMENT
':' DESCRIPTOR
143 if
($
<i
>3 && $
<i
>3 < D_ALIGN_CHAOTIC
)
144 yyerror("Illegal alignment - ignoring!");
146 tmpdungeon
[n_dgns
].flags |
= $
<i
>3 ;
150 prototype
: PROTOFILE
':' STRING
152 Strcpy
(tmpdungeon
[n_dgns
].protoname
, $3);
164 level1
: LEVEL
':' STRING bones_tag
'@' acouple
167 Strcpy
(tmplevel
[n_levs
].name
, $3);
168 tmplevel
[n_levs
].boneschar
= (char)$4;
169 tmplevel
[n_levs
].lev.base
= couple.base
;
170 tmplevel
[n_levs
].lev.rand
= couple.rand
;
171 tmpdungeon
[n_dgns
].levels
++;
174 | RNDLEVEL
':' STRING bones_tag
'@' acouple INTEGER
177 Strcpy
(tmplevel
[n_levs
].name
, $3);
178 tmplevel
[n_levs
].boneschar
= (char)$4;
179 tmplevel
[n_levs
].lev.base
= couple.base
;
180 tmplevel
[n_levs
].lev.rand
= couple.rand
;
181 tmplevel
[n_levs
].rndlevs
= $7;
182 tmpdungeon
[n_dgns
].levels
++;
187 level2
: LEVEL
':' STRING bones_tag
'@' acouple INTEGER
190 Strcpy
(tmplevel
[n_levs
].name
, $3);
191 tmplevel
[n_levs
].boneschar
= (char)$4;
192 tmplevel
[n_levs
].lev.base
= couple.base
;
193 tmplevel
[n_levs
].lev.rand
= couple.rand
;
194 tmplevel
[n_levs
].chance
= $7;
195 tmpdungeon
[n_dgns
].levels
++;
198 | RNDLEVEL
':' STRING bones_tag
'@' acouple INTEGER INTEGER
201 Strcpy
(tmplevel
[n_levs
].name
, $3);
202 tmplevel
[n_levs
].boneschar
= (char)$4;
203 tmplevel
[n_levs
].lev.base
= couple.base
;
204 tmplevel
[n_levs
].lev.rand
= couple.rand
;
205 tmplevel
[n_levs
].chance
= $7;
206 tmplevel
[n_levs
].rndlevs
= $8;
207 tmpdungeon
[n_dgns
].levels
++;
212 levdesc
: LEVELDESC
':' DESCRIPTOR
214 if
($
<i
>3 >= D_ALIGN_CHAOTIC
)
215 yyerror("Illegal description - ignoring!");
217 tmplevel
[n_levs
].flags |
= $
<i
>3 ;
219 | LEVALIGN
':' DESCRIPTOR
221 if
($
<i
>3 && $
<i
>3 < D_ALIGN_CHAOTIC
)
222 yyerror("Illegal alignment - ignoring!");
224 tmplevel
[n_levs
].flags |
= $
<i
>3 ;
228 chlevel1
: CHLEVEL
':' STRING bones_tag STRING
'+' rcouple
231 Strcpy
(tmplevel
[n_levs
].name
, $3);
232 tmplevel
[n_levs
].boneschar
= (char)$4;
233 tmplevel
[n_levs
].chain
= getchain
($5);
234 tmplevel
[n_levs
].lev.base
= couple.base
;
235 tmplevel
[n_levs
].lev.rand
= couple.rand
;
236 if
(!check_level
()) n_levs
--;
237 else tmpdungeon
[n_dgns
].levels
++;
241 | RNDCHLEVEL
':' STRING bones_tag STRING
'+' rcouple INTEGER
244 Strcpy
(tmplevel
[n_levs
].name
, $3);
245 tmplevel
[n_levs
].boneschar
= (char)$4;
246 tmplevel
[n_levs
].chain
= getchain
($5);
247 tmplevel
[n_levs
].lev.base
= couple.base
;
248 tmplevel
[n_levs
].lev.rand
= couple.rand
;
249 tmplevel
[n_levs
].rndlevs
= $8;
250 if
(!check_level
()) n_levs
--;
251 else tmpdungeon
[n_dgns
].levels
++;
257 chlevel2
: CHLEVEL
':' STRING bones_tag STRING
'+' rcouple INTEGER
260 Strcpy
(tmplevel
[n_levs
].name
, $3);
261 tmplevel
[n_levs
].boneschar
= (char)$4;
262 tmplevel
[n_levs
].chain
= getchain
($5);
263 tmplevel
[n_levs
].lev.base
= couple.base
;
264 tmplevel
[n_levs
].lev.rand
= couple.rand
;
265 tmplevel
[n_levs
].chance
= $8;
266 if
(!check_level
()) n_levs
--;
267 else tmpdungeon
[n_dgns
].levels
++;
271 | RNDCHLEVEL
':' STRING bones_tag STRING
'+' rcouple INTEGER INTEGER
274 Strcpy
(tmplevel
[n_levs
].name
, $3);
275 tmplevel
[n_levs
].boneschar
= (char)$4;
276 tmplevel
[n_levs
].chain
= getchain
($5);
277 tmplevel
[n_levs
].lev.base
= couple.base
;
278 tmplevel
[n_levs
].lev.rand
= couple.rand
;
279 tmplevel
[n_levs
].chance
= $8;
280 tmplevel
[n_levs
].rndlevs
= $9;
281 if
(!check_level
()) n_levs
--;
282 else tmpdungeon
[n_dgns
].levels
++;
292 branch
: BRANCH
':' STRING
'@' acouple branch_type direction
295 Strcpy
(tmpbranch
[n_brs
].name
, $3);
296 tmpbranch
[n_brs
].lev.base
= couple.base
;
297 tmpbranch
[n_brs
].lev.rand
= couple.rand
;
298 tmpbranch
[n_brs
].type
= $6;
299 tmpbranch
[n_brs
].up
= $7;
300 if
(!check_branch
()) n_brs
--;
301 else tmpdungeon
[n_dgns
].branches
++;
306 chbranch
: CHBRANCH
':' STRING STRING
'+' rcouple branch_type direction
309 Strcpy
(tmpbranch
[n_brs
].name
, $3);
310 tmpbranch
[n_brs
].chain
= getchain
($4);
311 tmpbranch
[n_brs
].lev.base
= couple.base
;
312 tmpbranch
[n_brs
].lev.rand
= couple.rand
;
313 tmpbranch
[n_brs
].type
= $7;
314 tmpbranch
[n_brs
].up
= $8;
315 if
(!check_branch
()) n_brs
--;
316 else tmpdungeon
[n_dgns
].branches
++;
322 branch_type
: /* nothing */
324 $$
= TBR_STAIR
; /* two way stair */
328 $$
= TBR_STAIR
; /* two way stair */
332 $$
= TBR_NO_UP
; /* no up staircase */
336 $$
= TBR_NO_DOWN
; /* no down staircase */
340 $$
= TBR_PORTAL
; /* portal connection */
344 direction
: /* nothing */
346 $$
= 0; /* defaults to down */
357 if
(strlen
(p
) != 1) {
358 if
(strcmp
(p
, "none") != 0)
359 yyerror("Bones marker must be a single char, or \"none\"!");
370 * (base, range) where:
372 * base is either a positive or negative integer with a value
373 * less than or equal to MAXLEVEL.
374 * base > 0 indicates the base level.
375 * base < 0 indicates reverse index (-1 == lowest level)
377 * range is the random component.
378 * if range is zero, there is no random component.
379 * if range is -1 the dungeon loader will randomize between
380 * the base and the end of the dungeon.
381 * during dungeon load, range is always *added* to the base,
382 * therefore range + base(converted) must not exceed MAXLEVEL.
384 acouple
: '(' INTEGER
',' INTEGER
')'
386 if
($2 < -MAXLEVEL ||
$2 > MAXLEVEL
) {
387 yyerror("Abs base out of dlevel range - zeroing!");
388 couple.base
= couple.rand
= 0;
389 } else if
($4 < -1 ||
390 (($2 < 0) ?
(MAXLEVEL
+ $2 + $4 + 1) > MAXLEVEL
:
391 ($2 + $4) > MAXLEVEL
)) {
392 yyerror("Abs range out of dlevel range - zeroing!");
393 couple.base
= couple.rand
= 0;
404 * (base, range) where:
406 * base is either a positive or negative integer with a value
407 * less than or equal to MAXLEVEL.
408 * base > 0 indicates a forward index.
409 * base < 0 indicates a reverse index.
410 * base == 0 indicates on the parent level.
412 * range is the random component.
413 * if range is zero, there is no random component.
414 * during dungeon load, range is always *added* to the base,
415 * range + base(converted) may be very large. The dungeon
416 * loader will then correct to "between here and the top/bottom".
418 * There is no practical way of specifying "between here and the
419 * nth / nth last level".
421 rcouple
: '(' INTEGER
',' INTEGER
')'
423 if
($2 < -MAXLEVEL ||
$2 > MAXLEVEL
) {
424 yyerror("Rel base out of dlevel range - zeroing!");
425 couple.base
= couple.rand
= 0;
437 if
(++n_dgns
> MAXDUNGEON
) {
438 (void) fprintf
(stderr
, "FATAL - Too many dungeons (limit: %d).\n",
440 (void) fprintf
(stderr
, "To increase the limit edit MAXDUNGEON in global.h\n");
445 tmpdungeon
[n_dgns
].lev.base
= 0;
446 tmpdungeon
[n_dgns
].lev.rand
= 0;
447 tmpdungeon
[n_dgns
].chance
= 100;
448 Strcpy
(tmpdungeon
[n_dgns
].name
, "");
449 Strcpy
(tmpdungeon
[n_dgns
].protoname
, "");
450 tmpdungeon
[n_dgns
].flags
= 0;
451 tmpdungeon
[n_dgns
].levels
= 0;
452 tmpdungeon
[n_dgns
].branches
= 0;
453 tmpdungeon
[n_dgns
].entry_lev
= 0;
459 if
(++n_levs
> LEV_LIMIT
) {
461 yyerror("FATAL - Too many special levels defined.");
464 tmplevel
[n_levs
].lev.base
= 0;
465 tmplevel
[n_levs
].lev.rand
= 0;
466 tmplevel
[n_levs
].chance
= 100;
467 tmplevel
[n_levs
].rndlevs
= 0;
468 tmplevel
[n_levs
].flags
= 0;
469 Strcpy
(tmplevel
[n_levs
].name
, "");
470 tmplevel
[n_levs
].chain
= -1;
476 if
(++n_brs
> BRANCH_LIMIT
) {
478 yyerror("FATAL - Too many special levels defined.");
481 tmpbranch
[n_brs
].lev.base
= 0;
482 tmpbranch
[n_brs
].lev.rand
= 0;
483 Strcpy
(tmpbranch
[n_brs
].name
, "");
484 tmpbranch
[n_brs
].chain
= -1;
495 for
(i
= n_levs
- tmpdungeon
[n_dgns
].levels
+ 1; i
<= n_levs
; i
++)
496 if
(!strcmp
(tmplevel
[i
].name
, s
)) return i
;
498 yyerror("Can't locate the specified chain level.");
505 * Consistancy checking routines:
507 * - A dungeon must have a unique name.
508 * - A dungeon must have a originating "branch" command
509 * (except, of course, for the first dungeon).
510 * - A dungeon must have a proper depth (at least (1, 0)).
518 for
(i
= 0; i
< n_dgns
; i
++)
519 if
(!strcmp
(tmpdungeon
[i
].name
, tmpdungeon
[n_dgns
].name
)) {
520 yyerror("Duplicate dungeon name.");
525 for
(i
= 0; i
< n_brs
- tmpdungeon
[n_dgns
].branches
; i
++) {
526 if
(!strcmp
(tmpbranch
[i
].name
, tmpdungeon
[n_dgns
].name
)) break
;
528 if
(i
>= n_brs
- tmpdungeon
[n_dgns
].branches
) {
529 yyerror("Dungeon cannot be reached.");
534 if
(tmpdungeon
[n_dgns
].lev.base
<= 0 ||
535 tmpdungeon
[n_dgns
].lev.rand
< 0) {
536 yyerror("Invalid dungeon depth specified.");
543 * - A level must have a unique level name.
544 * - If chained, the level used as reference for the chain
545 * must be in this dungeon, must be previously defined, and
546 * the level chained from must be "non-probabilistic" (ie.
547 * have a 100% chance of existing).
556 yyerror("Level defined outside of dungeon.");
560 for
(i
= 0; i
< n_levs
; i
++)
561 if
(!strcmp
(tmplevel
[i
].name
, tmplevel
[n_levs
].name
)) {
562 yyerror("Duplicate level name.");
566 if
(tmplevel
[i
].chain
== -2) {
567 yyerror("Invaild level chain reference.");
569 } else if
(tmplevel
[i
].chain
!= -1) { /* there is a chain */
570 /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */
571 if
(tmplevel
[tmplevel
[i
].chain
].chance
!= 100) {
572 yyerror("Level cannot chain from a probabilistic level.");
574 } else if
(tmplevel
[i
].chain
== n_levs
) {
575 yyerror("A level cannot chain to itself!");
583 * - A branch may not branch backwards - to avoid branch loops.
584 * - A branch name must be unique.
585 * (ie. You can only have one entry point to each dungeon).
586 * - If chained, the level used as reference for the chain
587 * must be in this dungeon, must be previously defined, and
588 * the level chained from must be "non-probabilistic" (ie.
589 * have a 100% chance of existing).
598 yyerror("Branch defined outside of dungeon.");
602 for
(i
= 0; i
< n_dgns
; i
++)
603 if
(!strcmp
(tmpdungeon
[i
].name
, tmpbranch
[n_brs
].name
)) {
605 yyerror("Reverse branching not allowed.");
609 if
(tmpbranch
[i
].chain
== -2) {
611 yyerror("Invaild branch chain reference.");
613 } else if
(tmpbranch
[i
].chain
!= -1) { /* it is chained */
615 if
(tmplevel
[tmpbranch
[i
].chain
].chance
!= 100) {
616 yyerror("Branch cannot chain from a probabilistic level.");
624 * Output the dungon definition into a file.
626 * The file will have the following format:
628 * [ nethack version ID ]
629 * [ number of dungeons ]
630 * [ first dungeon struct ]
631 * [ levels for the first dungeon ]
633 * [ branches for the first dungeon ]
635 * [ second dungeon struct ]
642 int nd
, cl
= 0, nl
= 0,
644 static struct version_info version_data
= {
645 VERSION_NUMBER
, VERSION_FEATURES
,
646 VERSION_SANITY1
, VERSION_SANITY2
, VERSION_SANITY3
650 yyerror("FATAL - no dungeons were defined.");
654 if
(fwrite
((char *)&version_data
, sizeof version_data
, 1, yyout
) != 1) {
655 yyerror("FATAL - output failure.");
659 (void) fwrite
((char *)&n_dgns
, sizeof
(int), 1, yyout
);
660 for
(nd
= 0; nd
< n_dgns
; nd
++) {
661 (void) fwrite
((char *)&tmpdungeon
[nd
], sizeof
(struct tmpdungeon
),
664 nl
+= tmpdungeon
[nd
].levels
;
666 (void) fwrite
((char *)&tmplevel
[cl
], sizeof
(struct tmplevel
),
669 nb
+= tmpdungeon
[nd
].branches
;
671 (void) fwrite
((char *)&tmpbranch
[cb
], sizeof
(struct tmpbranch
),
674 /* apparently necessary for Think C 5.x, otherwise harmless */
675 (void) fflush
(yyout
);