[net.sources.games] advgen - a compiler for Chris Torek's "adv": Part 3 of 3

chris@hwcs.UUCP (Chris Miller) (09/26/85)

#!/bin/sh
#
# This is a distribution of "advgen", a compiler for adventures to be
# run by Chris Torek's "adv".  To unpack the distribution, give each
# part as input to the (Bourne) shell.
# Then look at READ_ME.
#
echo 'Start of Advdist, part 03 of 03:'
echo 'x - Makefile'
sed 's/^X//' > Makefile << '/'
XINTERPRETER =	/usr/games/lib/adv
XMAXCODE =	50000
XMAXVOCAB =	1000
XCDEFS =		-DDEFINTERPRETER=\"$(INTERPRETER)\" -DMAXCODE=$(MAXCODE)\
X			-DMAXVOCAB=$(MAXVOCAB)
XCOPTS =		-O
XCFLAGS =	$(COPTS) $(CDEFS)
XYFLAGS =	-d
XLINTFLAGS =	-achx $(CDEFS)
XLINT =		/u1/staff/chris/bin/llint
XOBJS =		advgen.o advgram.o advlex.o lookup.o error.o specials.o\
X		vocab.o str.o rooms.o items.o vars.o msgs.o code.o
XSRCS =		advgen.c advgram.c advlex.c lookup.c error.c specials.c\
X		vocab.c str.c rooms.c items.c vars.c msgs.c code.c
XDIST =		READ_ME TO_DO advgen.man advgen.c advgram.y advlex.l lookup.c\
X		error.c specials.c vocab.c str.c rooms.c items.c vars.c\
X		msgs.c code.c advgen.h extfuncs.h code.h Makefile Pirate.adv\
X		Dist.hdr
X
Xadvgen:	$(OBJS)
X	cc $(COPTS) -o advgen $(OBJS)
X
Xlint:	$(SRCS) tokens.h
X	$(LINT) $(LINTFLAGS) $(SRCS)
X
X$(OBJS):	advgen.h extfuncs.h
X
Xadvgram.o code.o:	code.h
X
Xy.tab.h:	advgram.c
X
Xlookup.o advlex.o:	tokens.h
X
Xtokens.h:	y.tab.h
X	-cmp -s y.tab.h tokens.h || cp y.tab.h tokens.h
X
Xclean:
X	rm -f *.o advgram.c advlex.c y.output y.tab.h tokens.h \
X		core Advdist* adv.out advgen
X
Xdist:
X	rm -f Advdist*
X	packmail -hDist.hdr -oAdvdist $(DIST)
/
echo 'x - READ_ME'
sed 's/^X//' > READ_ME << '/'
XThis is an adventure-generator for the "adv" game by Chris Torek
X(chris@maryland.uucp).
X
XTo build it, check the Makefile and run "make". The most likely things
Xto be changed are:
X	INTERPRETER	The full pathname of "adv". A suitable #! header
X			will be prepended to adventure files, making them
X			directly executable (on BSD-derived systems). This
X			only works if you have a version of "adv" patched to
X			ignore any such initial header; if you don't, define
X			INTERPRETER to be empty.
X	MAXCODE		The maximum size of the generated code; on small
X			address-space systems cut this down to, say, 10000
X			to reduce the size of "advgen".
X	MAXVOCAB	The maximum number of entries in the verb and noun
X			tables; try MAXVOCAB=200 on small systems.
X
XThis has only been built and run on 4.2bsd on a VAX 11/750.  I am
Xunaware of any machine or version dependencies, but they are probably
Xthere.
X
XIf your system doesn't have getopt(3) it should have!  Several versions
Xhave been posted to Usenet recently, any of which will work correctly
Xfor "advgen".
X
XIf your system doesn't have adv(6) this program is useless to you.  The
Xprogram was posted to the net by chris@maryland.uucp, and a version
Xpatched to use the curses library is available from chris@hwcs.uucp
X(no relation!).
X
XThe file Pirate.adv is an extended example of an input file, produced
Xby de-compiling and massaging the "p" adventure distributed with adv.
XI hope the author will forgive me for revealing his secrets; however,
Xthe cat was out of the bag in any case :-) as soon as the source of adv
Xwas distributed.
X
XComments and complaints to chris@hwcs.uucp, known to the world at large as:
X		Chris Miller
X		Department of Computer Science
X		Heriot-Watt University
X		Edinburgh
X		Scotland
X			+44 31 225 8432 Ext. 242
/
echo 'x - TO_DO'
sed 's/^X//' > TO_DO << '/'
X  1.	Replace Message section by Constant section, allowing
X	symbolic names for numeric constants.
X
X  2.	Further extend by allowing constant expressions.
X
X  3.	Allow general boolean expressions in LHS of Daemon and
X	Action rules; parse as expression tree, transform tree to
X	conjunctive normal form, and produce appropriate number of
X	rules, one for each disjunct.  NB for daemons, the percentage
X	should be attached to setting a control variable, which is reset
X	to false on each turn, and is added as a conjunct to the LHS of
X	each disjunct.
X
X  4.	Allow <, <=, != and >= in relations.
X
X  5.	Allow "alphabeticiser" (e.g. ^) as prefix to characters to allow
X	anything to appear there.
X	[Done 16/9/85 - restricted to allowing ^ as initial character of
X	identifiers starting with a digit, to avoid nastiness with ",",
X	"*", newline or space in identifiers messing up the word declarations
X	in the output file.]
/
echo 'x - advgen.c'
sed 's/^X//' > advgen.c << '/'
X#include	"advgen.h"
X
Xvoid
Xmain(nargs, args)
X    int		nargs;
X    char	*args[];
X{
X    char	*envval();
X    void	print();
X    void	init_tabs();
X#ifdef lint
X    char	*optarg = CNULL;
X    int		optind = 0;
X#else	lint
X    extern char	*optarg;
X    extern int	optind;
X#endif	lint
X    int		opt;
X    bool	oflag = FALSE;
X    bool	wflag = FALSE;
X    bool	errflag = FALSE;
X    char	*outfilename = DEFOUTPUT;
X    char	*interpreter = envval("ADVINT", DEFINTERPRETER);
X    static char	badusage[] = "[-w] [-o output] [input]";
X    FILE	*inf = stdin;
X    FILE	*outf;
X
X    setprogname(nargs, args);
X    while ((opt = getopt(nargs, args, "wo:")) != EOF)
X    {
X	switch (opt)
X	{
X	    case 'o':
X	        if (oflag)
X		{
X		    errflag = TRUE;
X		}
X		else
X		{
X		    oflag = TRUE;
X		    outfilename = optarg;
X		}
X		break;
X	    case 'w':
X		if (wflag)
X		{
X		    errflag = TRUE;
X		}
X		else
X		{
X		    wflag = TRUE;
X		    novarwarnings();
X		}
X		break;
X	    default:
X		errflag = TRUE;
X		break;
X	}
X    }
X    if (errflag)
X    {
X	usage(badusage);
X    }
X    nargs -= optind;
X    args += optind;
X    switch (nargs)
X    {
X	case 0:
X	    break;
X	case 1:
X	    if ((inf = fopen(args[0], "r")) == NULL)
X	    {
X		fatal("cannot open input file %s", args[0]);
X	    }
X	    setinfile(args[0]);
X	    break;
X	default:
X	    usage(badusage);
X	    break;
X    }
X    init_tabs();
X
X    if (parse(inf))
X    {
X    	if ((outf = fopen(outfilename, "w")) == NULL)
X	{
X	    fatal("cannot write output file %s", outfilename);
X	}
X	if (*interpreter != '\0')
X	{
X	    if (chmod(outfilename, 0755) != 0)
X	    {
X		warning("cannot set execute permission for %s", outfilename);
X	    }
X	    fprintf(outf, "#!%s\n", interpreter);
X	}
X	print(outf);
X	exit(0);
X    }
X    else
X    {
X	exit(1);
X    }
X    /*NOTREACHED*/
X}
X
Xstatic void
Xprint(f)
X    FILE	*f;
X{
X    printspecials(f);
X    printrooms(f);
X    printvocab(f);
X    printitems(f);
X    printmsgs(f);
X    printcode(f);
X    (void) fclose(f);
X}
X
Xstatic void
Xinit_tabs()
X{
X    init_syms();
X    (void) decl_room(lookup("Limbo"), 0, SPNULL, "", FALSE);
X    decl_item(lookup("NilITEM"), SNULL, SNULL, "");
X}
X
Xstatic char *
Xenvval(var, deflt)
X    char	*var;
X    char	*deflt;
X{
X    char	*result = getenv(var);
X
X    return result == CNULL ? deflt : result;
X}
/
echo 'x - advgen.h'
sed 's/^X//' > advgen.h << '/'
X#include	<stdio.h>
X
Xtypedef int		bool;
Xtypedef	char		smallbool;
Xtypedef unsigned short	smallint;
X
X#define	TRUE		1
X#define	FALSE		0
X
X#ifndef	DEFINTERPRETER
X#define DEFINTERPRETER	"/usr/games/adv"	/*  Program to run output */
X#endif	DEFINTERPRETER
X#define	DEFWORDSIZE	3	/* Number of significant chars. in vocab. */
X#define DEFINVSIZE	5
X#define	DEFLLIFE	240	/* Lamp life */
X#define DEFLWARN	25	/* Lamp warning */
X#define	DEFOUTPUT	"adv.out"
X
X#define	MAXPARSEERRORS	40
X
X/*  Most of the maxima below are imposed by the interpreter's use of
X *  1-byte integers for storing indices.
X */
X
X#ifndef	MAXCODE
X#define	MAXCODE		50000	/* Generated code for daemons and rules */
X#endif	MAXCODE
X#ifndef	MAXVOCAB
X#define	MAXVOCAB	1000	/* Words in noun or verb table */
X#endif	MAXVOCAB
X#define	MAXROOMS	255	/* Rooms/Locations */
X#define	MAXITEMS	255	/* Items */
X#define	MAXVARS		255	/* Variable names */
X#define	MAXMSGS		255	/* Strings */
X#define	MAXWSIZE	20	/* Significant chars. in words (warning) */
X#define MAXINVSIZE	30	/* Maximum reasonable inventory size */
X#define MAXWORDLIST	25	/* Synonyms for special verbs */
X
X#define	LIMBO	0
X
Xtypedef struct symbol
X{
X    char	*s_sym;		/* symbol name */
X    smallint	s_type;
X#	define		S_UNKNOWN	0
X#	define		S_SYNTAX	1
X#	define		S_ROOM		2
X#	define		S_ITEM		3
X#	define		S_VAR		4
X#	define		S_MSG		5
X    smallint	s_value;	/* meaning depends on type */
X    smallint	s_noun;		/* index into noun table */
X    smallint	s_verb;		/* index into verb table */
X}			symbol;
X
Xtypedef struct room
X{
X    char	*r_name;
X    char	*r_desc;
X    smallint	r_neighbours[6];
X    smallbool	r_dark;
X    smallbool	r_declared;		/* To cope forward references */
X}			room;
X
Xtypedef struct item
X{
X    char	*i_name;
X    char	*i_desc;
X    smallint	i_noun;		/* Word used for this, if any */
X    smallint	i_room;		/* Where it starts */
X}			item;
X
Xtypedef struct vocab
X{
X    char	*v_word;
X    smallint	v_value;		/* Equal values for synonyms */
X    smallbool	v_dup;			/* Flag for indistinguishable words */
X}			vocab;
X
Xtypedef struct wordtable
X{
X    smallint	wt_size;		/* Number of entries */
X    smallint	wt_wcount;		/* Ditto, excluding duplicates */
X    smallint	wt_value;		/* Ditto, excluding synonyms */
X    vocab	wt_vocab[MAXVOCAB];
X}			wordtable;
X
Xtypedef struct wordlist		/* Mini-wordtable for special verbs/nouns */
X{
X    int		wl_count;
X    char	*wl_word[MAXWORDLIST];
X}			wordlist;
X
X#define	streq(s, t)	(*(s) == *(t) && strcmp((s), (t)) == 0)
X
X#define		CNULL	(char *) NULL
X#define		SNULL	(symbol *) NULL
X#define		SPNULL	(symbol **) NULL
X#define 	WNULL	(wordtable *) NULL
X
X#define		NOTFOUND	255
X
X#include	"extfuncs.h"
/
echo 'x - code.h'
sed 's/^X//' > code.h << '/'
X#define C_ALWAYS	NOTFOUND
X
X#define	C_EMPTYHANDED	1
X#define	C_ISDARK	3
X#define	C_V0ZERO	5
X#define C_VnZERO	9
X#define	C_V0TEST	13
X#define	C_CARRYING	17
X#define	C_SAMEROOM	19
X#define C_NEARTO	21
X#define C_INROOM	23
X#define	C_INLIMBO	25
X#define C_LOCATION	27
X#define C_VnTEST	29
X
X#define	A_WIN		1
X#define A_DIE		2
X#define A_QUIT		3
X#define A_INVENT	4
X#define A_DARKEN	5
X#define A_LIGHTEN	6
X#define	A_REFILL	7
X#define A_SCORE		8
X#define A_V0ZERO	9
X#define A_V0ONE		10
X#define A_V0INCR	11
X#define	A_V0PRINT	13
X#define A_SAY		14
X#define A_VnPRINT	15
X#define A_VnZERO	16
X#define A_VnONE		17
X#define A_VnINCR	18
X#define A_V0SET		20
X#define	A_V0AUG		21
X#define A_MOVETO	22
X#define	A_GET		23
X#define	A_DROP		24
X#define	A_ZAP		25
X#define	A_FETCH		26
X#define	A_VnSET		27
X#define	A_VnAUG		28
X#define	A_LOCATION	29
X#define	A_SWAP		30
X
X#define	R_EQ		0
X#define R_GT		2
X
X#define I_INCR		0
X#define	I_DECR		1
/
echo 'x - error.c'
sed 's/^X//' > error.c << '/'
X/*
X * error.c: general-purpose error-handling
X */
X
X#include	"advgen.h"
X
Xstatic char	*progname = "no name";	/* Set-up by setprogname(argc,argv) */
Xstatic char	*infilename = "standard input";
X
Xvoid
Xsetprogname(count,args)
X	int	count;
X	char	*args[];
X{
X	char	*p;
X
X	progname = (count>0 ? args[0] : "anonymous program");
X	if ((p = rindex(progname, '/')) != NULL)
X	{
X	    progname = p + 1;
X	}
X}
X
Xvoid
Xsetinfile(s)
X    char	*s;
X{
X    infilename = s;
X}
X
X/*VARARGS3*/
Xstatic void
Xdoerror(exitcode, level, message, arg1, arg2, arg3, arg4)
X/*
X * if exitcode !=0, exit(exitcode).
X * if message != NULL, fprintf it to stderr (maximum of 4 arguments).
X */
X	int	exitcode;
X	char	*level;
X	char	*message;
X{
X	if (message != NULL)
X	{
X		fprintf(stderr, "%s: ", progname);
X		if (level != NULL)
X		{
X			fprintf(stderr, "%s - ", level);
X		}
X		fprintf(stderr, message, arg1, arg2, arg3, arg4);
X		fprintf(stderr, "\n");
X	}
X	if (exitcode != 0)
X	{
X		exit(exitcode);
X		/*NOTREACHED*/
X	}
X}
X
X/*VARARGS1*/
Xvoid
Xfatal(message, arg1, arg2, arg3, arg4)
X	char	*message;
X{
X	doerror(1, "fatal", message, arg1, arg2, arg3, arg4);
X}
X
X/*VARARGS1*/
Xvoid
Xwarning(message, arg1, arg2, arg3, arg4)
X	char	*message;
X{
X	doerror(0, "warning", message, arg1, arg2, arg3, arg4);
X}
X
X/*VARARGS1*/
Xvoid
Xusage(use)
X	char	*use;
X{
X	doerror(1, (char *) NULL, "usage: %s %s", progname, use);
X}
X
X/*VARARGS2*/
Xvoid
Xgramerror(dump, s, a1, a2, a3, a4)
X    bool	dump;
X    char	*s;
X{
X    extern int	yylineno;
X    extern char	*infilename;
X
X    if (dump)
X    {
X	dumpline();
X    }
X    fprintf(stderr, "%s, line %d - ", infilename, yylineno);
X    fprintf(stderr, s, a1, a2, a3, a4);
X    (void) putc('\n', stderr);
X}
X
Xvoid
Xmuldecl(s, type)
X    char	*s;
X    char	*type;
X{
X    gramerror(TRUE, "multiple declaration of %s %s", type, s);
X    add_error();
X}
X
Xvoid
Xmuldef(s)
X    char	*s;
X{
X    gramerror(TRUE, "warning: %s multiply defined", s);
X}
X
Xstatic char	*typename[] =
X{
X	"n unknown", " keyword", " room", "n item", " variable", " message"
X};
X
Xvoid
Xconfdecl(s, type, flag)
X    char	*s;
X    char	*type;
X    smallint	flag;
X{
X    gramerror(TRUE, "conflicting declaration of (%s) %s as a%s",
X    		typename[flag], s, type);
X    add_error();
X}
X
Xvoid
Xtypeerror(s, t)
X    char	*s;
X    int		t;
X{
X    gramerror(TRUE, "%s is not a%s", s, typename[t]);
X    add_error();
X}
/
echo 'x - extfuncs.h'
sed 's/^X//' > extfuncs.h << '/'
Xvoid	add_error();		/* advgram.y */
Xvoid	addspecialword();	/* specials.c */
Xvoid	addsym();		/* lookup.c */
Xvoid	add_treasure();		/* specials.c */
Xvoid	addword();		/* vocab.c */
Xsymbol	*anon_msg();		/* msgs.c */
Xvoid	checkrooms();		/* rooms.c */
Xvoid	checkspecials();	/* specials.c */
Xvoid	codeassign();		/* code.c */
Xvoid	codeaugment();		/* code.c */
Xvoid	codebyte();		/* code.c */
Xvoid	codeinc();		/* code.c */
Xvoid	codeprint();		/* code.c */
Xint	codereln();		/* code.c */
Xvoid	confdecl();		/* error.c */
Xvoid	decl_item();		/* items.c */
Xvoid	decl_msg();		/* msgs.c */
Xint	decl_room();		/* rooms.c */
Xvoid	decl_var();		/* vars.c */
Xvoid	dumpline();		/* advlex.l */
Xvoid	endcond();		/* code.c */
Xvoid	enddaemons();		/* code.c */
Xvoid	endrule();		/* code.c */
Xvoid	fatal();		/* error.c */
Xint	findnoun();		/* vocab.c */
Xint	findverb();		/* vocab.c */
Xint	firstroom();		/* rooms.c */
Xchar	*getenv();		/* C library */
Xvoid	gramerror();		/* error.c */
Xvoid	greetmsg();		/* msgs.c */
Xvoid	init_nouns();		/* specials.c */
Xvoid	init_syms();		/* lookup.c */
Xvoid	init_verbs();		/* specials.c */
Xsymbol	*lookup();		/* lookup.c */
Xvoid	main();			/* advgen.c */
Xchar	*malloc();		/* C library */
Xvoid	muldecl();		/* error.c */
Xvoid	muldef();		/* error.c */
Xvoid	negate();		/* code.c */
Xchar	*noun_name();		/* vocab.c */
Xvoid	novarwarnings();	/* code.c */
Xbool	parse();		/* advgram.y */
Xvoid	printcode();		/* code.c */
Xvoid	printitems();		/* items.c */
Xvoid	printmsgs();		/* msgs.c */
Xvoid	printrooms();		/* rooms.c */
Xvoid	printspecials();	/* specials.c */
Xvoid	printvocab();		/* vocab.c */
Xchar	*rindex();		/* C library */
Xvoid	set_dirs();		/* specials.c */
Xvoid	set_drop_list();	/* specials.c */
Xvoid	set_get_list();		/* specials.c */
Xvoid	set_go_list();		/* specials.c */
Xvoid	set_greeting();		/* specials.c */
Xvoid	set_hell();		/* specials.c */
Xvoid	setinfile();		/* error.c */
Xvoid	setinput();		/* advlex.l */
Xvoid	set_inventory();	/* specials.c */
Xvoid	set_lamp();		/* specials.c */
Xvoid	set_llife();		/* specials.c */
Xvoid	set_lwarn();		/* specials.c */
Xvoid	set_nouns();		/* vocab.c */
Xvoid	setprogname();		/* error.c */
Xvoid	set_start();		/* specials.c */
Xvoid	set_treasury();		/* specials.c */
Xvoid	set_verbs();		/* vocab.c */
Xvoid	set_wsize();		/* specials.c */
Xchar	*strcpy();		/* C library */
Xchar	*strncpy();		/* C library */
Xchar	*strsave();		/* str.c */
Xint	typecheck();		/* code.c */
Xvoid	typeerror();		/* error.c */
Xvoid	usage();		/* error.c */
Xvoid	warning();		/* error.c */
/
echo 'x - items.c'
sed 's/^X//' > items.c << '/'
X#include	"advgen.h"
X
Xstatic int	nitems = 0;
Xstatic item	items[MAXITEMS];
X
Xvoid
Xdecl_item(sym, itemname, location, desc)
X    symbol	*sym;
X    symbol	*itemname;
X    symbol	*location;
X    char	*desc;
X{
X    item 	*i;
X
X    switch (sym -> s_type)
X    {
X	case S_ITEM: 
X	    muldecl (sym -> s_sym, "item");
X	    break;
X	case S_UNKNOWN: 
X	    sym->s_value = newitem (sym -> s_sym);
X	    break;
X	default: 
X	    confdecl (sym -> s_sym, "item", sym -> s_type);
X	    break;
X    }
X    i = items + sym->s_value;
X    sym->s_type = S_ITEM;
X    if (itemname == SNULL)
X    {
X	i -> i_noun = 0;
X    }
X    else if (itemname->s_noun == 0)
X    {
X	gramerror(TRUE, "%s is not a noun", itemname->s_sym);
X	add_error();
X    }
X    else
X    {
X	i->i_noun = itemname->s_noun;
X    }
X    i -> i_desc = desc;
X    if (*desc == '*')
X    {
X	add_treasure();
X    }
X    if (location == SNULL)
X    {
X	i -> i_room = LIMBO;
X    }
X    else
X    {
X	switch (location -> s_type)
X	{
X	    case S_ROOM: 
X		i -> i_room = location -> s_value;
X		break;
X	    default: 
X		gramerror (TRUE, "%s is not a room", location -> s_sym);
X		add_error ();
X		break;
X	}
X    }
X}
X
Xstatic int
Xnewitem(s)
X    char	*s;
X{
X    if (nitems == MAXITEMS)
X    {
X	fatal("too many items");
X    }
X    items[nitems].i_name = s;
X    return nitems++;
X}
X
Xvoid
Xprintitems(f)
X    FILE	*f;
X{
X    int		i;
X    extern int	wsize;
X
X    fprintf(f, "%d\n", nitems);
X    for (i=0; i<nitems; i++)
X    {
X	fprintf(f, "%d", items[i].i_room);
X	if (items[i].i_noun)
X	{
X	    fprintf(f, "=%-.*s", wsize, noun_name(items[i].i_noun));
X	}
X	fprintf(f, ":%s\n", items[i].i_desc);
X    }
X}
/
echo 'x - msgs.c'
sed 's/^X//' > msgs.c << '/'
X#include	"advgen.h"
X
Xstatic int	nmsgs = 1;
Xstatic char	*msgs[MAXMSGS] = { "Enjoy your adventure!" };
X
Xvoid
Xdecl_msg(s, m)
X    symbol	*s;
X    char	*m;
X{
X    switch (s->s_type)
X    {
X	case S_MSG:
X	    muldecl(s->s_sym, "message");
X	    break;
X	case S_UNKNOWN:
X	    if (nmsgs == MAXMSGS)
X	    {
X		fatal("too many messages");
X	    }
X	    msgs[nmsgs] = m;
X	    s->s_type = S_MSG;
X	    s->s_value = nmsgs++;
X	    break;
X	default:
X	    confdecl(s->s_sym, "message", s->s_type);
X	    break;
X    }
X}
X
Xsymbol *
Xanon_msg(m)
X    char	*m;
X{
X    static symbol	s;
X    int			i;
X
X    for (i=0; i<nmsgs; i++)
X    {
X	if (streq(m, msgs[i]))
X	{
X	    s.s_value = i;
X	    return &s;
X	}
X    }
X    if (nmsgs == MAXMSGS)
X    {
X	fatal("too many messages");
X    }
X    msgs[nmsgs] = m;
X    s.s_value = nmsgs++;
X    s.s_type = S_MSG;
X    return &s;
X}
X
Xvoid
Xgreetmsg(m)
X    char	*m;
X{
X    msgs[0] = m;
X}
X
Xvoid
Xprintmsgs(f)
X    FILE	*f;
X{
X    int		i;
X
X    fprintf(f, "%d\n", nmsgs);
X    for (i=0; i<nmsgs; i++)
X    {
X	fprintf(f, "%s\n", msgs[i]);
X    }
X}
/
echo 'x - rooms.c'
sed 's/^X//' > rooms.c << '/'
X#include	"advgen.h"
X
Xstatic room	rooms[MAXROOMS];
Xstatic int	nrooms;
X
Xint
Xdecl_room(sym, darkness, nbrs, desc, flag)
X    symbol	*sym;
X    bool	darkness;
X    symbol	**nbrs;
X    char	*desc;
X    bool	flag;
X{
X    room	*r;
X    int		i;
X    
X    switch (sym->s_type)
X    {
X	case S_ROOM:
X	    if (flag && rooms[sym->s_value].r_declared)
X	    {
X		muldecl(sym->s_sym, "room");
X	    }
X	    break;
X	case S_UNKNOWN:
X	    sym->s_value = newroom(sym->s_sym);
X	    sym->s_type = S_ROOM;
X	    break;
X	default:
X	    confdecl(sym->s_sym, "room", sym->s_type);
X	    break;
X    }
X    if (flag)
X    {
X	r = rooms+(sym->s_value);
X	r->r_declared = 1;
X	r->r_dark = darkness;
X	r->r_desc = desc;
X	for (i = 0; i < 6; i++)
X	{
X	    r->r_neighbours[i] = (nbrs && nbrs[i]) ?
X			decl_room(nbrs[i], FALSE, SPNULL, CNULL, FALSE) : 0;
X	}
X    }
X    return sym->s_value;
X}
X
Xstatic int
Xnewroom(s)
X    char	*s;
X{
X    if (nrooms == MAXROOMS)
X    {
X	fatal("too many rooms");
X    }
X    rooms[nrooms].r_name = s;
X    return nrooms++;
X}
X
Xvoid
Xcheckrooms()
X{
X    int		i;
X
X    for (i=1; i<nrooms; i++)
X    {
X	if (!rooms[i].r_declared)
X	{
X	    gramerror(FALSE, "warning: undeclared room %s", rooms[i].r_name);
X	}
X    }
X}
X
Xvoid
Xprintrooms(f)
X    FILE	*f;
X{
X    int		i, d;
X
X    fprintf(f, "%d\n", nrooms);
X    for (i = 0; i < nrooms; i++)
X    {
X	for (d = 0; d < 6; d++)
X	{
X	    if (rooms[i].r_neighbours[d])
X	    {
X		fprintf(f, "%c%d", "NSEWUD"[d], rooms[i].r_neighbours[d]);
X	    }
X	}
X	if (rooms[i].r_dark)
X	{
X	    (void) putc('%', f);
X	}
X	fprintf(f, ":%s\n", rooms[i].r_desc);
X    }
X}
X
Xint
Xfirstroom()
X{
X    return nrooms < 2 ? 0 : 1;
X}
/
echo 'Part 03 of Advdist complete.'
exit
-- 
	Chris Miller, Heriot-Watt University, Edinburgh
	...!ukc!hwcs!chris   chris@hwcs.uucp	chris@cs.hw.ac.uk