[net.sources.games] advgen - a compiler for Chris Torek's "adv": Part 2 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 02 of 03:'
echo 'x - advgram.y'
sed 's/^X//' > advgram.y << '/'
X%{
X#include	"advgen.h"
X#include	"code.h"
X
X#define		percent(n) ((int) ((n)*(255.0/100.0)))
X
Xstatic symbol	*nbrs[6];
Xstatic int	lastnoun, lastverb;
X%}
X
X%union
X{
X	char	*y_string;
X	int	y_int;
X	bool	y_bool;
X	symbol	*y_symbol;
X	symbol	**y_nbrs;
X	int	y_void;
X}
X
X%type	<y_nbrs>	neighbours
X%type	<y_int>		cond relation number
X%type	<y_bool>	darkness
X%type	<y_symbol>	itemname itemroom actword description
X
X%token <y_void>
X	ACTION
X	AND
X	ARROW
X	AT
X	BAR
X	COLON
X	COMMA
X	DAEMON
X	DARK
X	DARKEN
X	DEC
X	DROPVERB
X	EQ
X	GETS
X	GETVERB
X	GOVERB
X	GREETING
X	GT
X	HELL
X	INC
X	INCBY
X	INVALID
X	INVENTORYSIZE
X	ITEM
X	LAMPLIFE
X	LAMPWARNING
X	LAMP
X	LPAR
X	MESSAGE
X	NOT
X	NOUN
X	PERCENT
X	ROOM
X	RPAR
X	SEP
X	STAR
X	STARTROOM
X	TREASUREROOM
X	VAR
X	VERB
X	SWAP
X	WORDSIZE
X%token <y_int>
X	FFALSE
X	NUM
X	TTRUE
X%token <y_symbol>
X	CARRYING
X	DIE
X	DIRS
X	DROP
X	EMPTYHANDED
X	FETCH
X	GET
X	INROOM
X	INVENT
X	ISDARK
X	LIGHTEN
X	INLIMBO
X	LOC
X	MOVETO
X	NEARTO
X	PRINT
X	QUIT
X	REFILL
X	SAMEROOM
X	SAY
X	SCORE
X	WIN
X	WORD
X	ZAP
X%token <y_string>
X	STRING
X
X%start	game
X%%
Xgame
X	: specials
X		{ init_nouns(); }
X		nouns
X		{ init_verbs(); }
X		verbs
X		vars
X		rooms
X		items
X		messages
X		daemons
X		{ enddaemons(); }
X		rules
X	;
X
Xspecials
X	: /* Empty */
X	| special specials
X	;
X
Xspecial
X	: HELL WORD SEP
X			{ set_hell($2->s_sym); }
X	| DIRS WORD WORD WORD WORD WORD WORD SEP
X			{ set_dirs($2->s_sym, $3->s_sym, $4->s_sym,
X					$5->s_sym, $6->s_sym, $7->s_sym);
X			}
X	| LAMP WORD SEP
X			{ set_lamp($2->s_sym); }
X	| WORDSIZE number SEP
X			{ set_wsize($2); }
X	| STARTROOM WORD SEP
X			{ set_start($2->s_sym); }
X	| TREASUREROOM WORD SEP
X			{ set_treasury($2->s_sym); }
X	| INVENTORYSIZE number SEP
X			{ set_inventory($2); }
X	| LAMPLIFE number SEP
X			{ set_llife($2); }
X	| LAMPWARNING number SEP
X			{ set_lwarn($2); }
X	| GREETING STRING SEP
X			{ set_greeting($2); }
X	| GOVERB { set_go_list(); } verbdef SEP
X	| GETVERB { set_get_list(); } verbdef SEP
X	| DROPVERB { set_drop_list(); } verbdef SEP
X	| error SEP
X			{ yyerrok; }
X	;
X
Xverbs
X	: VERB verblist SEP
X	| VERB error SEP
X			{ yyerrok; }
X	| /* Empty */
X	;
X
Xverblist
X	: verbdef
X	| verblist verbdef
X	;
X
Xverbdef
X	: WORD
X			{ addword($1, 1); }
X	| WORD GETS
X		{ addword($1, 1); }
X		synonyms
X	;
Xnouns
X	: NOUN objlist SEP
X	| NOUN error SEP
X			{ yyerrok; }
X	| /* Empty */
X	;
X
Xobjlist
X	: objdef
X	| objlist objdef
X	;
X
Xobjdef
X	: WORD
X			{ addword($1, 1); }
X	| WORD GETS
X		{ addword($1, 1); }
X		synonyms
X	;
X
Xsynonyms
X	: WORD
X			{ addword($1, 0); }
X	| WORD GETS
X		{ addword($1, 0); }
X		synonyms
X	;
X
Xitems
X	: ITEM itemlist
X	| /* Empty */
X	;
X
Xitemlist
X	: item
X	| itemlist item
X	| itemlist error SEP
X			{ yyerrok; }
X	;
Xitem
X	: WORD itemname itemroom STRING SEP
X			{ decl_item($1, $2, $3, $4); }
X	;
X
Xitemname
X	: GETS WORD
X			{ $$ = $2; }
X	| /* Empty */
X			{ $$ = SNULL; }
X	;
X
Xitemroom
X	: AT WORD
X			{ $$ = $2; }
X	| /* Empty */
X			{ $$ = SNULL; }
X	;
X
Xdescription
X	: WORD
X			{ $$ = $1; }
X	| STRING
X			{ $$ = anon_msg($1); }
X	;
X
Xrooms
X	: ROOM roomlist
X			{ checkrooms(); }
X	| /* Empty */
X	;
X
Xroomlist
X	: room
X	| roomlist room
X	| roomlist error SEP
X			{ yyerrok; }
X	;
X
Xroom
X	: WORD darkness neighbours STRING SEP
X			{ (void) decl_room($1,$2,$3,$4,TRUE); clear_nbrs(); }
X	;
X
Xdarkness
X	: DARK
X			{ $$ = TRUE; }
X	| /* Empty */
X			{ $$ = FALSE; }
X	;
X
Xneighbours
X	: LPAR nlist RPAR
X			{ $$ = nbrs; }
X	| /* Empty */
X			{ $$ = SPNULL; }
X	;
X
Xnlist
X	: neighbr
X	| nlist neighbr
X	;
X
Xneighbr
X	: WORD COLON WORD
X			{
X				switch (($1->s_sym)[0])
X				{
X				case 'N': case 'n':
X					dupdir(0);
X					nbrs[0] = $3; break;
X				case 'S': case 's':
X					dupdir(1);
X					nbrs[1] = $3; break;
X				case 'E': case 'e':
X					dupdir(2);
X					nbrs[2] = $3; break;
X				case 'W': case 'w':
X					dupdir(3);
X					nbrs[3] = $3; break;
X				case 'U': case 'u':
X					dupdir(4);
X					nbrs[4] = $3; break;
X				case 'D': case 'd':
X					dupdir(5);
X					nbrs[5] = $3; break;
X				default:
X					gramerror(TRUE,
X						"unknown direction - %s",
X						$1->s_sym);
X					add_error();
X					break;
X				}
X			}
X	;
X
Xmessages
X	: MESSAGE messagelist
X	| /* Empty */
X	;
X
Xmessagelist
X	: message
X	| messagelist message
X	| messagelist error SEP { yyerrok; }
X	;
X
Xmessage
X	: WORD STRING SEP
X			{ decl_msg($1, $2); }
X	;
X
Xdaemons
X	: DAEMON daemonlist
X	| /* Empty */
X	;
X
Xdaemonlist
X	: daemon
X	| daemonlist daemon
X	| daemonlist error SEP { yyerrok; }
X	;
X
Xdaemon
X	: chance production SEP
X			{ endrule(); }
X	;
X
Xchance
X	: /* Empty */
X			{ codebyte(C_ALWAYS); }
X	| number PERCENT
X			{ codebyte(percent($1)); }
X	;
X
Xrules
X	: ACTION rulelist
X	| /* Empty */
X	;
X
Xrulelist
X	: rule
X	| rulelist rule
X	| rulelist error SEP { yyerrok; }
X	;
X
Xrule
X	: utterance alternates SEP
X	;
X
Xalternates
X	: production
X			{ endrule(); }
X	| alternates BAR
X		{ codebyte(lastverb); codebyte(lastnoun); }
X		production
X			{ endrule(); }
X	;
X
Xutterance
X	: actword actword COLON
X			{
X			    codebyte(lastverb = findverb($1, TRUE));
X			    codebyte(lastnoun = findnoun($2, TRUE));
X			}
X	| actword COLON
X			{
X			    lastverb = findverb($1, TRUE);
X			    if (lastverb != NOTFOUND)
X			    {
X				codebyte(lastverb);
X				codebyte(lastnoun = C_ALWAYS);
X			    }
X			    else
X			    {
X				codebyte(lastverb = C_ALWAYS);
X				codebyte(lastnoun = findnoun($1, TRUE));
X			    }
X			}
X	;
X
Xactword
X	: WORD
X			{ $$ = $1; }
X	| STAR
X			{ $$ = SNULL; }
X	;
X
Xproduction
X	: conditions ARROW
X		{ endcond(); }
X		actions
X	| conditions
X			{ endcond(); }
X	| ARROW
X		{ endcond(); }
X		actions
X	| /* Empty */
X			{ endcond(); }
X	;
X
Xconditions
X	: condition
X	| conditions AND condition
X	;
X
Xactions
X	: action
X	| actions COMMA action
X	;
X
Xcondition
X	: cond
X	| NOT cond
X			{ negate($2); }
X	;
X
Xcond
X	: EMPTYHANDED
X			{ codebyte(C_EMPTYHANDED); $$ = 1; }
X	| ISDARK
X			{ codebyte(C_ISDARK); $$ = 1; }
X	| WORD relation number
X			{ $$ = codereln($2, $1, $3); }
X	| WORD
X			{ $$ = codereln(R_GT, $1, 0); }
X	| CARRYING LPAR WORD RPAR
X			{
X			    codebyte(C_CARRYING);
X			    codebyte(typecheck($3, S_ITEM));
X			    $$ = 2;
X			}
X	| SAMEROOM LPAR WORD RPAR
X			{
X			    codebyte(C_SAMEROOM);
X			    codebyte(typecheck($3, S_ITEM));
X			    $$ = 2;
X			}
X	| NEARTO LPAR WORD RPAR
X			{
X			    codebyte(C_NEARTO);
X			    codebyte(typecheck($3, S_ITEM));
X			    $$ = 2;
X			}
X	| INROOM LPAR WORD RPAR
X			{
X			    codebyte(C_INROOM);
X			    codebyte(typecheck($3, S_ROOM));
X			    $$ = 2;
X			}
X	| INLIMBO LPAR WORD RPAR
X			{
X			    codebyte(C_INLIMBO);
X			    codebyte(typecheck($3, S_ITEM));
X			    $$ = 2;
X			}
X	| LOC LPAR WORD RPAR EQ WORD
X			{
X			    codebyte(C_LOCATION);
X			    codebyte(typecheck($3, S_ITEM));
X			    codebyte(typecheck($6, S_ROOM));
X			    $$ = 3;
X			}
X	| LPAR cond RPAR
X			{ $$ = $2; }
X	;
X
Xaction
X	: WIN
X			{ codebyte(A_WIN); }
X	| DIE
X			{ codebyte(A_DIE); }
X	| QUIT
X			{ codebyte(A_QUIT); }
X	| INVENT
X			{ codebyte(A_INVENT); }
X	| DARKEN
X			{ codebyte(A_DARKEN); }
X	| LIGHTEN
X			{ codebyte(A_LIGHTEN); }
X	| REFILL
X			{ codebyte(A_REFILL); }
X	| SCORE
X			{ codebyte(A_SCORE); }
X	| WORD GETS number
X			{ codeassign($1, $3); }
X	| INC WORD
X			{ codeinc($2, I_INCR); }
X	| DEC WORD
X			{ codeinc($2, I_DECR); }
X	| PRINT LPAR WORD RPAR
X			{ codeprint($3); }
X	| SAY description
X			{ codebyte(A_SAY); codebyte(typecheck($2, S_MSG)); }
X	| description
X			{ codebyte(A_SAY); codebyte(typecheck($1, S_MSG)); }
X	| WORD INCBY number
X			{ codeaugment($1, $3); }
X	| MOVETO LPAR WORD RPAR
X			{ codebyte(A_MOVETO); codebyte(typecheck($3,S_ROOM));}
X	| GET LPAR WORD RPAR
X			{ codebyte(A_GET); codebyte(typecheck($3, S_ITEM)); }
X	| DROP LPAR WORD RPAR
X			{ codebyte(A_DROP); codebyte(typecheck($3, S_ITEM)); }
X	| ZAP LPAR WORD RPAR
X			{ codebyte(A_ZAP); codebyte(typecheck($3, S_ITEM)); }
X	| FETCH LPAR WORD RPAR
X			{ codebyte(A_FETCH); codebyte(typecheck($3,S_ITEM)); }
X	| LOC LPAR WORD RPAR GETS WORD
X			{
X			    codebyte(A_LOCATION);
X			    codebyte(typecheck($3, S_ITEM));
X			    codebyte(typecheck($6, S_ROOM));
X			}
X	| WORD SWAP WORD
X			{
X			    codebyte(A_SWAP);
X			    codebyte(typecheck($1, S_ITEM));
X			    codebyte(typecheck($3, S_ITEM));
X			}
X	;
X
Xvars
X	: VAR varlist SEP
X	| VAR error SEP
X			{ yyerrok; }
X	| /* Empty */
X	;
X
Xvarlist
X	: WORD
X			{ decl_var($1); }
X	| varlist WORD
X			{ decl_var($2); }
X	;
X
Xrelation
X	: EQ
X			{ $$ = R_EQ; }
X	| GT
X			{ $$ = R_GT; }
X	;
X
Xnumber
X	: NUM
X			{ $$ = $1; }
X	| FFALSE
X			{ $$ = 0; }
X	| TTRUE
X			{ $$ = 1; }
X	;
X%%
Xstatic int	parseerrors = 0;
X
Xstatic void
Xyyerror(s)
X    char	*s;
X{
X	gramerror(TRUE, s);
X	add_error();
X}
X
Xvoid
Xadd_error()
X{
X	if (parseerrors++ > MAXPARSEERRORS)
X	{
X	    fatal("Too many errors\n");
X	}
X}
X
Xstatic void
Xdupdir(n)
X	int	n;
X{
X	if (nbrs[n] != SNULL)
X	{
X		gramerror(TRUE, "warning - duplicate direction '%c'",
X				"NSEWUD"[n]);
X	}
X}
X
Xstatic void
Xclear_nbrs()
X{
X	int	i;
X
X	for (i=0; i<6; i++)
X	{
X		nbrs[i] = SNULL;
X	}
X}
X
Xbool
Xparse(f)
X    FILE	*f;
X{
X    setinput(f);
X    if (yyparse() != 0)
X    {
X	add_error();
X    }
X    checkspecials();
X    return parseerrors == 0;
X}
/
echo 'x - advlex.l'
sed 's/^X//' > advlex.l << '/'
X	/*LINTLIBRARY*/
X%{
X#include	"advgen.h"
X#include	"tokens.h"
X
X#ifndef	NO_PRETTY_ERRORS
X/* Redefinition of input depends on "lex" implementation; it is done to
X * allow decent error reporting.
X */
X#undef	input
X#define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):nxtchr())==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
X#endif	NO_PRETTY_ERRORS
X
Xvoid	lexerror();
X%}
X
XWSP	[ \t\n]
XSPACE	{WSP}+
XCOMMENT	\#.*\n
XDIGIT	[0-9]
XLETTER	[A-Za-z_$]
XALNUM	({DIGIT}|{LETTER})
XIDENT	{LETTER}{ALNUM}*
XNIDENT	("^"{ALNUM}+)
XNUM	{DIGIT}+
XSTRING	(\'[^'\n]*\')|(\"[^"\n]*\")|(\`[^`\n]*\`)
X%%
X"&"		{ return AND; }
X"=>"		{ return ARROW; }
X"@"		{ return AT; }
X"|"		{ return BAR; }
X":"		{ return COLON; }
X","		{ return COMMA; }
X"--"		{ return DEC; }
X"=="		{ return EQ; }
X"="		{ return GETS; }
X">"		{ return GT; }
X"++"		{ return INC; }
X"+="		{ return INCBY; }
X"("		{ return LPAR; }
X"!"		{ return NOT; }
X"<->"		{ return SWAP; }
X{NUM}		{ yylval.y_int = atoi(yytext); return NUM; }
X"%"		{ return PERCENT; }
X")"		{ return RPAR; }
X";"		{ return SEP; }
X"*"		{ return STAR; }
X{IDENT}		{ yylval.y_symbol=lookup(yytext);
X		  return (yylval.y_symbol)->s_type == S_SYNTAX ?
X				(yylval.y_symbol)->s_value : WORD;
X		}
X{NIDENT}	{ yylval.y_symbol=lookup(yytext+1);
X		  return (yylval.y_symbol)->s_type == S_SYNTAX ?
X				(yylval.y_symbol)->s_value : WORD;
X		}
X{STRING}	{ yytext[yyleng-1] = '\0';
X		  yylval.y_string = strsave(yytext+1);
X		  return STRING;
X		}
X{SPACE}		;
X{COMMENT}	;
X.		{ lexerror(); }
X%%
Xstatic int
Xyywrap()
X{
X	return 1;
X}
X
Xstatic void
Xlexerror()
X{
X	int	c;
X
X	gramerror(TRUE, "invalid character (%03o, '%c')",
X			yytext[0], yytext[0], yylineno);
X	add_error();
X	while ((c = input()) != '\n' && c != EOF)
X		;
X}
X
X#ifndef	NO_PRETTY_ERRORS
X#	ifndef	BUFSIZ
X#		define	BUFSIZ	1024
X#	endif	BUFSIZ
X
Xchar	linebuf[BUFSIZ+1];
Xchar	*bufp = CNULL;
X
Xstatic int
Xnxtchr()
X{
X	int	c;
X
X	if (bufp == CNULL || bufp == linebuf+BUFSIZ)
X	{
X		if (fgets(linebuf, BUFSIZ, yyin) == NULL)
X		{
X			return EOF;
X		}
X		bufp = linebuf;
X	}
X	if ((c = *bufp++) == '\n')
X	{
X		bufp = CNULL;
X	}
X	return c;
X}
X#endif	NO_PRETTY_ERRORS
X
Xvoid
Xdumpline()
X{
X#ifndef	NO_PRETTY_ERRORS
X	char	*cp = linebuf;
X	char	*errp = linebuf;
X
X	fprintf(stderr, linebuf);
X	if (bufp == CNULL)
X	{
X		while (*errp)
X			errp++;
X	}
X	else
X	{
X		errp = bufp;
X	}
X	errp -= yyleng;		/* Backup 1 token */
X	if (errp < linebuf)
X	{
X		errp = linebuf;
X	}
X	while (cp < errp)
X	{
X		if (*cp == '\t')
X		{
X			(void) putc('\t', stderr);
X		}
X		else if (*cp >= ' ')
X		{
X			(void) putc(' ', stderr);
X		}
X		cp++;
X	}
X	fprintf(stderr, "^\n");
X#endif	NO_PRETTY_ERRS
X}
X
Xvoid
Xsetinput(f)
X    FILE	*f;
X{
X    yyin = f;
X}
/
echo 'x - code.c'
sed 's/^X//' > code.c << '/'
X#include	"advgen.h"
X#include	"code.h"
X
Xstatic char	code[MAXCODE];
Xstatic char	*code_ptr = code;
Xstatic char	*act_ptr;
Xstatic bool	okundeclvars = FALSE;
X
Xenum { indaemons, inactions } phase = indaemons;
X
Xstatic int	ndaemons = 0;
Xstatic int	nactions = 0;
X
Xvoid
Xcodebyte(b)
X    int		b;
X{
X    if (code_ptr == &(code[MAXCODE]))
X    {
X	fatal("too much code for daemons and actions");
X    }
X    *code_ptr++ = (char) b;
X}
X
Xint
Xcodereln(r, s, n)
X    int		r;
X    symbol	*s;
X    int		n;
X{
X    int		v = variable(s);
X
X    if (v == 0)
X    {
X	switch (n)
X	{
X	    case 0:
X		codebyte(C_V0ZERO + r);
X		return 1;
X	    default:
X		codebyte(C_V0TEST + r);
X		codebyte(n);
X		return 2;
X	}
X    }
X    else
X    {
X	switch (n)
X	{
X	    case 0:
X		codebyte(C_VnZERO+ r);
X		codebyte(v);
X		return 2;
X	    default:
X		codebyte(C_VnTEST + r);
X		codebyte(v);
X		codebyte(n);
X		return 3;
X	}
X    }
X}
X
Xvoid
Xcodeassign(s, n)
X    symbol	*s;
X    int		n;
X{
X    int		v = variable(s);
X
X    if (v == 0)
X    {
X	switch (n)
X	{
X	    case 0:
X		codebyte(A_V0ZERO);
X		break;
X	    case 1:
X		codebyte(A_V0ONE);
X		break;
X	    default:
X		codebyte(A_V0SET);
X		codebyte(n);
X		break;
X	}
X    }
X    else
X    {
X	switch (n)
X	{
X	    case 0:
X		codebyte(A_VnZERO);
X		codebyte(v);
X		break;
X	    case 1:
X		codebyte(A_VnONE);
X		codebyte(v);
X		break;
X	    default:
X		codebyte(A_VnSET);
X		codebyte(v);
X		codebyte(n);
X		break;
X	}
X    }
X}
X
Xvoid
Xcodeinc(s, incr)
X    symbol	*s;
X    int		incr;
X{
X    int		v = variable(s);
X
X    if (v == 0)
X    {
X	codebyte(A_V0INCR + incr);
X    }
X    else
X    {
X	codebyte(A_VnINCR + incr);
X	codebyte(v);
X    }
X}
X
Xvoid
Xcodeprint(s)
X    symbol	*s;
X{
X    int		v = variable(s);
X
X    if (v == 0)
X    {
X	codebyte(A_V0PRINT);
X    }
X    else
X    {
X	codebyte(A_VnPRINT);
X	codebyte(v);
X    }
X}
X
Xvoid
Xcodeaugment(s, incr)
X    symbol	*s;
X    int		incr;
X{
X    int		v = variable(s);
X
X    if (v == 0)
X    {
X	codebyte(A_V0AUG);
X	codebyte(incr);
X    }
X    else
X    {
X	codebyte(A_VnAUG);
X	codebyte(v);
X	codebyte(incr);
X    }
X}
X
Xvoid
Xnegate(offset)
X    int		offset;
X{
X    code_ptr[-offset]++;
X}
X
Xvoid
Xendcond()
X{
X    codebyte(0);
X}
X
Xvoid
Xendrule()
X{
X    codebyte(0);
X    switch (phase)
X    {
X	case indaemons:
X	    ndaemons++;
X	    break;
X	case inactions:
X	    nactions++;
X	    break;
X    }
X}
X
Xvoid
Xenddaemons()
X{
X    act_ptr = code_ptr;
X    phase = inactions;
X}
X
Xint
Xtypecheck(s, t)
X    symbol	*s;
X    int		t;
X{
X    if (s->s_type != t)
X    {
X	typeerror(s->s_sym, t);
X	return 255;
X    }
X    else
X    {
X	return s->s_value;
X    }
X}
X
Xvoid
Xprintcode(f)
X    FILE	*f;
X{
X    char	*cp = code;
X    char	*writerule();
X
X   fprintf(f, "%d\n", ndaemons);
X   while (cp < act_ptr)
X   {
X       cp = writerule(f, cp);
X   }
X   fprintf(f, "%d\n", nactions);
X   while (cp < code_ptr)
X   {
X       cp = writerule(f, cp);
X   }
X}
X
Xstatic char *
Xwriterule(f, cp)
X    FILE	*f;
X    char	*cp;
X{
X    /*  Write precondition, including final 0 */
X    do
X    {
X	fprintf(f, "%u,", *cp & 255);
X    } while (*cp++);
X    /*  Write rule, not including final 0 (to avoid spurious comma) */
X    while (*cp)
X    {
X	fprintf(f, "%u,", *cp++ & 255);
X    }
X    /*  Write final 0 */
X    fprintf(f, "0\n");
X
X    return cp+1;
X}
X
Xstatic int
Xvariable(s)
X    symbol	*s;
X{
X    if (s->s_type == S_UNKNOWN)
X    {
X	decl_var(s);
X	if (!okundeclvars)
X	{
X	    gramerror(TRUE, "warning - variable %s not previously declared",
X			s->s_sym);
X	}
X    }
X    return typecheck(s, S_VAR);
X}
X
Xvoid
Xnovarwarnings()
X{
X    okundeclvars = TRUE;
X}
/
echo 'x - lookup.c'
sed 's/^X//' > lookup.c << '/'
X#include	"advgen.h"
X#include	"tokens.h"
X
Xtypedef struct node
X{
X    struct node	*n_left;
X    struct node	*n_right;
X    symbol	n_sym;
X}			node;
X#define NNULL	(node *) NULL
X
X/*  Initial node chosen about the middle of the reserved words */
Xnode	sym_base = { NNULL, NNULL, { "Item", S_SYNTAX, ITEM, 0, 0 }};
Xnode	*sym_tree = &sym_base;
X
Xstatic node *
Xnewnode(s)
X    char	*s;
X{
X#ifdef	lint
X    node	*result = NNULL;
X#else	lint
X    node   	*result = (node *) malloc(sizeof (node));
X#endif	lint
X
X    if (result == NNULL)
X    {
X	fatal("out of memory for symbol table");
X    }
X    result->n_left = result->n_right = NNULL;
X    result->n_sym.s_sym = strsave(s);
X    result->n_sym.s_type = S_UNKNOWN;
X    result->n_sym.s_value = result->n_sym.s_noun = result->n_sym.s_verb = 0;
X    return result;
X}
X
X/*  Chris Torek suggested the speed improvements over the original
X *  version of this: check the first character and only do a strcmp()
X *  if it's equal (I'd planned to put that one in anyway), and replacement
X *  of the original tail-recursion by a goto (doing the work that a good
X *  optimiser should do for us, but usually doesn't).  The following
X *  recoding of looksym() is Chris's.
X *  The actual gain is surprisingly small: at most 10% as measured by
X *  recompiling the Pirate's adventure 20 times; the number of calls
X *  to strcmp and the subroutine call overhead are reduced considerably
X *  but processing is heavily dominated by yylook() and yyparse().
X */
Xstatic node *
Xlooksym(s, n)
X    char		*s;
X    register node	*n;
X{
X    register int	cmp;
X
Xtop:
X    cmp = *s - *n->n_sym.s_sym;	/* fast check on first character */
X    if (cmp == 0)		/* need full blown comparision */
X    {
X	cmp = strcmp(s, n->n_sym.s_sym);
X    }
X    if (cmp < 0)
X    {
X	if (n->n_left == NNULL)
X	{
X	    return n->n_left = newnode(s);
X	}
X	n = n->n_left;		/* recurse on left subtree */
X	goto top;
X    }
X    else if (cmp > 0)
X    {
X	if (n->n_right == NNULL)
X	{
X	    return n->n_right = newnode(s);
X	}
X	n = n->n_right;		/* recurse on right subtree */
X	goto top;
X    }
X    else
X    {
X	return n;
X    }
X}
X
Xsymbol *
Xlookup(s)
X    char	*s;
X{
X    return	&(looksym(s, sym_tree)->n_sym);
X}
X
Xtypedef struct keyword
X{
X    char	*k_word;
X    int		k_token;
X}			keyword;
X
X/*  This is ordered to give reasonable balance, but it probably doesn't
X *  matter very much, since most lookups will find non-reserved words
X *  anyway. Just for fun, the layout shows the tree structure.
X */
Xstatic keyword	ktab[] =
X{
X    { "Item", ITEM },
X	{ "Get", GET },
X	    { "Die", DIE },
X		{ "Daemon", DAEMON },
X		    { "Action", ACTION },
X			{ "Carrying", CARRYING },
X		    { "Dark", DARK },
X			{ "Darken", DARKEN },
X		{ "Dropverb", DROPVERB },
X		    { "Directions", DIRS },
X			{ "Drop", DROP },
X		    { "False", FFALSE },
X			{ "Emptyhanded",EMPTYHANDED },
X			{ "Fetch", FETCH },
X	    { "Inlimbo", INLIMBO },
X		{ "Goverb", GOVERB },
X		    { "Getverb", GETVERB },
X		    { "Greeting", GREETING },
X			{ "Hellroom", HELL },
X		{ "Inventory", INVENT },
X		    { "Inroom", INROOM },
X		    { "Inventorysize",INVENTORYSIZE },
X			{ "Isdark", ISDARK },
X	{ "Room", ROOM },
X	    { "Moveto", MOVETO },
X		{ "Lighten", LIGHTEN },
X		    { "Lamplife", LAMPLIFE },
X			{ "Lamp", LAMP },
X			{ "Lampwarn", LAMPWARNING },
X		    { "Location", LOC },
X			{ "Message", MESSAGE },
X		{ "Print", PRINT },
X		    { "Nearto", NEARTO },
X			{ "Noun", NOUN },
X		    { "Quit", QUIT },
X			{ "Refill", REFILL },
X	    { "Var", VAR },
X		{ "Score", SCORE },
X		    { "Sameroom", SAMEROOM },
X			{ "Say", SAY },
X		    { "Treasury", TREASUREROOM },
X			{ "Startroom", STARTROOM },
X			{ "True", TTRUE },
X		{ "Win", WIN },
X		    { "Wordsize", WORDSIZE },
X			{ "Verb", VERB },
X			{ "Zap", ZAP },
X    { CNULL, 0 }
X};
X
Xvoid
Xinit_syms()
X{
X    keyword	*k;
X    symbol	*s;
X
X    for (k = ktab; k->k_word != CNULL; k++)
X    {
X	s = lookup(k->k_word);
X	s->s_type = S_SYNTAX;
X	s->s_value = k->k_token;
X    }
X}
X
Xvoid
Xaddsym(s, incr)
X    char	*s;
X    int		incr;
X{
X    symbol	*sym = lookup(s);
X
X    if (sym->s_type == S_SYNTAX)
X    {
X	gramerror(FALSE, "%s is a reserved word", s);
X	return;
X    }
X    addword(sym, incr);
X}
/
echo 'x - specials.c'
sed 's/^X//' > specials.c << '/'
X#include	"advgen.h"
X
Xstatic wordlist	def_go = { 5, { "go", "run", "walk", "move", "enter" } };
Xstatic wordlist	def_get = { 4, { "get", "take", "pick", "remove" } };
Xstatic wordlist	def_drop = { 3, { "drop", "release", "leave" } };
X
Xstatic wordlist	go_list;
Xstatic wordlist	get_list;
Xstatic wordlist	drop_list;
X
Xstatic wordlist	*cur_list;
X
Xstatic void
Xbadzero(s)
X    char	*s;
X{
X    gramerror(1, "warning: invalid zero value for %s ignored", s);
X}
X
Xstatic int		tottrs = 0;
Xvoid
Xadd_treasure()
X{
X    tottrs++;
X}
X   
Xstatic char	*hellname = CNULL;
Xstatic int	hellroom;
Xvoid
Xset_hell(s)
X    char	*s;
X{
X    if (hellname != CNULL)
X    {
X	muldef("hell");
X    }
X    hellname = s;
X}
X
Xstatic char	*dirs[6] =
X    {
X	"North", "South", "East", "West", "Up", "Down"
X    };
Xstatic bool	dirs_set = FALSE;
Xvoid
Xset_dirs(n, s, e, w, u, d)
X    char	*n;
X    char	*s;
X    char	*e;
X    char	*w;
X    char	*u;
X    char	*d;
X{
X    if (dirs_set)
X    {
X	muldef("direction names");
X    }
X    dirs_set = TRUE;
X    dirs[0] = n;
X    dirs[1] = s;
X    dirs[2] = e;
X    dirs[3] = w;
X    dirs[4] = u;
X    dirs[5] = d;
X}
X
Xvoid
Xinit_nouns()
X{
X    static bool	initted = FALSE;
X    char	*shortname = "?";
X    int		d;
X
X    if (initted)
X    {
X	return;
X    }
X    initted = TRUE;
X    set_nouns();
X    for (d=0; d<6; d++)
X    {
X	addsym(dirs[d], 1);
X	shortname[0] = dirs[d][0];
X	addsym(strsave(shortname), 0);
X    }
X}
X
Xvoid
Xinit_verbs()
X{
X    static bool	initted = FALSE;
X    void	add_list();
X
X    if (initted)
X    {
X	return;
X    }
X    initted = TRUE;
X    set_verbs();
X    add_list(&go_list, &def_go);
X    add_list(&get_list, &def_get);
X    add_list(&drop_list, &def_drop);
X}
X
Xstatic bool	greeting_set = FALSE;
Xvoid
Xset_greeting(s)
X    char	*s;
X{
X    if (greeting_set)
X    {
X	muldef("greeting message");
X    }
X    greeting_set = TRUE;
X    greetmsg(s);
X}
X
Xstatic char	*lampname = CNULL;
Xstatic int	lamp;
Xvoid
Xset_lamp(s)
X    char	*s;
X{
X    if (lampname != CNULL)
X    {
X	muldef("lamp name");
X    }
X    lampname = s;
X}
X
Xint		wsize = 0;	/*  Referenced as extern elsewhere */
Xvoid
Xset_wsize(n)
X    int		n;
X{
X    if (n == 0)
X    {
X	badzero("wordsize");
X	return;
X    }
X    else if (n > MAXWSIZE)
X    {
X	gramerror(FALSE, "warning - unreasonable wordsize (> %d)", MAXWSIZE);
X    }
X    if (wsize != 0)
X    {
X	muldef("wordsize");
X    }
X    wsize = n;
X}
X
Xstatic char	*startname = CNULL;
Xstatic int	startroom;
Xvoid
Xset_start(s)
X    char	*s;
X{
X    if (startname != CNULL)
X    {
X	muldef("start room");
X    }
X    startname = s;
X}
X
Xstatic char	*trsname = CNULL;
Xstatic int	trsroom;
Xvoid
Xset_treasury(s)
X    char	*s;
X{
X    if (trsname != CNULL)
X    {
X	muldef("treasury room");
X    }
X    trsname = s;
X}
X
Xstatic int	invsize = 0;
Xvoid
Xset_inventory(n)
X    int		n;
X{
X    if (n == 0)
X    {
X	badzero("inventory size");
X	return;
X    }
X    else if (n > MAXINVSIZE)
X    {
X	gramerror(FALSE, "warning - unreasonable inventory size (> %d)",
X			MAXINVSIZE);
X    }
X    if (invsize != 0)
X    {
X	muldef("inventory size");
X    }
X    invsize = n;
X}
X
Xstatic int	lamplife = 0;
Xvoid
Xset_llife(n)
X    int		n;
X{
X    if (n == 0)
X    {
X	badzero("lamp life");
X	return;
X    }
X    if (lamplife != 0)
X    {
X	muldef("lamplife");
X    }
X    lamplife = n;
X}
X
Xstatic int	lampwarn = 0;
Xvoid
Xset_lwarn(n)
X    int		n;
X{
X    if (n == 0)
X    {
X	badzero("lamp warning");
X	return;
X    }
X    if (lampwarn != 0)
X    {
X	muldef("lamp warning");
X    }
X    lampwarn = n;
X}
X
Xvoid
Xset_go_list()
X{
X    cur_list = &go_list;
X}
X
Xvoid
Xset_get_list()
X{
X    cur_list = &get_list;
X}
X
Xvoid
Xset_drop_list()
X{
X    cur_list = &drop_list;
X}
X
Xvoid
Xaddspecialword(s)
X    char	*s;
X{
X    if (cur_list->wl_count == MAXWORDLIST)
X    {
X	gramerror(FALSE,
X		"warning: too many synonyms for %s", cur_list->wl_word[0]);
X    }
X    cur_list->wl_word[cur_list->wl_count++] = s;
X}
X
Xstatic void
Xadd_list(list, deflt)
X    wordlist	*list;
X    wordlist	*deflt;
X{
X    wordlist	*wl = list->wl_count ? list : deflt;
X    int		i;
X
X    addsym(wl->wl_word[0], 1);
X    for (i=1; i<wl->wl_count; i++)
X    {
X	addsym(wl->wl_word[i], 0);
X    }
X}
X
Xvoid
Xcheckspecials()
X{
X    hellroom = val(hellname, S_ROOM, "hell room");
X    lamp     = val(lampname, S_ITEM, "lamp");
X    startroom= val(startname,S_ROOM, "start room");
X    trsroom  = val(trsname,  S_ROOM, "treasury");
X
X    if (startname == CNULL)
X    {
X	gramerror(FALSE, "warning - no start room defined");
X	startroom = firstroom();
X    }
X    if (trsname == CNULL)
X    {
X	gramerror(FALSE, "warning - no treasure room defined");
X	trsroom = firstroom();
X    }
X    if (tottrs == 0)
X    {
X	gramerror(FALSE, "warning - no treasures among items");
X    }
X}
X
Xstatic int
Xval(name, type, title)
X    char	*name;
X    int		type;
X    char	*title;
X{
X    symbol	*s;
X    
X    if (name == CNULL)
X    {
X	return 0;
X    }
X    s = lookup(name);
X    if (s->s_type != type)
X    {
X	gramerror(FALSE, "%s - %s is undeclared", title, name);
X	add_error();
X    }
X    return s->s_value;
X}
X
Xvoid
Xprintspecials(f)
X    FILE	*f;
X{
X    if (hellname != CNULL)
X    {
X	fprintf(f, "!h%d\n", hellroom);
X    }
X    if (wsize == 0)
X    {
X	wsize = DEFWORDSIZE;
X    }
X    else
X    {
X	fprintf(f, "!w%d\n", wsize);
X    }
X    if (dirs_set)
X    {
X	fprintf(f, "!d%s %s %s %s %s %s\n", dirs[0], dirs[1], dirs[2],
X			dirs[3], dirs[4], dirs[5]);
X    }
X    if (lampname != CNULL)
X    {
X	fprintf(f, "!l%d\n", lamp);
X    }
X    fprintf(f, "%d\n%d\n%d\n%d\n%d\n%d\n",
X    		startroom, trsroom, tottrs,
X		invsize == 0 ? DEFINVSIZE : invsize,
X		lamplife == 0 ? DEFLLIFE : lamplife,
X		lampwarn == 0 ? DEFLWARN : lampwarn);
X}
/
echo 'x - vocab.c'
sed 's/^X//' > vocab.c << '/'
X#include	"advgen.h"
X
Xstatic wordtable	noun_table = { 1, 1, 0, { { "--", NOTFOUND } } };
Xstatic wordtable	verb_table = { 1, 1, 0, { { "--", NOTFOUND } } };
Xstatic wordtable	*cur_table = WNULL;
X
Xvoid
Xset_nouns()
X{
X    cur_table = &noun_table;
X}
X
Xvoid
Xset_verbs()
X{
X    cur_table = &verb_table;
X}
X
Xvoid
Xaddword(sym, incr)
X    symbol	*sym;
X    int		incr;
X{
X    void	toomanywords();
X    int		i;
X    bool	dup = FALSE;
X    int		val = cur_table->wt_value + incr;
X    char	*s = sym->s_sym;
X
X    if (cur_table == WNULL)
X    {
X	addspecialword(s);
X	return;
X    }
X    for (i = 0; i < cur_table->wt_size; i++)
X    {
X	if (equivalent(cur_table->wt_vocab[i].v_word, s))
X	{
X	    if (incr || cur_table->wt_value != cur_table->wt_vocab[i].v_value)
X	    {
X		gramerror(FALSE, "warning - '%s' is equivalent to '%s'", s,
X				cur_table->wt_vocab[i].v_word);
X		val = cur_table->wt_vocab[i].v_value;
X	    }
X	    dup = TRUE;
X	    break;
X	}
X    }
X    if (cur_table->wt_size == MAXVOCAB)
X    {
X	toomanywords();
X    }
X    if (!dup)
X    {
X	cur_table->wt_wcount++;
X	if (incr != 0)
X	{
X	    cur_table->wt_value += incr;
X	}
X    }
X    cur_table->wt_vocab[cur_table->wt_size].v_dup = dup;
X    cur_table->wt_vocab[cur_table->wt_size].v_word = s;
X    cur_table->wt_vocab[cur_table->wt_size].v_value = val;
X    if (cur_table == &noun_table)
X    {
X	sym->s_noun = cur_table->wt_size++;
X    }
X    else
X    {
X	sym->s_verb = cur_table->wt_size++;
X    }
X}
X
Xstatic void
Xtoomanywords()
X{
X    fatal("too many %ss", cur_table == &noun_table ? "noun" : "verb");
X}
X
Xint
Xfindnoun(s, flag)
X    symbol	*s;
X    bool	flag;
X{
X    int		val;
X
X    if (s == SNULL)
X    {
X	return NOTFOUND;
X    }
X    else
X    {
X	val = s->s_noun;
X	if (flag && val==0)
X	{
X	    gramerror(TRUE, "%s is not a noun", s->s_sym);
X	    add_error();
X	}
X	return val == 0 ? NOTFOUND : noun_table.wt_vocab[val].v_value;
X    }
X}
X
Xint
Xfindverb(s, flag)
X    symbol	*s;
X    bool	flag;
X{
X    int		val;
X
X    if (s == SNULL)
X    {
X	return NOTFOUND;
X    }
X    else
X    {
X	val = s->s_verb;
X	if (flag && val == 0)
X	{
X	    gramerror(TRUE, "%s is not a verb", s->s_sym);
X	    add_error();
X	}
X	return val == 0 ? NOTFOUND : verb_table.wt_vocab[val].v_value;
X    }
X}
X
Xchar *
Xnoun_name(i)
X    smallint	i;
X{
X    return noun_table.wt_vocab[i].v_word;
X}
X
Xvoid
Xprintvocab(f)
X    FILE	*f;
X{
X    void	printtable();
X
X    printtable(f, &verb_table);
X    printtable(f, &noun_table);    
X}
X
Xstatic void
Xprinttable(f, table)
X    FILE	*f;
X    wordtable	*table;
X{
X    char	*upcase();
X    int		i, count = 10, val = 0;
X    
X    fprintf(f, "%d", table->wt_wcount);
X    for (i = 0; i < table->wt_size; i++)
X    {
X	if (table->wt_vocab[i].v_dup)
X	{
X	    continue;
X	}
X	if (count++ == 10)
X	{
X	    count = 0;
X	    (void) putc('\n', f);
X	}
X	else
X	{
X	    (void) putc(',', f);
X	}
X	if (val == table->wt_vocab[i].v_value)
X	{
X	    (void) putc('*', f);
X	}
X	else
X	{
X	    val = table->wt_vocab[i].v_value;
X	}
X	fprintf(f, "%s", upcase(table->wt_vocab[i].v_word));
X    }
X    putc('\n', f);
X}
X
X#include	<ctype.h>
X
Xstatic char
Xup(c)
X    char	c;
X{
X    return islower(c) ? toupper(c) : c;
X}
X
Xstatic char *
Xupcase(s)
X    char	*s;
X{
X    extern int	wsize;
X    static char	image[500];
X    char	*cp;
X
X    (void) strncpy(image, s, wsize);
X    image[wsize] = '\0';
X    for (cp = image; *cp; cp++)
X    {
X	*cp = up(*cp);
X    }
X    return image;
X}
X
Xstatic bool
Xequivalent(s1, s2)
X    char	*s1;
X    char	*s2;
X{
X    extern int	wsize;
X    int		i;
X    int		limit = wsize ? wsize : DEFWORDSIZE;
X
X    for (i=0; i<limit; i++)
X    {
X	if (up(s1[i]) != up(s2[i]))
X	{
X	    return FALSE;
X	}
X	if (s1[i] == '\0')
X	{
X	    return TRUE;
X	}
X    }
X    return TRUE;
X}
/
echo 'Part 02 of Advdist complete.'
exit
-- 
	Chris Miller, Heriot-Watt University, Edinburgh
	...!ukc!hwcs!chris   chris@hwcs.uucp	chris@cs.hw.ac.uk