2874 lines · 58.8 KB · C
RawDownload
/*
	HEPARSE.C

	Input parsing functions:

		Available
		CallLibraryParse
		FindWord
		KillWord
		Match routines
			AnyObjWord
			AddAllObjects
			AddObj
			AddPossibleObject
			AdvanceGrammar
			DomainObj
			InList
			ObjWord
				ObjWordType
			SubtractObj
			SubtractPossibleObject
			TryObj
			ValidObj
		Parse
		ParseError
		RemoveWord
		ResetFindObject
		SeparateWords

	for the Hugo Engine

	Copyright (c) 1995-2006 by Kent Tessman
*/


#include "heheader.h"


/* Function prototypes: */
void AddObj(int obj);
void AddPossibleObject(int obj, char type, unsigned int w);
void AdvanceGrammar(void);
int DomainObj(int obj);
int InList(int obj);
int MatchObject(int *wordnum);
int MatchWord(int *wordnum);
int ObjWordType(int obj, unsigned int w, int type);
void ResetFindObject(void);
void SubtractObj(int obj);
void SubtractPossibleObject(int obj);
void TryObj(int obj);

int GetVal(void);			/* from heexpr.c */

#define MAXOBJLIST 32

#define STARTS_AS_NUMBER(a) (((a[0]>='0' && a[0]<='9') || a[0]=='-')?1:0)

char buffer[MAXBUFFER+MAXWORDS];        /* input buffer                    */
char errbuf[MAXBUFFER+1];               /* last invalid input              */
char line[1025];                        /* line buffer                     */

int words = 0;                          /* parsed word count               */
char *word[MAXWORDS+1];                 /* breakdown into words            */
unsigned int wd[MAXWORDS+1];            /*     "      "   dict. entries    */
unsigned int parsed_number;             /* needed for numbers in input	   */

signed char remaining = 0;              /* multiple commands in input      */
char parseerr[MAXBUFFER+1];             /* for passing to RunPrint, etc.   */
char parsestr[MAXBUFFER+1];             /* for passing quoted string       */
char xverb;                             /* flag; 0 = regular verb          */
char starts_with_verb;			/* input line; 0 = no verb word    */
unsigned int grammaraddr;             	/* address in grammar              */
char *obj_parselist = NULL;             /* objects with noun/adjective     */
int domain, odomain;                  	/* of object(s)                    */
int objlist[MAXOBJLIST];                /* for objects of verb             */
char objcount;                          /* of objlist                      */
char parse_allflag = false;             /* for "all" in MatchObject()      */
struct pobject_structure
	pobjlist[MAXPOBJECTS];          /* for possible objects            */
int pobjcount;                          /* of pobjlist                     */
int pobj;                               /* last remaining suspect          */
int obj_match_state;                    /* see MatchCommand() for details  */
char objword_cache[MAXWORDS];           /* for MatchWord() xobject, etc.   */
char object_is_number;                  /* number used in player command   */
unsigned int objgrammar;                /* for 2nd pass                    */
int objstart;                           /*  "   "   "                      */
int objfinish;                          /*  "   "   "                      */
char addflag;                           /* true if adding to objlist[]     */
int speaking;                           /* if command is addressed to obj. */

char oops[MAXBUFFER+1];                 /* illegal word                    */
int oopscount = 0;                      /* # of corrections in a row       */

char parse_called_twice;
char reparse_everything;
char punc_string[64];                   /* punctuation string */

char full_buffer = false;
static char recursive_call = false;     /* to MatchObject() */

/* Necessary for proper disambiguation when addressing a character;
   i.e., when 'held' doesn't refer to held by the player, etc.
*/
int parse_location;	/* usually var[location] */


/* ADDALLOBJECTS
*/

void AddAllObjects(int loc)
{
	int i;

	if (loc==var[player] && domain!=loc)
		return;

	/* Try to add everything in the specified domain
	   to objlist[]
	*/
	for (i=Child(loc); i!=0; i=Sibling(i))
	{
		if (i==var[xobject]) continue;

		TryObj(i);
		if (domain==0)
		{
			if (Child(i)) AddAllObjects(i);
		}
	}
}


