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