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