/* ADDOBJ

	Adds the object <obj> to objlist[], making all related adjustments.
*/

void AddObj(int obj)
{
	int i;

	for (i=0; i<objcount; i++)
	{
		if (objlist[i]==obj)
			return;
	}

	objlist[(int)objcount] = obj;
	if (++objcount> MAXOBJLIST) objcount = MAXOBJLIST;
}


/* ADDPOSSIBLEOBJECT

	Adds <obj> as a contender to the possible object list, noting that
	it was referred to as either a noun or an adjective.
*/

void AddPossibleObject(int obj, char type, unsigned int w)
{
	int i;

	if (pobjcount==MAXPOBJECTS)
		return;

	for (i=0; i<pobjcount; i++)
	{
		/* If it is already in the list */
		if (pobjlist[i].obj==obj)
		{
			/* Being referred to with a noun outweighs being
			   referred to previously with an adjective
			*/
			if (type==(char)noun || ObjWordType(obj, w, noun))
				pobjlist[i].type = (char)noun;

			return;
		}
	}

	/* Getting this to point is presuming that we're adding an object
	   referred to with an adjective, but check just to be sure it isn't
	   also a noun for that same object
	*/
	if (ObjWordType(obj, w, noun)) type = (char)noun;
	
	pobjlist[pobjcount].obj = obj;
	pobjlist[pobjcount].type = type;

	pobjcount++;
#ifdef DEBUG_PARSER
{
	char buf[100];
	sprintf(buf, "AddPossibleObject(%d:\"%s\")", obj, Name(obj));
	Printout(buf);
}
#endif
}


/* ADVANCEGRAMMAR

	Move the address in the grammar table past the current token.
*/

void AdvanceGrammar(void)
{
	int a;

	defseg = gameseg;

	switch (a = Peek(grammaraddr))
	{
		case FORWARD_SLASH_T:
		case HELD_T:
		case MULTI_T:
		case MULTIHELD_T:
		case ANYTHING_T:
		case NUMBER_T:
		case PARENT_T:
		case NOTHELD_T:
		case MULTINOTHELD_T:
		case WORD_T:
		case OBJECT_T:
		case XOBJECT_T:
		case STRING_T:
			grammaraddr++;
			break;

		case ASTERISK_T:
		case ATTR_T:
			grammaraddr += 2;
			break;

		case DICTENTRY_T:
		case ROUTINE_T:
		case OBJECTNUM_T:
			grammaraddr += 3;
			break;

		case OPEN_BRACKET_T:
			grammaraddr +=5;
			break;
	}
}


/* ANYOBJWORD

	For when it's only necessary to know if word[wn] is an object word for
	any object, not a particular object.  Returns 1 for an object word or -1
	for a non-object word.
*/

int AnyObjWord(int wn)
{
	int i;
	
	if (objword_cache[wn])
		return objword_cache[wn];

	for (i=0; i<objects; i++)
	{
		if (ObjWord(i, wd[wn]))
		{
			return (objword_cache[wn] = 1);
		}
	}

	return (objword_cache[wn] = -1);
}


/* AVAILABLE

	The non_grammar argument is true when called from a non-
	grammar function such as RunEvents().
*/

int Available(int obj, char non_grammar)
{
	int temp_stack_depth;

	if (findobjectaddr)
	{
		passlocal[0] = obj;

		/* if anything or (Routine) grammar */
		if ((Peek(grammaraddr)==ANYTHING_T
			|| (Peek(grammaraddr)==OPEN_BRACKET_T && Peek(grammaraddr+1)==ROUTINE_T))
			&& non_grammar==0)
		{
			passlocal[1] = 0;
		}
		else
		{
			if (domain > 0)
				passlocal[1] = domain;
			else if (speaking && non_grammar==0)
				passlocal[1] = GrandParent(speaking);
			/* domain of -1 is an explicit 'parent' */
/*
			else if (domain==-1)
				passlocal[1] = parse_location;
*/
			else
				passlocal[1] = parse_location;
		}

		ret = 0;

		PassLocals(2);
		temp_stack_depth = stack_depth;

		SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0);

#if defined (DEBUGGER)
		DebugRunRoutine((long)findobjectaddr*address_scale);
#else
		RunRoutine((long)findobjectaddr*address_scale);
#endif
		retflag = 0;
		stack_depth = temp_stack_depth;
		return ret;
	}
	else
		return 1;
}


