[Scummvm-git-logs] scummvm master -> abb7b22b2e4a9bd24058e0221c85680aed71d03f

dreammaster paulfgilbert at gmail.com
Sat May 11 05:20:07 CEST 2019


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
abb7b22b2e GLK: HUGO: Add heexpr


Commit: abb7b22b2e4a9bd24058e0221c85680aed71d03f
    https://github.com/scummvm/scummvm/commit/abb7b22b2e4a9bd24058e0221c85680aed71d03f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-11T13:19:52+10:00

Commit Message:
GLK: HUGO: Add heexpr

Changed paths:
  A engines/glk/hugo/heexpr.cpp
    engines/glk/hugo/hemisc.cpp
    engines/glk/hugo/hugo.cpp
    engines/glk/hugo/hugo.h
    engines/glk/module.mk


diff --git a/engines/glk/hugo/heexpr.cpp b/engines/glk/hugo/heexpr.cpp
new file mode 100644
index 0000000..b0865e4
--- /dev/null
+++ b/engines/glk/hugo/heexpr.cpp
@@ -0,0 +1,1240 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/hugo/hugo.h"
+
+namespace Glk {
+namespace Hugo {
+
+int Hugo::EvalExpr(int p) {
+	int n1, n2;
+	int oper;
+	short result = 0;		/* must be 16 bits */
+
+	/* for precedence stacking/unstacking */
+	int next_prec, this_prec, temp_lp;
+
+	if (!evalcount) return 0;       /* no expression */
+
+	do
+	{
+		if (eval[p]==1)
+		{
+			if (eval[p+1]==OPEN_BRACKET_T ||
+				eval[p+1]==OPEN_SQUARE_T)
+			{
+				eval[p] = 0;
+				eval[p+1] = EvalExpr(p+2);
+				TrimExpr(p+2);
+			}
+			else if (eval[p+1]==MINUS_T)
+			{
+				TrimExpr(p);
+				eval[p+1] = -eval[p+1];
+			}
+		}
+
+		if (evalcount<=p+2)
+		{
+			result = eval[p+1];
+			TrimExpr(p);
+			eval[p] = 0;
+			eval[p+1] = result;
+			goto ReturnResult;
+		}
+
+		n1 = eval[p+1];
+		oper = eval[p+3];
+
+		/* At this point, <n1> holds the first value, and <oper> holds
+		   the token number of the operator.
+		*/
+		if (eval[p+4]==1 && (eval[p+5]==OPEN_BRACKET_T
+			|| eval[p+5]==OPEN_SQUARE_T))
+		{
+			eval[p+4] = 0;
+			eval[p+5] = EvalExpr(p+6);
+			TrimExpr(p+6);
+		}
+
+		n2 = eval[p+5];
+
+		if (evalcount > p+7)
+		{
+			if (eval[p+3]==CLOSE_BRACKET_T && eval[p+2]==1)
+			{
+				TrimExpr(p+2);
+				return eval[p+1];
+			}
+
+			/* eval[p+7] holds the next operator, i.e., the "*"
+			   in:  "x + y * z"
+
+			   This way, we can check if the upcoming operator
+			   takes precedence over the current one.
+			*/
+			if ((next_prec = Precedence(eval[p+7]))
+				< (this_prec = Precedence(oper)))
+			{
+				if (next_prec >= last_precedence)
+				{
+#if defined (DEBUG_PRECEDENCE)
+sprintf(line, "Not preferring %s to %s because of previous level %d", token[eval[p+7]], token[oper], last_precedence);
+Printout(line);
+#endif
+					goto ReturnResult;
+				}
+
+#if defined (DEBUG_PRECEDENCE)
+sprintf(line, "Preferring %s to %s", token[eval[p+7]], token[oper]);
+Printout(line);
+#endif
+
+				temp_lp = last_precedence;
+				last_precedence = this_prec;
+				n2 = EvalExpr(p+4);
+				last_precedence = temp_lp;
+			}
+		}
+		else if (Precedence(oper)>=last_precedence)
+		{
+			goto ReturnResult;
+		}
+
+#if defined (DEBUG_PRECEDENCE)
+sprintf(line, "Solving %d %s %d", n1, token[oper], n2);
+Printout(line);
+#endif
+
+		switch (oper)
+		{
+			case DECIMAL_T:
+			{
+				result = GetProp(n1, n2, 1, 0);
+				break;
+			}
+
+			case EQUALS_T:
+			{
+				result = (n1==n2);
+				break;
+			}
+			case MINUS_T:
+			{
+				result = n1 - n2;
+				break;
+			}
+			case PLUS_T:
+			{
+				result = n1 + n2;
+				break;
+			}
+			case ASTERISK_T:
+			{
+				result = n1 * n2;
+				break;
+			}
+			case FORWARD_SLASH_T:
+			{
+				if (n2==0)
+#if defined (DEBUGGER)
+				{
+					RuntimeWarning("Division by zero:  invalid result");
+					result = 0;
+				}
+#else
+					FatalError(DIVIDE_E);
+#endif
+				result = n1 / n2;
+				break;
+			}
+			case PIPE_T:
+			{
+				result = n1 | n2;
+				break;
+			}
+			case GREATER_EQUAL_T:
+			{
+				result = (n1>=n2);
+				break;
+			}
+			case LESS_EQUAL_T:
+			{
+				result = (n1<=n2);
+				break;
+			}
+			case NOT_EQUAL_T:
+			{
+				result = (n1!=n2);
+				break;
+			}
+			case AMPERSAND_T:
+			{
+				result = n1 & n2;
+				break;
+			}
+			case GREATER_T:
+			{
+				result = (n1 > n2);
+				break;
+			}
+			case LESS_T:
+			{
+				result = (n1 < n2);
+				break;
+			}
+			case AND_T:
+			{
+				result = (n1 && n2);
+				break;
+			}
+			case OR_T:
+			{
+				result = (n1 || n2);
+				break;
+			}
+
+			default:
+			{
+				result = n1;
+			}
+		}
+
+#if defined (DEBUGGER)
+		if ((debug_eval) && debug_eval_error) return 0;
+#endif
+
+		TrimExpr(p+4);          /* second value */
+		TrimExpr(p+2);          /* operator */
+
+		eval[p] = 0;
+		eval[p+1] = result;
+
+
+	/* Keep looping while there are expression elements, or until there
+	   is a ")", "]", or end of line
+	*/
+	} while ((evalcount>p+2) && !(eval[p+2]==1 &&
+		(eval[p+3]==CLOSE_BRACKET_T || eval[p+3]==CLOSE_SQUARE_T ||
+		eval[p+3]==255)));
+
+	result = eval[p+1];
+
+	TrimExpr(p);                    /* first value */
+
+ReturnResult:
+
+#if defined (DEBUG_EXPR_EVAL)
+	if (p==0 && exprt)
+	{
+		sprintf(line, " = %d", result);
+		AP(line);
+	}
+#endif
+	return result;
+}
+
+int Hugo::GetVal() {
+	char a = 0;
+	char tempinexpr, tempgetaddress, tempinobj;
+	int i, j;
+	int tempret;
+
+	unsigned short routineaddr, arrayaddr;	/* must be 16 bits */
+	short val = 0;
+
+	char inctype = 0;
+	int preincdec;                  /* pre-increment/decrement */
+
+	defseg = gameseg;
+
+	tempret = ret;
+	tempinexpr = inexpr;
+	inexpr = 0;
+
+	preincdec = incdec;
+	incdec = 0;
+
+	switch (MEM(codeptr))
+	{
+		case AMPERSAND_T:       /* an address */
+			{codeptr++;
+			getaddress = true;
+			val = GetValue();
+			getaddress = false;
+			break;}
+
+		case ROUTINE_T:
+		case CALL_T:
+		{
+			if (MEM(codeptr)==ROUTINE_T)
+			{
+				if (tail_recursion==0 && MEM(codeptr-1)==RETURN_T)
+				{
+					/* We may be able to tail-recurse this return
+					   statement if it's simply 'return Routine(...)'
+					*/
+					tail_recursion = TAIL_RECURSION_ROUTINE;
+				}
+
+				routineaddr = PeekWord(++codeptr);
+				codeptr += 2;
+
+				if (getaddress)
+					{val = routineaddr;
+					getaddress = false;
+					break;}
+			}
+			else
+			{
+				codeptr++;
+				routineaddr = GetValue();
+			}
+
+#if defined (DEBUGGER)
+			if (debug_eval)
+			{
+				debug_eval_error = true;
+				val = 0;
+				break;
+			}
+#endif
+                        val = CallRoutine(routineaddr);
+
+			break;
+		}
+
+		case OPEN_BRACKET_T:
+		{
+			codeptr++;
+			inexpr = 1;
+			tempgetaddress = getaddress;
+			getaddress = false;
+			SetupExpr();
+			inexpr = 0;
+			val = EvalExpr(0);
+			getaddress = tempgetaddress;
+			break;
+		}
+
+		case MINUS_T:
+		{
+			codeptr++;
+			j = inexpr;	/* don't reuse tempinexpr */
+			inexpr = 1;
+			val = -GetValue();
+			inexpr = (char)j;
+			break;
+		}
+
+		case VALUE_T:                   /* integer 0 - 65535 */
+		case OBJECTNUM_T:
+		case DICTENTRY_T:
+		{
+			val = PeekWord(++codeptr);
+			codeptr += 2;
+			break;
+		}
+
+		case ATTR_T:
+		case PROP_T:
+		{
+			val = MEM(++codeptr);
+			codeptr++;
+			break;
+		}
+
+		case VAR_T:                     /* variable */
+		{
+			val = var[(i=MEM(++codeptr))];
+
+			if (game_version >= 22)
+			{
+				/* Pre-v2.4 included linelength and pagelength as
+				   global variables after objectcount
+				*/
+				if (i <= ((game_version>=24)?objectcount:objectcount+2))
+				{
+					if (i==wordcount) val = words;
+					else if (i==objectcount) val = objects;
+
+					/* i.e., pre-v2.4 only */
+					else if (i==objectcount+1)
+					{
+#if defined (ACTUAL_LINELENGTH)
+						val = ACTUAL_LINELENGTH();
+#else
+						val = SCREENWIDTH/charwidth;
+#endif
+					}
+					else if (i==objectcount+2)
+						val = SCREENHEIGHT/lineheight;
+				}
+			}
+			codeptr++;
+
+			if (!inobj) inctype = IsIncrement(codeptr);
+
+			/* don't operate on, e.g., ++variable.property as
+			   (++variable).property
+			*/
+			if ((incdec || preincdec) && MEM(codeptr)!=DECIMAL_T)
+			{
+				if (i < MAXGLOBALS) SaveUndo(VAR_T, i, val, 0, 0);
+
+				if (inctype) val = Increment(val, inctype);
+
+				/* still a post-increment hanging around */
+				var[i] = (val+=preincdec) + incdec;
+
+				incdec = preincdec = 0;
+			}
+
+			break;
+		}
+
+		case TRUE_T:
+			val = 1;
+			codeptr++;
+			break;
+
+		case FALSE_T:
+			val = 0;
+			codeptr++;
+			break;
+
+		case TILDE_T:
+			codeptr++;
+			val = ~GetValue();
+			break;
+
+		case NOT_T:
+			codeptr++;
+			val = !GetValue();
+			break;
+
+		case ARRAYDATA_T:
+		case ARRAY_T:
+		{
+			unsigned int element;
+
+			if (MEM(codeptr)==ARRAY_T)
+			{
+				codeptr++;
+				arrayaddr = GetValue();
+			}
+			else
+			{
+				arrayaddr = PeekWord(++codeptr);
+				codeptr += 2;
+			}
+
+			if (MEM(codeptr)!=OPEN_SQUARE_T)
+				{val = arrayaddr;
+				break;}
+
+			if (game_version>=22)
+			{
+				/* convert to word value */
+				arrayaddr*=2;
+
+				if (game_version>=23)
+					/* space for array length */
+					a = 2;
+			}
+
+			/* check if this is array[] (i.e., array length) */
+			if (MEM(++codeptr)==CLOSE_SQUARE_T)
+			{
+				defseg = arraytable;
+				val = PeekWord(arrayaddr);
+				codeptr++;
+				break;
+			}
+
+			tempinobj = inobj;
+			inobj = 0;
+			j = GetValue();
+			inobj = tempinobj;
+
+			/* The array element we're after: */
+			element = arrayaddr+a + j*2;
+			
+			defseg = arraytable;
+#if defined (DEBUGGER)
+			CheckinRange(element, debug_workspace, "array data");
+#endif
+			/* Check to make sure we've got a sane element number */
+			if ((element>0) && (element < (unsigned int)(dicttable-arraytable)*16))
+				val = PeekWord(element);
+			else
+				val = 0;
+			codeptr++;
+
+			if (!inobj) inctype = IsIncrement(codeptr);
+
+			/* Don't operate on the array on:
+
+				 ++a[n].property
+			*/
+			if ((incdec || preincdec) && MEM(codeptr)!=DECIMAL_T)
+			{
+				/* Same sanity check for element number */
+				if ((element>0) && (element < (unsigned)(dicttable-arraytable)*16))
+				{
+					if (inctype) val = Increment(val, inctype);
+
+					/* still a post-increment hanging around */
+					SaveUndo(ARRAYDATA_T, arrayaddr+a, j, val, 0);
+
+					PokeWord(element, (val+=preincdec) + incdec);
+
+					incdec = preincdec = 0;
+				}
+			}
+
+			break;
+		}
+
+		case RANDOM_T:
+		{
+			codeptr += 2;           /* skip the "(" */
+			val = GetValue();
+			if (val!=0) 
+#if !defined (RANDOM)
+				val = (hugo_rand() % val)+1;
+#else
+				val = (RANDOM() % val)+1;
+#endif
+			if (MEM(codeptr)==2) codeptr++;
+			break;
+		}
+
+		case WORD_T:
+		{
+			codeptr += 2;           /* skip the "[" */
+
+			if (MEM(codeptr)==CLOSE_SQUARE_T)	/* words[] */
+			{
+				val = words;
+				break;
+			}
+			
+			val = wd[GetValue()];
+			if (MEM(codeptr)==CLOSE_SQUARE_T) codeptr++;
+			break;
+		}
+
+		case CHILDREN_T:
+		{
+			codeptr += 2;        /* skip the "(" */
+			val = GetValue();
+			if (MEM(codeptr)==CLOSE_BRACKET_T) codeptr++;
+			val = Children(val);
+			break;
+		}
+
+		case PARENT_T:
+		case SIBLING_T:
+		case CHILD_T:
+		case YOUNGEST_T:
+		case ELDEST_T:
+		case YOUNGER_T:
+		case ELDER_T:
+		{
+			i = MEM(codeptr);
+			codeptr += 2;         /* skip the "(" */
+			val = GetValue();
+			if (MEM(codeptr)==CLOSE_BRACKET_T) codeptr++;
+
+			switch (i)
+			{
+				case PARENT_T:
+					val = Parent(val);
+					break;
+
+				case SIBLING_T:
+				case YOUNGER_T:
+					val = Sibling(val);
+					break;
+
+				case CHILD_T:
+				case ELDEST_T:
+					val = Child(val);
+					break;
+
+				case YOUNGEST_T:
+					val = Youngest(val);
+					break;
+
+				case ELDER_T:
+					val = Elder(val);
+					break;
+			}
+			break;
+		}
+
+		case SAVE_T:
+			val = RunSave();
+			codeptr++;
+			break;
+
+		case RESTORE_T:
+			val = RunRestore();
+			codeptr++;
+			break;
+
+		case SCRIPTON_T:
+		case SCRIPTOFF_T:
+			val = RunScriptSet();
+			codeptr++;
+			break;
+
+		case RESTART_T:
+			val = RunRestart();
+			codeptr++;
+			break;
+
+		case STRING_T:
+			val = RunString();
+			break;
+
+		case UNDO_T:
+			val = Undo();
+			codeptr++;
+			break;
+
+		case DICT_T:
+			val = Dict();
+			if (MEM(codeptr)==CLOSE_BRACKET_T) codeptr++;
+			break;
+
+		case RECORDON_T:
+		case RECORDOFF_T:
+		case PLAYBACK_T:
+			val = RecordCommands();
+			codeptr++;
+			break;
+
+		case READVAL_T:
+		{
+			val = 0;
+			if (ioblock)
+			{
+#ifdef TODO
+				int low, high;
+
+				if ((ioblock==1)
+					|| (low = hugo_fgetc(io))==EOF
+					|| (high = hugo_fgetc(io))==EOF)
+				{
+					ioerror = true;
+					retflag = true;
+				}
+				else val = low + high*256;
+#else
+				error("TODO: file io");
+#endif
+			}
+			codeptr++;
+			break;
+		}
+
+		case PARSE_T:
+		{
+			val = (short)PARSE_STRING_VAL;
+			codeptr++;
+			break;
+		}
+
+		case SERIAL_T:
+		{
+			val = (short)SERIAL_STRING_VAL;
+			codeptr++;
+			break;
+		}
+		
+		case SYSTEM_T:
+		{
+			val = RunSystem();
+			codeptr++;
+			break;
+		}
+		
+		default:
+		{
+#if defined (DEBUGGER)
+			if (debug_eval)
+				debug_eval_error = true;
+			else
+#endif
+
+			FatalError(EXPECT_VAL_E);
+
+#if defined (DEBUGGER)
+			runtime_error = true;
+			codeptr++;
+			return 0;
+#endif
+		}
+	}
+	defseg = gameseg;
+	ret = tempret;
+	inexpr = tempinexpr;
+
+	incdec = preincdec;
+
+	return val;
+}
+
+int Hugo::GetValue() {
+	char noself = 0;
+	int p, n;
+	char inctype; int preincdec;
+	int nattr = 0, attr;
+	unsigned int pa, val;
+	long tempptr;
+	short g;			/* must be 16 bits */
+	int potential_tail_recursion = 0;
+
+	/* Check to see if this may be a valid tail-recursion */
+	if (tail_recursion==0 && MEM(codeptr-1)==RETURN_T)
+	{
+		/* We may be able to tail-recurse this return statement if
+		   it's simply 'return object.property[.property...]'
+		*/
+		potential_tail_recursion = TAIL_RECURSION_PROPERTY;
+	}
+
+	IsIncrement(codeptr);           /* check for ++, -- */
+
+	tempptr = codeptr;
+	g = GetVal();
+
+	preincdec = incdec;
+	incdec = 0;
+
+	if (inobj==0)
+	{
+	  switch (MEM(codeptr))
+	  {
+		case DECIMAL_T:                         /* object.property */
+		{
+DetermineProperty:
+			if (MEM(++codeptr)==DECIMAL_T)  /* object..property */
+			{
+				noself = true;
+				codeptr++;
+			}
+
+			if (MEM(codeptr)==POUND_T)      /* object.#property */
+			{
+				codeptr++;
+				inobj = true;
+				p = GetValue();
+				inobj = false;
+				pa = PropAddr(g, p, 0);
+				if (pa)
+				{
+					defseg = proptable;
+					g = Peek(pa + 1);
+					if (g==PROP_ROUTINE) g = 1;
+					defseg = gameseg;
+				}
+				else
+					g = 0;
+			}
+			else
+			{
+				inobj = true;
+				p = GetValue();
+				inobj = false;
+
+				if (MEM(codeptr) != POUND_T)
+					n = 1;
+
+				else		/* object.property #x */
+				{
+					codeptr++;
+
+					/* Not GetValue(), since that might
+					   botch "obj.property #n is attr"
+					*/
+					n = GetVal();
+				}
+
+				/* We checked this at the start of the function, but
+				   GetValue() for the property would've cleared it
+				*/
+				tail_recursion = potential_tail_recursion;
+
+				val = GetProp(g, p, n, noself);
+
+				inctype = IsIncrement(codeptr);
+
+				/* Increment/decrement an object.property, although
+				   only if this is the last property in, e.g.,
+				   object.property.property...
+				*/
+				if ((incdec || preincdec) && MEM(codeptr)!=DECIMAL_T)
+				{
+					SaveUndo(PROP_T, g, p, n, val);
+
+					if (inctype) val = Increment(val, inctype);
+
+					/* Still a post-increment hanging around */
+					pa = PropAddr(g, p, 0);
+					defseg = proptable;
+
+					/* Only change it if not a routine */
+					if (Peek(pa+1)!=PROP_ROUTINE)
+						PokeWord(pa+n*2, (val+=preincdec)+incdec);
+
+					defseg = gameseg;
+
+					incdec = preincdec = 0;
+				}
+				g = val;
+			}
+			if (MEM(codeptr)==IS_T) goto CheckAttribute;
+
+			break;
+		}
+
+		case IS_T:
+		{
+CheckAttribute:
+			if (!inobj)
+			{
+				codeptr++;
+				if (MEM(codeptr)==NOT_T)
+				{
+					nattr = 1;
+					codeptr++;
+				}
+				attr = GetValue();
+#if defined (DEBUGGER)
+				CheckinRange((unsigned)attr, (unsigned)attributes, "attribute");
+#endif
+				g = TestAttribute(g, attr, nattr);
+
+				break;
+			}
+		}
+	  }
+
+	  switch (MEM(codeptr))
+	  {
+		/* This comes here (again) in order to process
+		   object.property1.property2...
+		*/
+		case DECIMAL_T:  goto DetermineProperty;
+
+		case NOT_T:
+			if (!inobj)
+				{nattr = 1;
+				codeptr++;}
+		case IN_T:
+		{
+			if (!inobj)
+			{
+				codeptr++;
+				p = GetValue();          /* testing parent */
+				g = (p==Parent(g));
+				if (nattr)
+					g = !g;
+			}
+		}
+	  }
+	}                                       /* end of "if (inobj==0)" */
+
+	n = MEM(codeptr);
+
+	/* See if we have an implicit expression that needs to be
+	   taken as a single value, i.e., "n + 1" where we've just
+	   read n
+	*/
+	if (((n>=MINUS_T && n<=PIPE_T) || n==AMPERSAND_T) &&
+		((!inexpr)) && !inobj)
+/*
+#if !defined (DEBUGGER)
+		((!inexpr)) && !inobj)
+#else
+		((!inexpr)) && !inobj && !debug_eval)
+#endif
+*/
+	{
+		inexpr = 2;
+		codeptr = tempptr;
+		SetupExpr();
+		g = EvalExpr(0);
+		inexpr = 0;
+	}
+
+	/* Not a tail-recursive 'return object.property' */
+	if (tail_recursion_addr==0)
+		tail_recursion = 0;
+
+	return g;
+}
+
+int Hugo::Increment(int a, char inctype) {
+	short v;			/* must be 16 bits */
+
+	v = a;
+
+	switch (inctype)
+	{
+		case MINUS_T:           {v -= incdec; break;}
+		case PLUS_T:            {v += incdec; break;}
+		case ASTERISK_T:        {v *= incdec; break;}
+		case AMPERSAND_T:       {v &= incdec; break;}
+		case PIPE_T:            {v |= incdec; break;}
+		case FORWARD_SLASH_T:
+		{
+#if defined (DEBUGGER)
+			if (incdec==0)
+			{
+				RuntimeWarning("Division by zero:  invalid result");
+				v = 0;
+			}
+			else
+#endif
+				v /= incdec;
+			break;
+		}
+	}
+
+	if (inctype!=1) incdec = 0;
+
+	return v;
+}
+
+char Hugo::IsIncrement(long addr) {
+	unsigned char a, t = 0;
+
+	incdec = 0;
+
+	switch (a = MEM(addr))
+	{
+		case MINUS_T:
+		case PLUS_T:
+		case ASTERISK_T:
+		case FORWARD_SLASH_T:
+		case AMPERSAND_T:
+		case PIPE_T:
+		{
+			/* ++, -- */
+			if ((a==MINUS_T || a==PLUS_T) && MEM(addr+1)==a)
+			{
+				codeptr = addr + 2;
+				if (a==PLUS_T) incdec = 1;
+				else incdec = -1;
+				t = 1;
+				break;
+			}
+
+			/* +=, -=, etc. */
+			else if (MEM(addr+1)==EQUALS_T)
+			{
+				codeptr = addr + 2;
+				incdec = GetValue();
+				t = a;
+			}
+		}
+	}
+
+#if defined (DEBUGGER)
+	if (t && debug_eval)
+	{
+		debug_eval_error = true;
+		sprintf(debug_line, "'%s%s' illegal in watch/assignment", token[a], token[MEM(addr+1)]);
+		DebugMessageBox("Expression Error", debug_line);
+		t = 0;
+	}
+#endif
+	return t;
+}
+
+int Hugo::Precedence(int t) {
+	switch (t)
+	{
+		case DECIMAL_T:
+			return 1;
+
+		case ASTERISK_T:
+		case FORWARD_SLASH_T:
+			return 2;
+
+		case MINUS_T:
+		case PLUS_T:
+			return 3;
+
+		case PIPE_T:
+		case TILDE_T:
+		case AMPERSAND_T:
+			return 4;
+
+		case EQUALS_T:
+		case GREATER_EQUAL_T:
+		case LESS_EQUAL_T:
+		case NOT_EQUAL_T:
+		case GREATER_T:
+		case LESS_T:
+			return 5;
+
+		default:
+			return 6;
+	}
+}
+
+#if defined (DEBUG_EXPR_EVAL)
+/* PRINTEXPR
+
+Prints the current expression during expression tracing.
+*/
+void PrintExpr(void)
+{
+	char e[261];
+	int i, bracket = 0;
+
+	if (!evalcount) return;
+
+	strcpy(e, "( ");
+	for (i=0; i<=evalcount; i+=2)
+	{
+		switch (eval[i])
+		{
+			case 0:
+			{
+				sprintf(line, "%d ", eval[i + 1]);
+				strcat(e, line);
+				break;
+			}
+			case 1:
+			{
+				if (eval[i+1]==OPEN_BRACKET_T) bracket++;
+				if (eval[i+1]==CLOSE_BRACKET_T)
+					{bracket--;
+					if (bracket<0) goto ExitPrintExpr;}
+
+				if (token[eval[i+1]][0]=='~')
+					strcat(e, "\\");
+				if (eval[i+1] != 255)
+					{sprintf(line, "%s ", token[eval[i+1]]);
+					strcat(e, line);}
+				break;
+			}
+		}
+	}
+
+ExitPrintExpr:
+	strcat(e, ")\\;");
+
+	AP(e);
+}
+#endif
+
+void Hugo::SetupExpr() {
+	char justgotvalue = 1;
+	int j, t, bracket = 0;
+	int tempret;
+	int tempeval[MAX_EVAL_ELEMENTS];
+	int tempevalcount;
+
+	last_precedence = 10;
+
+	tempret = ret;
+	tempevalcount = 0;
+
+	inobj = false;
+	if (!inexpr) inexpr = 1;
+
+	do
+	{
+		justgotvalue++;
+
+		switch (t = MEM(codeptr))
+		{
+			/* Various indications that we've hit the
+			   end of the expression:
+			*/
+			case EOL_T:
+				arrexpr = false;
+			case COMMA_T:
+				multiprop = false;
+			case SEMICOLON_T:
+			case CLOSE_SQUARE_T:
+			case JUMP_T:
+			{
+				if (t==EOL_T || t==COMMA_T || t==JUMP_T)
+					codeptr++;
+LeaveSetupExpr:
+				for (j=0; j<tempevalcount; j++)
+					eval[j] = tempeval[j];
+				evalcount = tempevalcount;
+
+				eval[evalcount] = 1;
+				eval[evalcount + 1] = 255;
+
+#if defined (DEBUG_EXPR_EVAL)
+				if (exprt) PrintExpr();
+#endif
+
+				ret = tempret;
+				return;
+			}
+
+
+			/* Otherwise we have a value: */
+
+			case OPEN_BRACKET_T:
+
+			case MINUS_T:
+			case PLUS_T:
+			case TILDE_T:
+			case AMPERSAND_T:
+			case NOT_T:
+
+			case PARENT_T:
+			case SIBLING_T:
+			case CHILD_T:
+			case YOUNGEST_T:
+			case ELDEST_T:
+			case YOUNGER_T:
+			case ELDER_T:
+			case CHILDREN_T:
+			case RANDOM_T:
+			case SYSTEM_T:
+
+			case PROP_T:
+			case ATTR_T:
+			case VAR_T:
+			case DICTENTRY_T:
+			case ROUTINE_T:
+			case OBJECTNUM_T:
+			case VALUE_T:
+
+			case ARRAYDATA_T:
+			case ARRAY_T:
+			case WORD_T:
+
+			case CALL_T:
+
+			case SAVE_T:
+			case RESTORE_T:
+			case SCRIPTON_T:
+			case SCRIPTOFF_T:
+			case RESTART_T:
+			case UNDO_T:
+			case READVAL_T:
+
+			case STRING_T:
+			case DICT_T:
+
+			case PARSE_T:
+			case SERIAL_T:
+			{
+				if ((t==AMPERSAND_T || t==MINUS_T ||
+					t==PLUS_T) && justgotvalue==1)
+					goto SomeSymbolorToken;
+
+				tempeval[tempevalcount] = 0;
+				tempeval[tempevalcount + 1] = GetValue();
+
+#if defined (DEBUGGER)
+				if ((debug_eval) && debug_eval_error)
+					return;
+#endif
+
+				tempevalcount += 2;
+				if (tempevalcount > MAX_EVAL_ELEMENTS-2)
+					FatalError(OVERFLOW_E);
+
+				justgotvalue = 0;
+
+				break;
+			}
+
+			/* Logical constants */
+			case TRUE_T:
+			case FALSE_T:
+			{
+				tempeval[tempevalcount] = 0;
+				if (Peek(codeptr)==TRUE_T)
+					tempeval[tempevalcount + 1] = 1;
+				else
+					tempeval[tempevalcount + 1] = 0;
+
+				codeptr++;
+
+				tempevalcount += 2;
+				if (tempevalcount > MAX_EVAL_ELEMENTS-2)
+					FatalError(OVERFLOW_E);
+
+				break;
+			}
+
+			/* Some symbol or token */
+			default:
+			{
+SomeSymbolorToken:
+				tempeval[tempevalcount] = 1;
+				tempeval[tempevalcount + 1] = MEM(codeptr++);
+
+				tempevalcount += 2;
+				if (tempevalcount > MAX_EVAL_ELEMENTS-2)
+					FatalError(OVERFLOW_E);
+
+				switch (MEM(codeptr-1))
+				{
+					case OPEN_BRACKET_T:
+						{bracket++;
+						break;}
+					case CLOSE_BRACKET_T:
+						{bracket--;
+						justgotvalue = 0;
+						if (inexpr==2)
+							codeptr--;}
+				}
+				if (bracket < 0) goto LeaveSetupExpr;
+
+				break;
+			}
+		}
+	}
+	while (true);                      /* endless loop */
+}
+
+void Hugo::TrimExpr(int ptr) {
+	int i;
+
+	for (i=ptr; i<=evalcount; i+=2)
+	{
+		eval[i] = eval[i+2];
+		eval[i+1] = eval[i+3];
+	}
+	evalcount -= 2;
+}
+
+} // End of namespace Hugo
+} // End of namespace Glk
diff --git a/engines/glk/hugo/hemisc.cpp b/engines/glk/hugo/hemisc.cpp
index 696b7a2..9e56057 100644
--- a/engines/glk/hugo/hemisc.cpp
+++ b/engines/glk/hugo/hemisc.cpp
@@ -978,7 +978,7 @@ char *Hugo::GetText(long textaddr) {
 }
 
 const char *Hugo::GetWord(unsigned int w) {
-	static char *b;
+	static const char *b;
 	unsigned short a;
 
 	a = w;
diff --git a/engines/glk/hugo/hugo.cpp b/engines/glk/hugo/hugo.cpp
index dccf978..60d27ae 100644
--- a/engines/glk/hugo/hugo.cpp
+++ b/engines/glk/hugo/hugo.cpp
@@ -68,7 +68,7 @@ Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam
 		debugger_finish(false), debugger_run(false), debugger_interrupt(false),
 		debugger_skip(false), runtime_error(false), currentroutine(false),
 		complex_prop_breakpoint(false), trace_complex_prop_routine(false), routines(0),
-		properties(0), current_locals(0), this_codeptr(0)
+		properties(0), current_locals(0), this_codeptr(0), debug_workspace(0), attributes(0)
 #endif
 		{
 	// heexpr
@@ -103,8 +103,8 @@ Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam
 
 #ifdef DEBUGGER
 	debug_line[0] = '\0';
-	Common::fill(&objectname[0], &objectname[MAX_OBJECT], nullptr);
-	Common::fill(&propertyname[0], &propertyname[MAX_PROPERTY], nullptr);
+	Common::fill(&objectname[0], &objectname[MAX_OBJECT], (char *)nullptr);
+	Common::fill(&propertyname[0], &propertyname[MAX_PROPERTY], (char *)nullptr);
 	Common::fill(&codeline[0][0], &codeline[9][100], 0);
 	Common::fill(&localname[0][0], &localname[9][100], 0);
 #endif
diff --git a/engines/glk/hugo/hugo.h b/engines/glk/hugo/hugo.h
index a1e2c29..76983ad 100644
--- a/engines/glk/hugo/hugo.h
+++ b/engines/glk/hugo/hugo.h
@@ -237,9 +237,72 @@ private:
 	char localname[9][100];
 	int current_locals;
 	long this_codeptr;
+	int debug_workspace;
+	int attributes;
 #endif
 private:
 	/**
+	 * \defgroup heexpr
+	 * @{
+	 */
+
+	 /**
+	  * The new-and-improved expression evaluator.  Evaluates the current expression
+	  * (or sub-expression therein) beginning at eval[p].
+	  */
+	int EvalExpr(int p);
+
+	/**
+	 * Called by GetValue(); does the actual dirty work of returning a value from a
+	 * simple data type.
+	 */
+	int GetVal();
+
+	/**
+	 * Does any reckoning for more sophisticated constructions.
+	 */
+	int GetValue();
+
+	/**
+	 * Actually performs the increment given below by IsIncrement.
+	 */
+	int Increment(int a, char inctype);
+
+	/**
+	 * If an increment/decrement is next up (i.e. ++, --, or +=, *=, etc.),
+	 * then sets incdec equal to the increment/decrement and repositions codeptr.
+	 * Returns the token number of the operation, if any.
+	 */
+	char IsIncrement(long addr);
+
+	/**
+	 *  Returns the precedence ranking of the operator represented by token[t].
+	 * The lower the return value, the higher the rank in terms of processing order.
+	 */
+	int Precedence(int t);
+
+	/**
+	 * Reads the current expression from the current code position into eval[],
+	 * using the following key:
+	 *
+	 * if eval[n] is 0, eval[n+1] is a value
+	 * if eval[n] is 1, eval[n+1] is a token
+	 *
+	 * <inexpr> is used in various routines to keep track of whether or not we're currently
+	 * reading an expression.  If <inexpr> is 1, we're in an expression; if 2, we may have
+	 * to step back one code position if encountering a closing parentheses.
+	 */
+	void SetupExpr();
+
+	/**
+	 * Cuts off straggling components of eval[] after an expression or sub-expression
+	 * has been successfully evaluated.
+	 */
+	void TrimExpr(int ptr);
+
+	/**@}*/
+
+	/**
 	 * \defgroup heglk
 	 * @{
 	 */
@@ -660,6 +723,10 @@ private:
 		return s->read(ptr, size * count);
 	}
 
+	uint hugo_rand() {
+		return _random.getRandomNumber(0xffffff);
+	}
+
 	/**@}*/
 private:
 	/**
@@ -695,7 +762,6 @@ public:
 	virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override;
 
 	// TODO: Stubs to be Properly implemented
-	int GetValue() { return 0; }
 	void PlayGame() {}
 	void hugo_closefiles() {}
 	void RunRoutine(long v) {}
@@ -704,6 +770,12 @@ public:
 	void hugo_stopmusic() {}
 	int hugo_hasgraphics() { return 0; }
 	int hugo_writetoscript(const char *s) { return 0; }
+	short RunSave() { return 0; }
+	short RunRestore() { return 0; }
+	short RunScriptSet() { return 0; }
+	short RunRestart() { return 0; }
+	short RunString() { return 0; }
+	short RunSystem() { return 0; }
 };
 
 } // End of namespace Hugo
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 41c53c3..62237b6 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -72,6 +72,7 @@ MODULE_OBJS := \
 	glulxe/string.o \
 	glulxe/vm.o \
 	hugo/detection.o \
+	hugo/heexpr.o \
 	hugo/heglk.o \
 	hugo/hemisc.o \
 	hugo/heobject.o \





More information about the Scummvm-git-logs mailing list