Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.1 6/24/83 (MC830713); site hwcs.UUCP
Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!seismo!mcvax!ukc!cstvax!hwcs!chris
From: chris@hwcs.UUCP (Chris Miller)
Newsgroups: net.sources.games
Subject: advgen - a compiler for Chris Torek's "adv": Part 2 of 3
Message-ID: <620@hwcs.UUCP>
Date: Thu, 26-Sep-85 11:51:38 EDT
Article-I.D.: hwcs.620
Posted: Thu Sep 26 11:51:38 1985
Date-Received: Sun, 22-Sep-85 06:16:41 EDT
Reply-To: chris@cs.hw.AC.UK.UUCP (Chris Miller)
Organization: Computer Sci., Heriot-Watt U., Scotland
Lines: 1835
#!/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 neighbours
X%type cond relation number
X%type darkness
X%type itemname itemroom actword description
X
X%token
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
X FFALSE
X NUM
X TTRUE
X%token
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
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; iwl_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
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