/* CALLLIBRARYPARSE */

void CallLibraryParse(void)
{
	if (parseaddr)
	{
#ifdef DEBUG_PARSER
		Printout("CallLibraryParse()");
#endif
		parse_called_twice = false;

		SetStackFrame(RESET_STACK_DEPTH, RUNROUTINE_BLOCK, 0, 0);

		ret = 0;
		PassLocals(0);
#if defined (DEBUGGER)
		DebugRunRoutine((long)parseaddr*address_scale);
#else
		RunRoutine((long)parseaddr*address_scale);
#endif
		retflag = 0;

		/* Returning non-zero return calls the
		   engine's Parse routine again.
		*/
		if (ret)
		{
			parse_called_twice = true;
			Parse();
		}
#ifdef DEBUG_PARSER
		if (ret)
			Printout("CallLibraryParse() returned true");
		else
			Printout("CallLibraryParse() returned false");
#endif
	}
}


/* DOMAINOBJ

	Takes into account the preset domain for checking an object's
	presence; <domain> is 0, -1, or an object number..
*/

int DomainObj(int obj)
{
	int yes = false;

	if (obj != var[actor])
	{
		switch (domain)
		{
			case 0:
			case -1:
			{
				if (Parent(obj)==parse_location)
					yes = true;
				else if ((parse_allflag) && GrandParent(obj)==parse_location)
					yes = true;
				else
				{
					if (Parent(obj)==parse_location && !InList(Parent(obj)))
						yes = true;
				}

				if (Peek(grammaraddr)==MULTINOTHELD_T)
				{
					if (Parent(obj)==var[actor])
						yes = false;
				}
				break;
			}

			default:
			{
				if (Parent(obj)==domain)
					yes = true;
			}
		}
	}

	return yes;
}


/* FINDWORD

	Returns the dictionary address of <a>.
*/

unsigned int FindWord(char *a)
{
	unsigned int ptr = 0;
	int i, p, alen;

	if (a[0]=='\0')
		return 0;

	alen = strlen(a);

	defseg = dicttable;

	for (i=1; i<=dictcount; i++)
	{
		if (alen==(p = Peek(ptr+2)) && (unsigned char)(MEM(dicttable*16L+ptr+3)-CHAR_TRANSLATION)==(unsigned char)a[0])
		{
			if (!strcmp(GetString(ptr + 2), a))
			{
				defseg = gameseg;
				return ptr;
			}
		}

		ptr += (p + 1);
	}
	
	/* As a last resort, see if the first 6 characters of the word (if it
	   has at least six characters) match a dictionary word:
	*/
	if (alen >= 6)
	{
		unsigned int possible = 0;
		int posscount = 0;

		ptr = 0;
	
		for (i=1; i<=dictcount; i++)
		{
			if (alen<=(p = Peek(ptr+2)) && (unsigned char)MEM(dicttable*16L+ptr+3)-CHAR_TRANSLATION==a[0])
			{
				if (!strncmp(GetString(ptr + 2), a, alen))
				{
					/* As long as the dictionary word 
					   doesn't contain a space */
					if (!strrchr(GetString(ptr+2), ' '))
					{
						possible = ptr;
						posscount++;
					}
				}
			}
			ptr += (p + 1);
		}
		
		if (posscount==1)
			return possible;
	}

	defseg = gameseg;

	return UNKNOWN_WORD;                    /* not found */
}


/* INLIST

	Checks to see if <obj> is in objlist[].
*/

int InList(int obj)
{
	int i;

	for (i=0; i<objcount; i++)
	{
		if (objlist[i]==obj)
			return true;

Lines 1–500 of 2874.