From: jwalz Date: Sat, 5 Jan 2002 21:06:00 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: MOVE2GIT~3620 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2b2eaa2510364440d4a6051c68dbae2597f0c6b6;p=nethack *** empty log message *** --- diff --git a/util/dgn_comp.y b/util/dgn_comp.y new file mode 100644 index 000000000..cf1ff83ca --- /dev/null +++ b/util/dgn_comp.y @@ -0,0 +1,678 @@ +%{ +/* SCCS Id: @(#)dgn_comp.c 3.3 96/06/22 */ +/* Copyright (c) 1989 by Jean-Christophe Collet */ +/* Copyright (c) 1990 by M. Stephenson */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * This file contains the Dungeon Compiler code + */ + +/* In case we're using bison in AIX. This definition must be + * placed before any other C-language construct in the file + * excluding comments and preprocessor directives (thanks IBM + * for this wonderful feature...). + * + * Note: some cpps barf on this 'undefined control' (#pragma). + * Addition of the leading space seems to prevent barfage for now, + * and AIX will still see the directive in its non-standard locale. + */ + +#ifdef _AIX + #pragma alloca /* keep leading space! */ +#endif + +#include "config.h" +#include "date.h" +#include "dgn_file.h" + +void FDECL(yyerror, (const char *)); +void FDECL(yywarning, (const char *)); +int NDECL(yylex); +int NDECL(yyparse); +int FDECL(getchain, (char *)); +int NDECL(check_dungeon); +int NDECL(check_branch); +int NDECL(check_level); +void NDECL(init_dungeon); +void NDECL(init_branch); +void NDECL(init_level); +void NDECL(output_dgn); + +#define Free(ptr) free((genericptr_t)ptr) + +#ifdef AMIGA +# undef printf +#ifndef LATTICE +# define memset(addr,val,len) setmem(addr,len,val) +#endif +#endif + +#define ERR (-1) + +static struct couple couple; +static struct tmpdungeon tmpdungeon[MAXDUNGEON]; +static struct tmplevel tmplevel[LEV_LIMIT]; +static struct tmpbranch tmpbranch[BRANCH_LIMIT]; + +static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; + +extern int fatal_error; +extern const char *fname; +extern FILE *yyin, *yyout; /* from dgn_lex.c */ + +%} + +%union +{ + int i; + char* str; +} + +%token INTEGER +%token A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL +%token UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC +%token ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL +%token STRING +%type optional_int direction branch_type bones_tag +%start file + +%% +file : /* nothing */ + | dungeons + { + output_dgn(); + } + ; + +dungeons : dungeon + | dungeons dungeon + ; + +dungeon : dungeonline + | dungeondesc + | branches + | levels + ; + +dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int + { + init_dungeon(); + Strcpy(tmpdungeon[n_dgns].name, $3); + tmpdungeon[n_dgns].boneschar = (char)$4; + tmpdungeon[n_dgns].lev.base = couple.base; + tmpdungeon[n_dgns].lev.rand = couple.rand; + tmpdungeon[n_dgns].chance = $6; + Free($3); + } + ; + +optional_int : /* nothing */ + { + $$ = 0; + } + | INTEGER + { + $$ = $1; + } + ; + +dungeondesc : entry + | descriptions + | prototype + ; + +entry : ENTRY ':' INTEGER + { + tmpdungeon[n_dgns].entry_lev = $3; + } + ; + +descriptions : desc + ; + +desc : DESCRIPTION ':' DESCRIPTOR + { + if($3 <= TOWN || $3 >= D_ALIGN_CHAOTIC) + yyerror("Illegal description - ignoring!"); + else + tmpdungeon[n_dgns].flags |= $3 ; + } + | ALIGNMENT ':' DESCRIPTOR + { + if($3 && $3 < D_ALIGN_CHAOTIC) + yyerror("Illegal alignment - ignoring!"); + else + tmpdungeon[n_dgns].flags |= $3 ; + } + ; + +prototype : PROTOFILE ':' STRING + { + Strcpy(tmpdungeon[n_dgns].protoname, $3); + Free($3); + } + ; + +levels : level1 + | level2 + | levdesc + | chlevel1 + | chlevel2 + ; + +level1 : LEVEL ':' STRING bones_tag '@' acouple + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmpdungeon[n_dgns].levels++; + Free($3); + } + | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].rndlevs = $7; + tmpdungeon[n_dgns].levels++; + Free($3); + } + ; + +level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].chance = $7; + tmpdungeon[n_dgns].levels++; + Free($3); + } + | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].chance = $7; + tmplevel[n_levs].rndlevs = $8; + tmpdungeon[n_dgns].levels++; + Free($3); + } + ; + +levdesc : LEVELDESC ':' DESCRIPTOR + { + if($3 >= D_ALIGN_CHAOTIC) + yyerror("Illegal description - ignoring!"); + else + tmplevel[n_levs].flags |= $3 ; + } + | LEVALIGN ':' DESCRIPTOR + { + if($3 && $3 < D_ALIGN_CHAOTIC) + yyerror("Illegal alignment - ignoring!"); + else + tmplevel[n_levs].flags |= $3 ; + } + ; + +chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].chain = getchain($5); + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + if(!check_level()) n_levs--; + else tmpdungeon[n_dgns].levels++; + Free($3); + Free($5); + } + | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].chain = getchain($5); + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].rndlevs = $8; + if(!check_level()) n_levs--; + else tmpdungeon[n_dgns].levels++; + Free($3); + Free($5); + } + ; + +chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].chain = getchain($5); + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].chance = $8; + if(!check_level()) n_levs--; + else tmpdungeon[n_dgns].levels++; + Free($3); + Free($5); + } + | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER + { + init_level(); + Strcpy(tmplevel[n_levs].name, $3); + tmplevel[n_levs].boneschar = (char)$4; + tmplevel[n_levs].chain = getchain($5); + tmplevel[n_levs].lev.base = couple.base; + tmplevel[n_levs].lev.rand = couple.rand; + tmplevel[n_levs].chance = $8; + tmplevel[n_levs].rndlevs = $9; + if(!check_level()) n_levs--; + else tmpdungeon[n_dgns].levels++; + Free($3); + Free($5); + } + ; + +branches : branch + | chbranch + ; + +branch : BRANCH ':' STRING '@' acouple branch_type direction + { + init_branch(); + Strcpy(tmpbranch[n_brs].name, $3); + tmpbranch[n_brs].lev.base = couple.base; + tmpbranch[n_brs].lev.rand = couple.rand; + tmpbranch[n_brs].type = $6; + tmpbranch[n_brs].up = $7; + if(!check_branch()) n_brs--; + else tmpdungeon[n_dgns].branches++; + Free($3); + } + ; + +chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction + { + init_branch(); + Strcpy(tmpbranch[n_brs].name, $3); + tmpbranch[n_brs].chain = getchain($4); + tmpbranch[n_brs].lev.base = couple.base; + tmpbranch[n_brs].lev.rand = couple.rand; + tmpbranch[n_brs].type = $7; + tmpbranch[n_brs].up = $8; + if(!check_branch()) n_brs--; + else tmpdungeon[n_dgns].branches++; + Free($3); + Free($4); + } + ; + +branch_type : /* nothing */ + { + $$ = TBR_STAIR; /* two way stair */ + } + | STAIR + { + $$ = TBR_STAIR; /* two way stair */ + } + | NO_UP + { + $$ = TBR_NO_UP; /* no up staircase */ + } + | NO_DOWN + { + $$ = TBR_NO_DOWN; /* no down staircase */ + } + | PORTAL + { + $$ = TBR_PORTAL; /* portal connection */ + } + ; + +direction : /* nothing */ + { + $$ = 0; /* defaults to down */ + } + | UP_OR_DOWN + { + $$ = $1; + } + ; + +bones_tag : STRING + { + char *p = $1; + if (strlen(p) != 1) { + if (strcmp(p, "none") != 0) + yyerror("Bones marker must be a single char, or \"none\"!"); + *p = '\0'; + } + $$ = *p; + Free(p); + } + ; + +/* + * acouple rules: + * + * (base, range) where: + * + * base is either a positive or negative integer with a value + * less than or equal to MAXLEVEL. + * base > 0 indicates the base level. + * base < 0 indicates reverse index (-1 == lowest level) + * + * range is the random component. + * if range is zero, there is no random component. + * if range is -1 the dungeon loader will randomize between + * the base and the end of the dungeon. + * during dungeon load, range is always *added* to the base, + * therefore range + base(converted) must not exceed MAXLEVEL. + */ +acouple : '(' INTEGER ',' INTEGER ')' + { + if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { + yyerror("Abs base out of dlevel range - zeroing!"); + couple.base = couple.rand = 0; + } else if ($4 < -1 || + (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL : + ($2 + $4) > MAXLEVEL)) { + yyerror("Abs range out of dlevel range - zeroing!"); + couple.base = couple.rand = 0; + } else { + couple.base = $2; + couple.rand = $4; + } + } + ; + +/* + * rcouple rules: + * + * (base, range) where: + * + * base is either a positive or negative integer with a value + * less than or equal to MAXLEVEL. + * base > 0 indicates a forward index. + * base < 0 indicates a reverse index. + * base == 0 indicates on the parent level. + * + * range is the random component. + * if range is zero, there is no random component. + * during dungeon load, range is always *added* to the base, + * range + base(converted) may be very large. The dungeon + * loader will then correct to "between here and the top/bottom". + * + * There is no practical way of specifying "between here and the + * nth / nth last level". + */ +rcouple : '(' INTEGER ',' INTEGER ')' + { + if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { + yyerror("Rel base out of dlevel range - zeroing!"); + couple.base = couple.rand = 0; + } else { + couple.base = $2; + couple.rand = $4; + } + } + ; +%% + +void +init_dungeon() +{ + if(++n_dgns > MAXDUNGEON) { + (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", + MAXDUNGEON); + (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); + exit(EXIT_FAILURE); + } + + in_dungeon = 1; + tmpdungeon[n_dgns].lev.base = 0; + tmpdungeon[n_dgns].lev.rand = 0; + tmpdungeon[n_dgns].chance = 100; + Strcpy(tmpdungeon[n_dgns].name, ""); + Strcpy(tmpdungeon[n_dgns].protoname, ""); + tmpdungeon[n_dgns].flags = 0; + tmpdungeon[n_dgns].levels = 0; + tmpdungeon[n_dgns].branches = 0; + tmpdungeon[n_dgns].entry_lev = 0; +} + +void +init_level() +{ + if(++n_levs > LEV_LIMIT) { + + yyerror("FATAL - Too many special levels defined."); + exit(EXIT_FAILURE); + } + tmplevel[n_levs].lev.base = 0; + tmplevel[n_levs].lev.rand = 0; + tmplevel[n_levs].chance = 100; + tmplevel[n_levs].rndlevs = 0; + tmplevel[n_levs].flags = 0; + Strcpy(tmplevel[n_levs].name, ""); + tmplevel[n_levs].chain = -1; +} + +void +init_branch() +{ + if(++n_brs > BRANCH_LIMIT) { + + yyerror("FATAL - Too many special levels defined."); + exit(EXIT_FAILURE); + } + tmpbranch[n_brs].lev.base = 0; + tmpbranch[n_brs].lev.rand = 0; + Strcpy(tmpbranch[n_brs].name, ""); + tmpbranch[n_brs].chain = -1; +} + +int +getchain(s) + char *s; +{ + int i; + + if(strlen(s)) { + + for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) + if(!strcmp(tmplevel[i].name, s)) return i; + + yyerror("Can't locate the specified chain level."); + return(-2); + } + return(-1); +} + +/* + * Consistancy checking routines: + * + * - A dungeon must have a unique name. + * - A dungeon must have a originating "branch" command + * (except, of course, for the first dungeon). + * - A dungeon must have a proper depth (at least (1, 0)). + */ + +int +check_dungeon() +{ + int i; + + for(i = 0; i < n_dgns; i++) + if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { + yyerror("Duplicate dungeon name."); + return(0); + } + + if(n_dgns) + for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { + if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; + + if(i >= n_brs - tmpdungeon[n_dgns].branches) { + yyerror("Dungeon cannot be reached."); + return(0); + } + } + + if(tmpdungeon[n_dgns].lev.base <= 0 || + tmpdungeon[n_dgns].lev.rand < 0) { + yyerror("Invalid dungeon depth specified."); + return(0); + } + return(1); /* OK */ +} + +/* + * - A level must have a unique level name. + * - If chained, the level used as reference for the chain + * must be in this dungeon, must be previously defined, and + * the level chained from must be "non-probabilistic" (ie. + * have a 100% chance of existing). + */ + +int +check_level() +{ + int i; + + if(!in_dungeon) { + yyerror("Level defined outside of dungeon."); + return(0); + } + + for(i = 0; i < n_levs; i++) + if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { + yyerror("Duplicate level name."); + return(0); + } + + if(tmplevel[i].chain == -2) { + yyerror("Invaild level chain reference."); + return(0); + } else if(tmplevel[i].chain != -1) { /* there is a chain */ + /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ + if(tmplevel[tmplevel[i].chain].chance != 100) { + yyerror("Level cannot chain from a probabilistic level."); + return(0); + } else if(tmplevel[i].chain == n_levs) { + yyerror("A level cannot chain to itself!"); + return(0); + } + } + return(1); /* OK */ +} + +/* + * - A branch may not branch backwards - to avoid branch loops. + * - A branch name must be unique. + * (ie. You can only have one entry point to each dungeon). + * - If chained, the level used as reference for the chain + * must be in this dungeon, must be previously defined, and + * the level chained from must be "non-probabilistic" (ie. + * have a 100% chance of existing). + */ + +int +check_branch() +{ + int i; + + if(!in_dungeon) { + yyerror("Branch defined outside of dungeon."); + return(0); + } + + for(i = 0; i < n_dgns; i++) + if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { + + yyerror("Reverse branching not allowed."); + return(0); + } + + if(tmpbranch[i].chain == -2) { + + yyerror("Invaild branch chain reference."); + return(0); + } else if(tmpbranch[i].chain != -1) { /* it is chained */ + + if(tmplevel[tmpbranch[i].chain].chance != 100) { + yyerror("Branch cannot chain from a probabilistic level."); + return(0); + } + } + return(1); /* OK */ +} + +/* + * Output the dungon definition into a file. + * + * The file will have the following format: + * + * [ nethack version ID ] + * [ number of dungeons ] + * [ first dungeon struct ] + * [ levels for the first dungeon ] + * ... + * [ branches for the first dungeon ] + * ... + * [ second dungeon struct ] + * ... + */ + +void +output_dgn() +{ + int nd, cl = 0, nl = 0, + cb = 0, nb = 0; + static struct version_info version_data = { + VERSION_NUMBER, VERSION_FEATURES, + VERSION_SANITY1, VERSION_SANITY2 + }; + + if(++n_dgns <= 0) { + yyerror("FATAL - no dungeons were defined."); + exit(EXIT_FAILURE); + } + + if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { + yyerror("FATAL - output failure."); + exit(EXIT_FAILURE); + } + + (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); + for (nd = 0; nd < n_dgns; nd++) { + (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), + 1, yyout); + + nl += tmpdungeon[nd].levels; + for(; cl < nl; cl++) + (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), + 1, yyout); + + nb += tmpdungeon[nd].branches; + for(; cb < nb; cb++) + (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), + 1, yyout); + } + /* apparently necessary for Think C 5.x, otherwise harmless */ + (void) fflush(yyout); +} + +/*dgn_comp.y*/