1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/adrift/scare.h"
24 #include "glk/adrift/scprotos.h"
25 #include "glk/jumps.h"
26 
27 namespace Glk {
28 namespace Adrift {
29 
30 /*
31  * Module notes:
32  *
33  * o The tokenizer doesn't differentiate between "&", "&&", and "and", but "&"
34  *   is context sensitive -- either a logical and for numerics, or concaten-
35  *   ation for strings.  As a result, "&&" and "and" also work as string
36  *   concatenators when used in string expressions.  It may not be to spec,
37  *   but we'll call this a "feature".
38  */
39 
40 /* Assorted definitions and constants. */
41 enum { MAX_NESTING_DEPTH = 32 };
42 static const sc_char NUL = '\0';
43 static const sc_char PERCENT = '%';
44 static const sc_char SINGLE_QUOTE = '\'';
45 static const sc_char DOUBLE_QUOTE = '"';
46 
47 
48 /*
49  * Tokens.  Single character tokens are represented by their ascii value
50  * (0-255), others by values above 255.  -1 represents a null token.  Because
51  * '&' and '+' are context sensitive, the pseudo-token TOK_CONCATENATE
52  * serves to indicate string concatenation -- it's never returned by the
53  * tokenizer.
54  */
55 enum {
56 	TOK_NONE = -1,
57 	TOK_ADD = '+', TOK_SUBTRACT = '-', TOK_MULTIPLY = '*', TOK_DIVIDE = '/',
58 	TOK_AND = '&', TOK_OR = '|',
59 	TOK_LPAREN = '(', TOK_RPAREN = ')', TOK_COMMA = ',', TOK_POWER = '^',
60 	TOK_EQUAL = '=', TOK_GREATER = '>', TOK_LESS = '<',
61 
62 	TOK_IDENT = 256,
63 	TOK_INTEGER, TOK_STRING, TOK_VARIABLE, TOK_UMINUS, TOK_UPLUS,
64 	TOK_MOD, TOK_NOT_EQUAL, TOK_GREATER_EQ, TOK_LESS_EQ, TOK_IF,
65 	TOK_MIN, TOK_MAX, TOK_EITHER, TOK_RANDOM, TOK_INSTR, TOK_LEN, TOK_VAL,
66 	TOK_ABS, TOK_UPPER, TOK_LOWER, TOK_PROPER, TOK_RIGHT, TOK_LEFT, TOK_MID,
67 	TOK_STR, TOK_CONCATENATE,
68 	TOK_EOS
69 };
70 
71 /*
72  * Small tables tying multicharacter tokens strings to tokens.  At present,
73  * the string lengths for names are not used.
74  */
75 struct sc_expr_multichar_t {
76 	const sc_char *const name;
77 	const sc_int length;
78 	const sc_int token;
79 };
80 
81 static const sc_expr_multichar_t FUNCTION_TOKENS[] = {
82 	{"either", 6, TOK_EITHER},
83 	{"proper", 6, TOK_PROPER}, {"pcase", 5, TOK_PROPER}, {"instr", 5, TOK_INSTR},
84 	{"upper", 5, TOK_UPPER}, {"ucase", 5, TOK_UPPER},
85 	{"lower", 5, TOK_LOWER}, {"lcase", 5, TOK_LOWER},
86 	{"right", 5, TOK_RIGHT}, {"left", 4, TOK_LEFT},
87 	{"rand", 4, TOK_RANDOM}, {"max", 3, TOK_MAX}, {"min", 3, TOK_MIN},
88 	{"mod", 3, TOK_MOD}, {"abs", 3, TOK_ABS}, {"len", 3, TOK_LEN},
89 	{"val", 3, TOK_VAL}, {"and", 3, TOK_AND}, {"mid", 3, TOK_MID},
90 	{"str", 3, TOK_STR}, {"or", 2, TOK_OR}, {"if", 2, TOK_IF},
91 	{NULL, 0, TOK_NONE}
92 };
93 static const sc_expr_multichar_t OPERATOR_TOKENS[] = {
94 	{"&&", 2, TOK_AND}, {"||", 2, TOK_OR},
95 	{"==", 2, TOK_EQUAL}, {"!=", 2, TOK_NOT_EQUAL},
96 	{"<>", 2, TOK_NOT_EQUAL}, {">=", 2, TOK_GREATER_EQ}, {"<=", 2, TOK_LESS_EQ},
97 	{NULL, 0, TOK_NONE}
98 };
99 
100 
101 /*
102  * expr_multichar_search()
103  *
104  * Multicharacter token table search, returns the matching token, or
105  * TOK_NONE if no match.
106  */
expr_multichar_search(const sc_char * name,const sc_expr_multichar_t * table)107 static sc_int expr_multichar_search(const sc_char *name, const sc_expr_multichar_t *table) {
108 	const sc_expr_multichar_t *entry;
109 
110 	/* Scan the table for a case-independent full string match. */
111 	for (entry = table; entry->name; entry++) {
112 		if (sc_strcasecmp(name, entry->name) == 0)
113 			break;
114 	}
115 
116 	/* Return the token matched, or TOK_NONE. */
117 	return entry->name ? entry->token : (sc_int)TOK_NONE;
118 }
119 
120 
121 /* Tokenizer variables. */
122 static const sc_char *expr_expression = NULL;
123 static sc_int expr_index = 0;
124 static sc_vartype_t expr_token_value;
125 static sc_char *expr_temporary = NULL;
126 static sc_int expr_current_token = TOK_NONE;
127 
128 /*
129  * expr_tokenize_start()
130  * expr_tokenize_end()
131  *
132  * Start and wrap up expression string tokenization.
133  */
expr_tokenize_start(const sc_char * expression)134 static void expr_tokenize_start(const sc_char *expression) {
135 	static sc_bool initialized = FALSE;
136 
137 	/* On first call only, verify the string lengths in the tables. */
138 	if (!initialized) {
139 		const sc_expr_multichar_t *entry;
140 
141 		/* Compare table lengths with string lengths. */
142 		for (entry = FUNCTION_TOKENS; entry->name; entry++) {
143 			if (entry->length != (sc_int) strlen(entry->name)) {
144 				sc_fatal("expr_tokenize_start:"
145 				         " token string length is wrong for \"%s\"\n",
146 				         entry->name);
147 			}
148 		}
149 
150 		for (entry = OPERATOR_TOKENS; entry->name; entry++) {
151 			if (entry->length != (sc_int) strlen(entry->name)) {
152 				sc_fatal("expr_tokenize_start:"
153 				         " operator string length is wrong for \"%s\"\n",
154 				         entry->name);
155 			}
156 		}
157 
158 		initialized = TRUE;
159 	}
160 
161 	/* Save expression, and restart index. */
162 	expr_expression = expression;
163 	expr_index = 0;
164 
165 	/* Allocate a temporary token value/literals string. */
166 	assert(!expr_temporary);
167 	expr_temporary = (sc_char *)sc_malloc(strlen(expression) + 1);
168 
169 	/* Reset last token to none. */
170 	expr_current_token = TOK_NONE;
171 }
172 
expr_tokenize_end(void)173 static void expr_tokenize_end(void) {
174 	/* Deallocate temporary strings, clear expression. */
175 	sc_free(expr_temporary);
176 	expr_temporary = NULL;
177 	expr_expression = NULL;
178 	expr_index = 0;
179 	expr_current_token = TOK_NONE;
180 }
181 
182 
183 /*
184  * expr_next_token_unadjusted()
185  * expr_next_token()
186  *
187  * Return the next token from the current expression.  The initial token may
188  * be adjusted into a unary +/- depending on the value of the previous token.
189  */
expr_next_token_unadjusted(sc_vartype_t * token_value)190 static sc_int expr_next_token_unadjusted(sc_vartype_t *token_value) {
191 	sc_int c;
192 	assert(expr_expression);
193 
194 	/* Skip any and all leading whitespace. */
195 	do {
196 		c = expr_expression[expr_index++];
197 	} while (sc_isspace(c) && c != NUL);
198 
199 	/* Return EOS if at expression end. */
200 	if (c == NUL) {
201 		expr_index--;
202 		return TOK_EOS;
203 	}
204 
205 	/*
206 	 * Identify and return numerics.  We deal only with unsigned numbers here;
207 	 * the unary +/- tokens take care of any integer sign issues.
208 	 */
209 	else if (sc_isdigit(c)) {
210 		sc_int value;
211 
212 		sscanf(expr_expression + expr_index - 1, "%ld", &value);
213 
214 		while (sc_isdigit(c) && c != NUL)
215 			c = expr_expression[expr_index++];
216 		expr_index--;
217 
218 		token_value->integer = value;
219 		return TOK_INTEGER;
220 	}
221 
222 	/* Identify and return variable references. */
223 	else if (c == PERCENT) {
224 		sc_int index_;
225 
226 		/* Copy variable name. */
227 		c = expr_expression[expr_index++];
228 		for (index_ = 0; c != PERCENT && c != NUL;) {
229 			expr_temporary[index_++] = c;
230 			c = expr_expression[expr_index++];
231 		}
232 		expr_temporary[index_++] = NUL;
233 
234 		if (c == NUL) {
235 			sc_error("expr_next_token_unadjusted:"
236 			         " warning: unterminated variable name\n");
237 			expr_index--;
238 		}
239 
240 		/* Return a variable name. */
241 		token_value->string = expr_temporary;
242 		return TOK_VARIABLE;
243 	}
244 
245 	/* Identify and return string literals. */
246 	else if (c == DOUBLE_QUOTE || c == SINGLE_QUOTE) {
247 		sc_int index_;
248 		sc_char quote;
249 
250 		/* Copy maximal string literal. */
251 		quote = c;
252 		c = expr_expression[expr_index++];
253 		for (index_ = 0; c != quote && c != NUL;) {
254 			expr_temporary[index_++] = c;
255 			c = expr_expression[expr_index++];
256 		}
257 		expr_temporary[index_++] = NUL;
258 
259 		if (c == NUL) {
260 			sc_error("expr_next_token_unadjusted:"
261 			         " warning: unterminated string literal\n");
262 			expr_index--;
263 		}
264 
265 		/* Return string literal. */
266 		token_value->string = expr_temporary;
267 		return TOK_STRING;
268 	}
269 
270 	/* Identify ids and other multicharacter tokens. */
271 	else if (sc_isalpha(c)) {
272 		sc_int index_, token;
273 
274 		/*
275 		 * Copy maximal alphabetical string.  While an ident would normally
276 		 * be alpha followed by zero or more alnum, for Adrift purposes we
277 		 * use only alpha -- all idents should really be "functions", and
278 		 * in particular we want to see "mod7" as "mod" and 7 separately.
279 		 */
280 		for (index_ = 0; sc_isalpha(c) && c != NUL;) {
281 			expr_temporary[index_++] = c;
282 			c = expr_expression[expr_index++];
283 		}
284 		expr_index--;
285 		expr_temporary[index_++] = NUL;
286 
287 		/*
288 		 * Check for a function name, and if known, return that, otherwise
289 		 * return a bare id.
290 		 */
291 		token = expr_multichar_search(expr_temporary, FUNCTION_TOKENS);
292 		if (token == TOK_NONE) {
293 			token_value->string = expr_temporary;
294 			return TOK_IDENT;
295 		} else
296 			return token;
297 	}
298 
299 	/*
300 	 * Last chance check for two-character (multichar) operators, and if none
301 	 * then return a single-character token.
302 	 */
303 	else {
304 		sc_char operator_[3];
305 		sc_int token;
306 
307 		/*
308 		 * Build a two-character string.  If we happen to be at the last
309 		 * expression character, we'll pick up the expression NUL into
310 		 * operator_[1], so no need to special case end of expression here.
311 		 */
312 		operator_[0] = c;
313 		operator_[1] = expr_expression[expr_index];
314 		operator_[2] = NUL;
315 
316 		/* Search for this two-character operator. */
317 		if (operator_[0] != NUL && operator_[1] != NUL) {
318 			token = expr_multichar_search(operator_, OPERATOR_TOKENS);
319 			if (token != TOK_NONE) {
320 				/* Matched, so advance expression index and return this token. */
321 				expr_index++;
322 				return token;
323 			}
324 		}
325 
326 		/*
327 		 * No match, or at last expression character; return a single character
328 		 * token.
329 		 */
330 		return c;
331 	}
332 }
333 
expr_next_token(void)334 static sc_int expr_next_token(void) {
335 	sc_int token;
336 	sc_vartype_t token_value;
337 
338 	/*
339 	 * Get the basic next token.  We may adjust it later for unary minus/plus
340 	 * depending on what it is, and the prior token.
341 	 */
342 	token_value.voidp = NULL;
343 	token = expr_next_token_unadjusted(&token_value);
344 
345 	/* Special handling for unary minus/plus signs. */
346 	if (token == TOK_SUBTRACT || token == TOK_ADD) {
347 		/*
348 		 * Unary minus/plus if prior token was an operator or a comparison, left
349 		 * parenthesis, or comma, or if there was no prior token.
350 		 */
351 		switch (expr_current_token) {
352 		case TOK_MOD:
353 		case TOK_POWER:
354 		case TOK_ADD:
355 		case TOK_SUBTRACT:
356 		case TOK_MULTIPLY:
357 		case TOK_DIVIDE:
358 		case TOK_AND:
359 		case TOK_OR:
360 		case TOK_EQUAL:
361 		case TOK_GREATER:
362 		case TOK_LESS:
363 		case TOK_NOT_EQUAL:
364 		case TOK_GREATER_EQ:
365 		case TOK_LESS_EQ:
366 		case TOK_LPAREN:
367 		case TOK_COMMA:
368 		case TOK_NONE:
369 			token = (token == TOK_SUBTRACT) ? TOK_UMINUS : TOK_UPLUS;
370 			break;
371 
372 		default:
373 			break;
374 		}
375 	}
376 
377 	/* Set current token to the one just found, and return it. */
378 	expr_current_token = token;
379 	expr_token_value = token_value;
380 	return token;
381 }
382 
383 
384 /*
385  * expr_current_token_value()
386  *
387  * Return the token value of the current token.  Undefined if the current
388  * token is not numeric, an id, or a variable.
389  */
expr_current_token_value(sc_vartype_t * value)390 static void expr_current_token_value(sc_vartype_t *value) {
391 	/* Quick check that the value is a valid one. */
392 	switch (expr_current_token) {
393 	case TOK_INTEGER:
394 	case TOK_STRING:
395 	case TOK_VARIABLE:
396 	case TOK_IDENT:
397 		break;
398 
399 	default:
400 		sc_fatal("expr_current_token_value:"
401 		         " taking undefined token value, %ld\n", expr_current_token);
402 	}
403 
404 	/* Return value. */
405 	*value = expr_token_value;
406 }
407 
408 
409 /*
410  * Evaluation values stack, uses a variable type so it can contain both
411  * integers and strings, and flags strings for possible garbage collection
412  * on parse errors.
413  */
414 struct sc_stack_t {
415 	sc_bool is_collectible;
416 	sc_vartype_t value;
417 };
418 static sc_stack_t expr_eval_stack[MAX_NESTING_DEPTH];
419 static sc_int expr_eval_stack_index = 0;
420 
421 /* Variables set to reference for %...% values. */
422 static sc_var_setref_t expr_varset = NULL;
423 
424 /*
425  * expr_eval_start()
426  *
427  * Reset the evaluation stack to an empty state, and register the variables
428  * set to use when referencing %...% variables.
429  */
expr_eval_start(sc_var_setref_t vars)430 static void expr_eval_start(sc_var_setref_t vars) {
431 	expr_eval_stack_index = 0;
432 	expr_varset = vars;
433 }
434 
435 
436 /*
437  * expr_eval_garbage_collect()
438  *
439  * In case of parse error, empty out and free all collectible malloced
440  * strings left in the evaluation array.
441  */
expr_eval_garbage_collect(void)442 static void expr_eval_garbage_collect(void) {
443 	sc_int index_;
444 
445 	/*
446 	 * Find and free all collectible strings still in the stack.  We have to
447 	 * free through mutable string rather than const string.
448 	 */
449 	for (index_ = 0; index_ < expr_eval_stack_index; index_++) {
450 		if (expr_eval_stack[index_].is_collectible)
451 			sc_free(expr_eval_stack[index_].value.mutable_string);
452 	}
453 
454 	/* Reset the stack index, for clarity and neatness. */
455 	expr_eval_stack_index = 0;
456 }
457 
458 
459 /*
460  * expr_eval_push_integer()
461  * expr_eval_push_string()
462  * expr_eval_push_alloced_string()
463  *
464  * Push a value onto the values stack.  Strings are malloc'ed and copied,
465  * and the copy is placed onto the stack, unless _alloced_string() is used;
466  * for this case, the input string is assumed to be already malloc'ed, and
467  * the caller should not subsequently free the string.
468  */
expr_eval_push_integer(sc_int value)469 static void expr_eval_push_integer(sc_int value) {
470 	if (expr_eval_stack_index >= MAX_NESTING_DEPTH)
471 		sc_fatal("expr_eval_push_integer: stack overflow\n");
472 
473 	expr_eval_stack[expr_eval_stack_index].is_collectible = FALSE;
474 	expr_eval_stack[expr_eval_stack_index++].value.integer = value;
475 }
476 
expr_eval_push_string(const sc_char * value)477 static void expr_eval_push_string(const sc_char *value) {
478 	sc_char *value_copy;
479 
480 	if (expr_eval_stack_index >= MAX_NESTING_DEPTH)
481 		sc_fatal("expr_eval_push_string: stack overflow\n");
482 
483 	/* Push a copy of value. */
484 	value_copy = (sc_char *)sc_malloc(strlen(value) + 1);
485 	strcpy(value_copy, value);
486 	expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE;
487 	expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value_copy;
488 }
489 
expr_eval_push_alloced_string(sc_char * value)490 static void expr_eval_push_alloced_string(sc_char *value) {
491 	if (expr_eval_stack_index >= MAX_NESTING_DEPTH)
492 		sc_fatal("expr_eval_push_alloced_string: stack overflow\n");
493 
494 	expr_eval_stack[expr_eval_stack_index].is_collectible = TRUE;
495 	expr_eval_stack[expr_eval_stack_index++].value.mutable_string = value;
496 }
497 
498 
499 /*
500  * expr_eval_pop_integer()
501  * expr_eval_pop_string()
502  *
503  * Pop values off the values stack.  Returned strings are malloc'ed copies,
504  * and the caller is responsible for freeing them.
505  */
expr_eval_pop_integer(void)506 static sc_int expr_eval_pop_integer(void) {
507 	if (expr_eval_stack_index == 0)
508 		sc_fatal("expr_eval_pop_integer: stack underflow\n");
509 
510 	assert(!expr_eval_stack[expr_eval_stack_index - 1].is_collectible);
511 	return expr_eval_stack[--expr_eval_stack_index].value.integer;
512 }
513 
expr_eval_pop_string(void)514 static sc_char *expr_eval_pop_string(void) {
515 	if (expr_eval_stack_index == 0)
516 		sc_fatal("expr_eval_pop_string: stack underflow\n");
517 
518 	/* Returns mutable string rather than const string. */
519 	assert(expr_eval_stack[expr_eval_stack_index - 1].is_collectible);
520 	return expr_eval_stack[--expr_eval_stack_index].value.mutable_string;
521 }
522 
523 
524 /*
525  * expr_eval_result()
526  *
527  * Return the top of the values stack as the expression result.
528  */
expr_eval_result(sc_vartype_t * vt_rvalue)529 static void expr_eval_result(sc_vartype_t *vt_rvalue) {
530 	if (expr_eval_stack_index != 1)
531 		sc_fatal("expr_eval_result: values stack not completed\n");
532 
533 	/* Clear down stack and return the top value. */
534 	expr_eval_stack_index = 0;
535 	*vt_rvalue = expr_eval_stack[0].value;
536 }
537 
538 
539 /*
540  * expr_eval_abs()
541  *
542  * Return the absolute value of the given sc_int.  Replacement for labs(),
543  * avoids tying sc_int to long types too closely.
544  */
expr_eval_abs(sc_int value)545 static sc_int expr_eval_abs(sc_int value) {
546 	return value < 0 ? -value : value;
547 }
548 
549 /*
550  * expr_eval_action
551  *
552  * Evaluate the effect of a token into the values stack.
553  */
expr_eval_action(CONTEXT,sc_int token)554 static void expr_eval_action(CONTEXT, sc_int token) {
555 	sc_vartype_t token_value;
556 
557 	switch (token) {
558 	/* Handle tokens representing stack pushes. */
559 	case TOK_INTEGER:
560 		expr_current_token_value(&token_value);
561 		expr_eval_push_integer(token_value.integer);
562 		break;
563 
564 	case TOK_STRING:
565 		expr_current_token_value(&token_value);
566 		expr_eval_push_string(token_value.string);
567 		break;
568 
569 	case TOK_VARIABLE: {
570 		sc_vartype_t vt_rvalue;
571 		sc_int type;
572 
573 		expr_current_token_value(&token_value);
574 		if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) {
575 			sc_error("expr_eval_action:"
576 			         " undefined variable, %s\n", token_value.string);
577 			LONG_JUMP;
578 		}
579 		switch (type) {
580 		case VAR_INTEGER:
581 			expr_eval_push_integer(vt_rvalue.integer);
582 			break;
583 
584 		case VAR_STRING:
585 			expr_eval_push_string(vt_rvalue.string);
586 			break;
587 
588 		default:
589 			sc_fatal("expr_eval_action: bad variable type\n");
590 		}
591 		break;
592 	}
593 
594 	/* Handle tokens representing functions returning numeric. */
595 	case TOK_IF: {
596 		sc_int test, val1, val2;
597 
598 		/* Pop the test and alternatives, and push back result. */
599 		val2 = expr_eval_pop_integer();
600 		val1 = expr_eval_pop_integer();
601 		test = expr_eval_pop_integer();
602 		expr_eval_push_integer(test ? val1 : val2);
603 		break;
604 	}
605 
606 	case TOK_MAX:
607 	case TOK_MIN: {
608 		sc_int argument_count, index_, result;
609 
610 		/* Get argument count off the top of the stack. */
611 		argument_count = expr_eval_pop_integer();
612 		assert(argument_count > 0);
613 
614 		/* Find the max or min of these stacked values. */
615 		result = expr_eval_pop_integer();
616 		for (index_ = 1; index_ < argument_count; index_++) {
617 			sc_int next;
618 
619 			next = expr_eval_pop_integer();
620 			switch (token) {
621 			case TOK_MAX:
622 				result = (next > result) ? next : result;
623 				break;
624 
625 			case TOK_MIN:
626 				result = (next < result) ? next : result;
627 				break;
628 
629 			default:
630 				sc_fatal("expr_eval_action: bad token, %ld\n", token);
631 			}
632 		}
633 
634 		/* Push back the result. */
635 		expr_eval_push_integer(result);
636 		break;
637 	}
638 
639 	case TOK_EITHER: {
640 		sc_int argument_count, pick, index_;
641 		sc_int result = 0;
642 
643 		/* Get argument count off the top of the stack. */
644 		argument_count = expr_eval_pop_integer();
645 		assert(argument_count > 0);
646 
647 		/*
648 		 * Pick one of the top N items at random, then unstack all N and
649 		 * push back the value of the one picked.
650 		 */
651 		pick = sc_rand() % argument_count;
652 		for (index_ = 0; index_ < argument_count; index_++) {
653 			sc_int val;
654 
655 			val = expr_eval_pop_integer();
656 			if (index_ == pick)
657 				result = val;
658 		}
659 
660 		/* Push back the result. */
661 		expr_eval_push_integer(result);
662 		break;
663 	}
664 
665 	case TOK_INSTR: {
666 		sc_char *val1, *val2, *search;
667 		sc_int result;
668 
669 		/* Extract the two values to work on. */
670 		val2 = expr_eval_pop_string();
671 		val1 = expr_eval_pop_string();
672 
673 		/*
674 		 * Search for the second in the first.  The result is the character
675 		 * position, starting at 1, or 0 if not found.  Then free the popped
676 		 * strings, and push back the result.
677 		 */
678 		search = (val1[0] != NUL) ? strstr(val1, val2) : NULL;
679 		result = (!search) ? 0 : search - val1 + 1;
680 		sc_free(val1);
681 		sc_free(val2);
682 		expr_eval_push_integer(result);
683 		break;
684 	}
685 
686 	case TOK_LEN: {
687 		sc_char *val;
688 		sc_int result;
689 
690 		/* Pop the top string, and push back its length. */
691 		val = expr_eval_pop_string();
692 		result = strlen(val);
693 		sc_free(val);
694 		expr_eval_push_integer(result);
695 		break;
696 	}
697 
698 	case TOK_VAL: {
699 		sc_char *val;
700 		sc_int result = 0;
701 
702 		/*
703 		 * Extract the string at stack top, and try to convert, returning
704 		 * zero if conversion fails.  Free the popped string, and push back
705 		 * the result.
706 		 */
707 		val = expr_eval_pop_string();
708 		sscanf(val, "%ld", &result);
709 		sc_free(val);
710 		expr_eval_push_integer(result);
711 		break;
712 	}
713 
714 	/* Handle tokens representing unary numeric operations. */
715 	case TOK_UMINUS:
716 		expr_eval_push_integer(-(expr_eval_pop_integer()));
717 		break;
718 
719 	case TOK_UPLUS:
720 		break;
721 
722 	case TOK_ABS:
723 		expr_eval_push_integer(expr_eval_abs(expr_eval_pop_integer()));
724 		break;
725 
726 	/* Handle tokens representing most binary numeric operations. */
727 	case TOK_ADD:
728 	case TOK_SUBTRACT:
729 	case TOK_MULTIPLY:
730 	case TOK_AND:
731 	case TOK_OR:
732 	case TOK_EQUAL:
733 	case TOK_GREATER:
734 	case TOK_LESS:
735 	case TOK_NOT_EQUAL:
736 	case TOK_GREATER_EQ:
737 	case TOK_LESS_EQ:
738 	case TOK_RANDOM: {
739 		sc_int val1, val2, result = 0;
740 
741 		/* Extract the two values to work on. */
742 		val2 = expr_eval_pop_integer();
743 		val1 = expr_eval_pop_integer();
744 
745 		/* Generate the result value. */
746 		switch (token) {
747 		case TOK_ADD:
748 			result = val1 + val2;
749 			break;
750 		case TOK_SUBTRACT:
751 			result = val1 - val2;
752 			break;
753 		case TOK_MULTIPLY:
754 			result = val1 * val2;
755 			break;
756 		case TOK_AND:
757 			result = val1 && val2;
758 			break;
759 		case TOK_OR:
760 			result = val1 || val2;
761 			break;
762 		case TOK_EQUAL:
763 			result = val1 == val2;
764 			break;
765 		case TOK_GREATER:
766 			result = val1 > val2;
767 			break;
768 		case TOK_LESS:
769 			result = val1 < val2;
770 			break;
771 		case TOK_NOT_EQUAL:
772 			result = val1 != val2;
773 			break;
774 		case TOK_GREATER_EQ:
775 			result = val1 >= val2;
776 			break;
777 		case TOK_LESS_EQ:
778 			result = val1 <= val2;
779 			break;
780 		case TOK_RANDOM:
781 			result = sc_randomint(val1, val2);
782 			break;
783 		default:
784 			sc_fatal("expr_eval_action: bad token, %ld\n", token);
785 		}
786 
787 		/* Put result back at top of stack. */
788 		expr_eval_push_integer(result);
789 		break;
790 	}
791 
792 	/* Handle division and modulus separately; they're "eccentric". */
793 	case TOK_DIVIDE:
794 	case TOK_MOD: {
795 		sc_int val1, val2, x, y, result = 0;
796 
797 		/* Extract the two values to work on, complain about division by 0. */
798 		val2 = expr_eval_pop_integer();
799 		val1 = expr_eval_pop_integer();
800 		if (val2 == 0) {
801 			sc_error("expr_eval_action: attempt to divide by zero\n");
802 			expr_eval_push_integer(result);
803 			break;
804 		}
805 
806 		/*
807 		 * ANSI/ISO C only defines integer division for positive values.
808 		 * Negative values usually work consistently across platforms, but are
809 		 * not guaranteed.  For maximum portability, then, here we'll work
810 		 * carefully with positive integers only.
811 		 */
812 		x = expr_eval_abs(val1);
813 		y = expr_eval_abs(val2);
814 
815 		/* Generate the result value. */
816 		switch (token) {
817 		case TOK_DIVIDE:
818 			/*
819 			 * Adrift's division apparently works by dividing using floating
820 			 * point, then applying (asymmetrical) rounding, so we have to do
821 			 * the same here.
822 			 */
823 			result = ((val1 < 0) == (val2 < 0))
824 			         ? ((x / y) + (((x % y) * 2 >= y) ? 1 : 0))
825 			         : -((x / y) + (((x % y) * 2 >  y) ? 1 : 0));
826 			break;
827 
828 		case TOK_MOD:
829 			/*
830 			 * Adrift also breaks numerical consistency by defining mod in a
831 			 * conventional (non-rounded), way, so that A=(AdivB)*B+AmodB
832 			 * does not hold.
833 			 */
834 			result = (val1 < 0) ? -(x % y) : (x % y);
835 			break;
836 
837 		default:
838 			sc_fatal("expr_eval_action: bad token, %ld\n", token);
839 		}
840 
841 		/* Put result back at top of stack. */
842 		expr_eval_push_integer(result);
843 		break;
844 	}
845 
846 	/* Handle power individually, to avoid needing a maths library. */
847 	case TOK_POWER: {
848 		sc_int val1, val2, result;
849 
850 		/* Extract the two values to work on. */
851 		val2 = expr_eval_pop_integer();
852 		val1 = expr_eval_pop_integer();
853 
854 		/* Handle negative and zero power values first, as special cases. */
855 		if (val2 == 0)
856 			result = 1;
857 		else if (val2 < 0) {
858 			if (val1 == 0) {
859 				sc_error("expr_eval_action: attempt to divide by zero\n");
860 				result = 0;
861 			} else if (val1 == 1)
862 				result = val1;
863 			else if (val1 == -1)
864 				result = (-val2 & 1) ? val1 : -val1;
865 			else
866 				result = 0;
867 		} else {
868 			/* Raise to positive powers using the Russian Peasant algorithm. */
869 			while ((val2 & 1) == 0) {
870 				val1 = val1 * val1;
871 				val2 >>= 1;
872 			}
873 
874 			result = val1;
875 			val2 >>= 1;
876 			while (val2 > 0) {
877 				val1 = val1 * val1;
878 				if (val2 & 1)
879 					result = result * val1;
880 				val2 >>= 1;
881 			}
882 		}
883 
884 		/* Put result back at top of stack. */
885 		expr_eval_push_integer(result);
886 		break;
887 	}
888 
889 	/* Handle tokens representing functions returning string. */
890 	case TOK_LEFT:
891 	case TOK_RIGHT: {
892 		sc_char *text;
893 		sc_int length;
894 
895 		/*
896 		 * Extract the text and length.  If length is longer than text, or
897 		 * negative, do nothing.
898 		 */
899 		length = expr_eval_pop_integer();
900 		text = expr_eval_pop_string();
901 		if (length < 0 || length >= (sc_int) strlen(text)) {
902 			expr_eval_push_alloced_string(text);
903 			break;
904 		}
905 
906 		/*
907 		 * Take the left or right segment -- for left, the operation is a
908 		 * simple truncation; for right, it's a memmove.
909 		 */
910 		switch (token) {
911 		case TOK_LEFT:
912 			text[length] = NUL;
913 			break;
914 
915 		case TOK_RIGHT:
916 			memmove(text, text + strlen(text) - length, length + 1);
917 			break;
918 
919 		default:
920 			sc_fatal("expr_eval_action: bad token, %ld\n", token);
921 		}
922 
923 		/* Put result back at top of stack. */
924 		expr_eval_push_alloced_string(text);
925 		break;
926 	}
927 
928 	case TOK_MID: {
929 		sc_char *text;
930 		sc_int length, start, limit;
931 
932 		/*
933 		 * Extract the text, start, and length, re-basing start from 1 to 0,
934 		 * and calculate the limit on characters available for the move.
935 		 */
936 		length = expr_eval_pop_integer();
937 		start = expr_eval_pop_integer() - 1;
938 		text = expr_eval_pop_string();
939 		limit = strlen(text);
940 
941 		/*
942 		 * Clamp ranges that roam outside the available text -- start less
943 		 * than 0 to 0, and greater than len(text) to len(text), and length
944 		 * less than 0 to 0, and off string end to string end.
945 		 */
946 		if (start < 0)
947 			start = 0;
948 		else if (start > limit)
949 			start = limit;
950 		if (length < 0)
951 			length = 0;
952 		else if (length > limit - start)
953 			length = limit - start;
954 
955 		/* Move substring, terminate, and put back at top of stack. */
956 		memmove(text, text + start, length + 1);
957 		text[length] = NUL;
958 		expr_eval_push_alloced_string(text);
959 		break;
960 	}
961 
962 	case TOK_STR: {
963 		sc_int val;
964 		sc_char buffer[32];
965 
966 		/*
967 		 * Extract the value, convert it, and push back the resulting string.
968 		 * The leading space on positive values matches the Runner.
969 		 */
970 		val = expr_eval_pop_integer();
971 		sprintf(buffer, "% ld", val);
972 		expr_eval_push_string(buffer);
973 		break;
974 	}
975 
976 
977 	/* Handle tokens representing unary string operations. */
978 	case TOK_UPPER:
979 	case TOK_LOWER:
980 	case TOK_PROPER: {
981 		sc_char *text;
982 		sc_int index_;
983 
984 		/* Extract the value to work on. */
985 		text = expr_eval_pop_string();
986 
987 		/* Convert the entire string in place -- it's malloc'ed. */
988 		for (index_ = 0; text[index_] != NUL; index_++) {
989 			switch (token) {
990 			case TOK_UPPER:
991 				text[index_] = sc_toupper(text[index_]);
992 				break;
993 
994 			case TOK_LOWER:
995 				text[index_] = sc_tolower(text[index_]);
996 				break;
997 
998 			case TOK_PROPER:
999 				if (index_ == 0 || sc_isspace(text[index_ - 1]))
1000 					text[index_] = sc_toupper(text[index_]);
1001 				else
1002 					text[index_] = sc_tolower(text[index_]);
1003 				break;
1004 
1005 			default:
1006 				sc_fatal("expr_eval_action: bad token, %ld\n", token);
1007 			}
1008 		}
1009 
1010 		/* Put result back at top of stack. */
1011 		expr_eval_push_alloced_string(text);
1012 		break;
1013 	}
1014 
1015 	/* Handle token representing binary string operation. */
1016 	case TOK_CONCATENATE: {
1017 		sc_char *text1, *text2;
1018 
1019 		/* Extract the two texts to work on. */
1020 		text2 = expr_eval_pop_string();
1021 		text1 = expr_eval_pop_string();
1022 
1023 		/*
1024 		 * Resize text1 to be long enough for both, and concatenate, then
1025 		 * free text2, and push back the concatenation.
1026 		 */
1027 		text1 = (sc_char *)sc_realloc(text1, strlen(text1) + strlen(text2) + 1);
1028 		strcat(text1, text2);
1029 		sc_free(text2);
1030 		expr_eval_push_alloced_string(text1);
1031 		break;
1032 	}
1033 
1034 	default:
1035 		sc_fatal("expr_eval_action: bad token, %ld\n", token);
1036 	}
1037 }
1038 
1039 
1040 /* Predictive parser lookahead token. */
1041 static sc_int expr_parse_lookahead = TOK_NONE;
1042 
1043 /* Forward declaration of factor parsers and string expression parser. */
1044 static void expr_parse_numeric_factor(CONTEXT);
1045 static void expr_parse_string_factor(CONTEXT);
1046 static void expr_parse_string_expr(CONTEXT);
1047 
1048 /*
1049  * expr_parse_match
1050  *
1051  * Match a token to the lookahead, then advance lookahead.
1052  */
expr_parse_match(CONTEXT,sc_int token)1053 static void expr_parse_match(CONTEXT, sc_int token) {
1054 	if (expr_parse_lookahead == token)
1055 		expr_parse_lookahead = expr_next_token();
1056 	else {
1057 		/* Syntax error. */
1058 		sc_error("expr_parse_match: syntax error,"
1059 		         " expected %ld, got %ld\n", expr_parse_lookahead, token);
1060 		LONG_JUMP;
1061 	}
1062 }
1063 
1064 
1065 /*
1066  * Numeric operator precedence table.  Operators are in order of precedence,
1067  * with the highest being a factor.  Each precedence entry permits several
1068  * listed tokens.  The end of the table (highest precedence) is marked by
1069  * a list with no operators (although in practice we need to put a TOK_NONE
1070  * in here since some C compilers won't accept { } as an empty initializer).
1071  */
1072 struct sc_precedence_entry_t {
1073 	const sc_int token_count;
1074 	const sc_int tokens[6];
1075 };
1076 #if 0
1077 /*
1078  * Conventional (BASIC, C) precedence table for the parser.  Exponentiation
1079  * has the highest precedence, then multiplicative operations, additive,
1080  * comparisons, and boolean combiners.
1081  */
1082 static const sc_precedence_entry_t PRECEDENCE_TABLE[] = {
1083 	{1, {TOK_OR}},
1084 	{1, {TOK_AND}},
1085 	{2, {TOK_EQUAL, TOK_NOT_EQUAL}},
1086 	{4, {TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ}},
1087 	{2, {TOK_ADD, TOK_SUBTRACT}},
1088 	{3, {TOK_MULTIPLY, TOK_DIVIDE, TOK_MOD}},
1089 	{1, {TOK_POWER}},
1090 	{0, {TOK_NONE}}
1091 };
1092 #else
1093 /*
1094  * Adrift-like precedence table for the parser.  Exponentiation and modulus
1095  * operations seem to be implemented at the same level as addition and
1096  * subtraction, and boolean 'and' and 'or' have equal precedence.
1097  */
1098 static const sc_precedence_entry_t PRECEDENCE_TABLE[] = {
1099 	{2, {TOK_OR, TOK_AND}},
1100 	{
1101 		6, {
1102 			TOK_EQUAL, TOK_NOT_EQUAL,
1103 			TOK_GREATER, TOK_LESS, TOK_GREATER_EQ, TOK_LESS_EQ
1104 		}
1105 	},
1106 	{4, {TOK_ADD, TOK_SUBTRACT, TOK_POWER, TOK_MOD}},
1107 	{2, {TOK_MULTIPLY, TOK_DIVIDE}},
1108 	{0, {TOK_NONE}}
1109 };
1110 #endif
1111 
1112 
1113 /*
1114  * expr_parse_contains_token()
1115  *
1116  * Helper for expr_parse_numeric_element().  Search the token list for the
1117  * entry passed in, and return TRUE if it contains the given token.
1118  */
expr_parse_contains_token(const sc_precedence_entry_t * entry,sc_int token)1119 static int expr_parse_contains_token(const sc_precedence_entry_t *entry, sc_int token) {
1120 	sc_bool is_matched;
1121 	sc_int index_;
1122 
1123 	/* Search the entry's token list for the token passed in. */
1124 	is_matched = FALSE;
1125 	for (index_ = 0; index_ < entry->token_count; index_++) {
1126 		if (entry->tokens[index_] == token) {
1127 			is_matched = TRUE;
1128 			break;
1129 		}
1130 	}
1131 
1132 	return is_matched;
1133 }
1134 
1135 
1136 /*
1137  * expr_parse_numeric_element()
1138  *
1139  * Parse numeric expression elements.  This function uses the precedence table
1140  * to match tokens, then decide whether, and how, to recurse into itself, or
1141  * whether to parse a highest-precedence factor.
1142  */
expr_parse_numeric_element(CONTEXT,sc_int precedence)1143 static void expr_parse_numeric_element(CONTEXT, sc_int precedence) {
1144 	const sc_precedence_entry_t *entry;
1145 
1146 	/* See if the level passed in has listed tokens. */
1147 	entry = PRECEDENCE_TABLE + precedence;
1148 	if (entry->token_count == 0) {
1149 		/* Precedence levels that hit the table end are factors. */
1150 		CALL0(expr_parse_numeric_factor);
1151 		return;
1152 	}
1153 
1154 	/*
1155 	 * Parse initial higher-precedence factor, then others that associate
1156 	 * with the given level.
1157 	 */
1158 	CALL1(expr_parse_numeric_element, precedence + 1);
1159 	while (expr_parse_contains_token(entry, expr_parse_lookahead)) {
1160 		sc_int token;
1161 
1162 		/* Note token and match, parse next level, then action this token. */
1163 		token = expr_parse_lookahead;
1164 		CALL1(expr_parse_match, token);
1165 		CALL1(expr_parse_numeric_element, precedence + 1);
1166 		CALL1(expr_eval_action, token);
1167 	}
1168 }
1169 
1170 
1171 /*
1172  * expr_parse_numeric_expr
1173  *
1174  * Parse a complete numeric (sub-)expression.
1175  */
expr_parse_numeric_expr(CONTEXT)1176 static void expr_parse_numeric_expr(CONTEXT) {
1177 	/* Call the parser of the lowest precedence operators. */
1178 	CALL1(expr_parse_numeric_element, 0);
1179 }
1180 
1181 
1182 /*
1183  * expr_parse_numeric_factor()
1184  *
1185  * Parse a numeric expression factor.
1186  */
expr_parse_numeric_factor(CONTEXT)1187 static void expr_parse_numeric_factor(CONTEXT) {
1188 	/* Handle factors based on lookahead token. */
1189 	switch (expr_parse_lookahead) {
1190 	/* Handle straightforward factors first. */
1191 	case TOK_LPAREN:
1192 		CALL1(expr_parse_match, TOK_LPAREN);
1193 		CALL0(expr_parse_numeric_expr);
1194 		CALL1(expr_parse_match, TOK_RPAREN);
1195 		break;
1196 
1197 	case TOK_UMINUS:
1198 		CALL1(expr_parse_match, TOK_UMINUS);
1199 		CALL0(expr_parse_numeric_factor);
1200 		CALL1(expr_eval_action, TOK_UMINUS);
1201 		break;
1202 
1203 	case TOK_UPLUS:
1204 		CALL1(expr_parse_match, TOK_UPLUS);
1205 		CALL0(expr_parse_numeric_factor);
1206 		break;
1207 
1208 	case TOK_INTEGER:
1209 		CALL1(expr_eval_action, TOK_INTEGER);
1210 		CALL1(expr_parse_match, TOK_INTEGER);
1211 		break;
1212 
1213 	case TOK_VARIABLE: {
1214 		sc_vartype_t token_value, vt_rvalue;
1215 		sc_int type;
1216 
1217 		expr_current_token_value(&token_value);
1218 		if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) {
1219 			sc_error("expr_parse_numeric_factor:"
1220 			         " undefined variable, %s\n", token_value.string);
1221 			LONG_JUMP;
1222 		}
1223 		if (type != VAR_INTEGER) {
1224 			sc_error("expr_parse_numeric_factor:"
1225 			         " string variable in numeric context, %s\n",
1226 			         token_value.string);
1227 			LONG_JUMP;
1228 		}
1229 		CALL1(expr_eval_action, TOK_VARIABLE);
1230 		CALL1(expr_parse_match, TOK_VARIABLE);
1231 		break;
1232 	}
1233 
1234 	/* Handle functions as factors. */
1235 	case TOK_ABS:
1236 		/* Parse as "abs (val)". */
1237 		CALL1(expr_parse_match, TOK_ABS);
1238 		CALL1(expr_parse_match, TOK_LPAREN);
1239 		CALL0(expr_parse_numeric_expr);
1240 		CALL1(expr_parse_match, TOK_RPAREN);
1241 		CALL1(expr_eval_action, TOK_ABS);
1242 		break;
1243 
1244 	case TOK_IF:
1245 		/* Parse as "if (boolean, val1, val2)". */
1246 		CALL1(expr_parse_match, TOK_IF);
1247 		CALL1(expr_parse_match, TOK_LPAREN);
1248 		CALL0(expr_parse_numeric_expr);
1249 		CALL1(expr_parse_match, TOK_COMMA);
1250 		CALL0(expr_parse_numeric_expr);
1251 		CALL1(expr_parse_match, TOK_COMMA);
1252 		CALL0(expr_parse_numeric_expr);
1253 		CALL1(expr_parse_match, TOK_RPAREN);
1254 		CALL1(expr_eval_action, TOK_IF);
1255 		break;
1256 
1257 	case TOK_RANDOM:
1258 		/* Parse as "random (low, high)". */
1259 		CALL1(expr_parse_match, TOK_RANDOM);
1260 		CALL1(expr_parse_match, TOK_LPAREN);
1261 		CALL0(expr_parse_numeric_expr);
1262 		CALL1(expr_parse_match, TOK_COMMA);
1263 		CALL0(expr_parse_numeric_expr);
1264 		CALL1(expr_parse_match, TOK_RPAREN);
1265 		CALL1(expr_eval_action, TOK_RANDOM);
1266 		break;
1267 
1268 	case TOK_MAX:
1269 	case TOK_MIN:
1270 	case TOK_EITHER:
1271 		/* Parse as "<func> (val1[,val2[,val3...]]])". */
1272 	{
1273 		sc_int token, argument_count;
1274 
1275 		/* Match up the function name and opening parenthesis. */
1276 		token = expr_parse_lookahead;
1277 		CALL1(expr_parse_match, token);
1278 		CALL1(expr_parse_match, TOK_LPAREN);
1279 
1280 		/* Count variable number of arguments as they are stacked. */
1281 		CALL0(expr_parse_numeric_expr);
1282 		argument_count = 1;
1283 		while (expr_parse_lookahead == TOK_COMMA) {
1284 			CALL1(expr_parse_match, TOK_COMMA);
1285 			CALL0(expr_parse_numeric_expr);
1286 			argument_count++;
1287 		}
1288 		CALL1(expr_parse_match, TOK_RPAREN);
1289 
1290 		/* Push additional value -- the count of arguments. */
1291 		expr_eval_push_integer(argument_count);
1292 		CALL1(expr_eval_action, token);
1293 		break;
1294 	}
1295 
1296 	case TOK_INSTR:
1297 		/* Parse as "instr (val1, val2)". */
1298 		CALL1(expr_parse_match, TOK_INSTR);
1299 		CALL1(expr_parse_match, TOK_LPAREN);
1300 		CALL0(expr_parse_string_expr);
1301 		CALL1(expr_parse_match, TOK_COMMA);
1302 		CALL0(expr_parse_string_expr);
1303 		CALL1(expr_parse_match, TOK_RPAREN);
1304 		CALL1(expr_eval_action, TOK_INSTR);
1305 		break;
1306 
1307 	case TOK_LEN:
1308 		/* Parse as "len (val)". */
1309 		CALL1(expr_parse_match, TOK_LEN);
1310 		CALL1(expr_parse_match, TOK_LPAREN);
1311 		CALL0(expr_parse_string_expr);
1312 		CALL1(expr_parse_match, TOK_RPAREN);
1313 		CALL1(expr_eval_action, TOK_LEN);
1314 		break;
1315 
1316 	case TOK_VAL:
1317 		/* Parse as "val (val)". */
1318 		CALL1(expr_parse_match, TOK_VAL);
1319 		CALL1(expr_parse_match, TOK_LPAREN);
1320 		CALL0(expr_parse_string_expr);
1321 		CALL1(expr_parse_match, TOK_RPAREN);
1322 		CALL1(expr_eval_action, TOK_VAL);
1323 		break;
1324 
1325 	case TOK_IDENT:
1326 		/* Unrecognized function-type token. */
1327 		sc_error("expr_parse_numeric_factor: syntax error, unknown ident\n");
1328 		LONG_JUMP;
1329 
1330 	default:
1331 		/* Syntax error. */
1332 		sc_error("expr_parse_numeric_factor:"
1333 		         " syntax error, unexpected token, %ld\n", expr_parse_lookahead);
1334 		LONG_JUMP;
1335 	}
1336 }
1337 
1338 
1339 /*
1340  * expr_parse_string_expr()
1341  *
1342  * Parse a complete string (sub-)expression.
1343  */
expr_parse_string_expr(CONTEXT)1344 static void expr_parse_string_expr(CONTEXT) {
1345 	/*
1346 	 * Parse a string factor, then all repeated concatenations.  Because the '+'
1347 	 * and '&' are context sensitive, we have to invent/translate them into the
1348 	 * otherwise unused TOK_CONCATENATE for evaluation.
1349 	 */
1350 	CALL0(expr_parse_string_factor);
1351 	while (expr_parse_lookahead == TOK_AND || expr_parse_lookahead == TOK_ADD) {
1352 		CALL1(expr_parse_match, expr_parse_lookahead);
1353 		CALL0(expr_parse_string_factor);
1354 		CALL1(expr_eval_action, TOK_CONCATENATE);
1355 	}
1356 }
1357 
1358 
1359 /*
1360  * expr_parse_string_factor()
1361  *
1362  * Parse a string expression factor.
1363  */
expr_parse_string_factor(CONTEXT)1364 static void expr_parse_string_factor(CONTEXT) {
1365 	/* Handle factors based on lookahead token. */
1366 	switch (expr_parse_lookahead) {
1367 	/* Handle straightforward factors first. */
1368 	case TOK_LPAREN:
1369 		CALL1(expr_parse_match, TOK_LPAREN);
1370 		CALL0(expr_parse_string_expr);
1371 		CALL1(expr_parse_match, TOK_RPAREN);
1372 		break;
1373 
1374 	case TOK_STRING:
1375 		CALL1(expr_eval_action, TOK_STRING);
1376 		CALL1(expr_parse_match, TOK_STRING);
1377 		break;
1378 
1379 	case TOK_VARIABLE: {
1380 		sc_vartype_t token_value, vt_rvalue;
1381 		sc_int type;
1382 
1383 		expr_current_token_value(&token_value);
1384 		if (!var_get(expr_varset, token_value.string, &type, &vt_rvalue)) {
1385 			sc_error("expr_parse_string_factor:"
1386 			         " undefined variable, %s\n", token_value.string);
1387 			LONG_JUMP;
1388 		}
1389 		if (type != VAR_STRING) {
1390 			sc_error("expr_parse_string_factor:"
1391 			         " numeric variable in string context, %s\n",
1392 			         token_value.string);
1393 			LONG_JUMP;
1394 		}
1395 		CALL1(expr_eval_action, TOK_VARIABLE);
1396 		CALL1(expr_parse_match, TOK_VARIABLE);
1397 		break;
1398 	}
1399 
1400 	/* Handle functions as factors. */
1401 	case TOK_UPPER:
1402 	case TOK_LOWER:
1403 	case TOK_PROPER:
1404 		/* Parse as "<func> (text)". */
1405 	{
1406 		sc_int token;
1407 
1408 		token = expr_parse_lookahead;
1409 		CALL1(expr_parse_match, token);
1410 		CALL1(expr_parse_match, TOK_LPAREN);
1411 		CALL0(expr_parse_string_expr);
1412 		CALL1(expr_parse_match, TOK_RPAREN);
1413 		CALL1(expr_eval_action, token);
1414 		break;
1415 	}
1416 
1417 	case TOK_LEFT:
1418 	case TOK_RIGHT:
1419 		/* Parse as "<func> (text,length)". */
1420 	{
1421 		sc_int token;
1422 
1423 		token = expr_parse_lookahead;
1424 		CALL1(expr_parse_match, token);
1425 		CALL1(expr_parse_match, TOK_LPAREN);
1426 		CALL0(expr_parse_string_expr);
1427 		CALL1(expr_parse_match, TOK_COMMA);
1428 		CALL0(expr_parse_numeric_expr);
1429 		CALL1(expr_parse_match, TOK_RPAREN);
1430 		CALL1(expr_eval_action, token);
1431 		break;
1432 	}
1433 
1434 	case TOK_MID:
1435 		/* Parse as "mid (text,start,length)". */
1436 		CALL1(expr_parse_match, TOK_MID);
1437 		CALL1(expr_parse_match, TOK_LPAREN);
1438 		CALL0(expr_parse_string_expr);
1439 		CALL1(expr_parse_match, TOK_COMMA);
1440 		CALL0(expr_parse_numeric_expr);
1441 		CALL1(expr_parse_match, TOK_COMMA);
1442 		CALL0(expr_parse_numeric_expr);
1443 		CALL1(expr_parse_match, TOK_RPAREN);
1444 		CALL1(expr_eval_action, TOK_MID);
1445 		break;
1446 
1447 	case TOK_STR:
1448 		/* Parse as "str (val)". */
1449 		CALL1(expr_parse_match, TOK_STR);
1450 		CALL1(expr_parse_match, TOK_LPAREN);
1451 		CALL0(expr_parse_numeric_expr);
1452 		CALL1(expr_parse_match, TOK_RPAREN);
1453 		CALL1(expr_eval_action, TOK_STR);
1454 		break;
1455 
1456 	case TOK_IDENT:
1457 		/* Unrecognized function-type token. */
1458 		sc_error("expr_parse_string_factor: syntax error, unknown ident\n");
1459 		LONG_JUMP;
1460 
1461 	default:
1462 		/* Syntax error. */
1463 		sc_error("expr_parse_string_factor:"
1464 		         " syntax error, unexpected token, %ld\n", expr_parse_lookahead);
1465 		LONG_JUMP;
1466 	}
1467 }
1468 
1469 
1470 /*
1471  * expr_evaluate_expression()
1472  *
1473  * Parse a string expression into a runtime values stack.  Return the
1474  * value of the expression.
1475  */
expr_evaluate_expression(const sc_char * expression,sc_var_setref_t vars,sc_int assign_type,sc_vartype_t * vt_rvalue)1476 static sc_bool expr_evaluate_expression(const sc_char *expression, sc_var_setref_t vars,
1477 		sc_int assign_type, sc_vartype_t *vt_rvalue) {
1478 	assert(assign_type == VAR_INTEGER || assign_type == VAR_STRING);
1479 	Context context;
1480 
1481 	/* Reset values stack and start tokenizer. */
1482 	expr_eval_start(vars);
1483 	expr_tokenize_start(expression);
1484 
1485 	// Try parsing an expression, and ensure it ends at string end. */
1486 	expr_parse_lookahead = expr_next_token();
1487 	if (assign_type == VAR_STRING)
1488 		expr_parse_string_expr(context);
1489 	else
1490 		expr_parse_numeric_expr(context);
1491 	if (!context._break)
1492 		expr_parse_match(context, TOK_EOS);
1493 
1494 	if (context._break) {
1495 		/* Parse error -- clean up tokenizer, collect garbage, and fail. */
1496 		expr_tokenize_end();
1497 		expr_eval_garbage_collect();
1498 		return FALSE;
1499 	}
1500 
1501 	/* Clean up tokenizer and return successfully with result. */
1502 	expr_tokenize_end();
1503 	expr_eval_result(vt_rvalue);
1504 	return TRUE;
1505 }
1506 
1507 
1508 /*
1509  * expr_eval_numeric_expression()
1510  * expr_eval_string_expression()
1511  *
1512  * Public interfaces to expression evaluation.  Evaluate an expression, and
1513  * assign the result to either a numeric or a string.  For string expressions,
1514  * the return value is malloc'ed, and the caller is responsible for freeing
1515  * it.
1516  */
expr_eval_numeric_expression(const sc_char * expression,sc_var_setref_t vars,sc_int * rvalue)1517 sc_bool expr_eval_numeric_expression(const sc_char *expression, sc_var_setref_t vars, sc_int *rvalue) {
1518 	sc_vartype_t vt_rvalue;
1519 	sc_bool status;
1520 	assert(expression && vars && rvalue);
1521 
1522 	/* Evaluate numeric expression, and return value if valid. */
1523 	status = expr_evaluate_expression(expression, vars, VAR_INTEGER, &vt_rvalue);
1524 	if (status)
1525 		*rvalue = vt_rvalue.integer;
1526 	return status;
1527 }
1528 
expr_eval_string_expression(const sc_char * expression,sc_var_setref_t vars,sc_char ** rvalue)1529 sc_bool expr_eval_string_expression(const sc_char *expression, sc_var_setref_t vars, sc_char **rvalue) {
1530 	sc_vartype_t vt_rvalue;
1531 	sc_bool status;
1532 	assert(expression && vars && rvalue);
1533 
1534 	/* Evaluate string expression, and return value if valid. */
1535 	status = expr_evaluate_expression(expression, vars, VAR_STRING, &vt_rvalue);
1536 	if (status)
1537 		*rvalue = vt_rvalue.mutable_string;
1538 	return status;
1539 }
1540 
1541 } // End of namespace Adrift
1542 } // End of namespace Glk
1543