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/alan2/types.h"
24 #include "glk/alan2/exe.h"
25 #include "glk/alan2/inter.h"
26 #include "glk/alan2/glkio.h"
27 #include "glk/alan2/main.h"
28 #include "glk/alan2/parse.h"
29 #include "glk/alan2/stack.h"
30 #include "glk/alan2/sysdep.h"
31 
32 namespace Glk {
33 namespace Alan2 {
34 
35 /* PRIVATE DATA */
36 
37 static int pc;
38 
39 
if_(Aword v)40 static void if_(Aword v) {
41 	int lev = 1;
42 	Aword i;
43 
44 	if (!v) {
45 		/* Skip to next ELSE or ENDIF on same level */
46 		while (TRUE) {
47 			i = memory[pc++];
48 			if (I_CLASS(i) == (Aword)C_STMOP)
49 				switch (I_OP(i)) {
50 				case I_ELSE:
51 					if (lev == 1) return;
52 					break;
53 				case I_IF:
54 					lev++;
55 					break;
56 				case I_ENDIF:
57 					lev--;
58 					if (lev == 0) return;
59 					break;
60 				default:
61 					break;
62 				}
63 		}
64 	}
65 }
66 
else_()67 static void else_() {
68 	int lev = 1;
69 	Aword i;
70 
71 	while (TRUE) {
72 		/* Skip to ENDIF on the same level */
73 		i = memory[pc++];
74 		if (I_CLASS(i) == (Aword)C_STMOP)
75 			switch (I_OP(i)) {
76 			case I_ENDIF:
77 				lev--;
78 				if (lev == 0) return;
79 				break;
80 			case I_IF:
81 				lev++;
82 				break;
83 			default:
84 				break;
85 			}
86 	}
87 }
88 
depstart()89 static void depstart() {
90 	/* A DEPSTART was executed so skip across the redundant DEPCASE to
91 	   start at the first expression */
92 	pc++;
93 }
94 
swap()95 static void swap() {
96 	Aptr v1 = pop();
97 	Aptr v2 = pop();
98 
99 	push(v1);
100 	push(v2);
101 }
102 
depexec(Aword v)103 static void depexec(Aword v) {
104 	int lev = 1;
105 	Aword i;
106 
107 	if (!v)
108 		/* The expression was not true, skip to next CASE on the same
109 		   level which could be a DEPCASE or DEPELSE */
110 		while (TRUE) {
111 			i = memory[pc++];
112 			if (I_CLASS(i) == (Aword)C_STMOP)
113 				switch (I_OP(i)) {
114 				case I_DEPSTART:
115 					lev++;
116 					break;
117 				case I_DEPEND:
118 					if (lev == 1) return;
119 					lev--;
120 					break;
121 				case I_DEPCASE:
122 				case I_DEPELSE:
123 					if (lev == 1) return;
124 					break;
125 				default:
126 					break;
127 				}
128 		}
129 }
130 
depcase()131 static void depcase() {
132 	int lev = 1;
133 	Aword i;
134 
135 	/* Skip to end of DEPENDING block (next DEPEND on same level) because
136 	   we have just executed a DEPCASE/DEPELSE statement as a result of a DEPCASE
137 	   catching */
138 
139 	while (TRUE) {
140 		i = memory[pc++];
141 		if (I_CLASS(i) == (Aword)C_STMOP)
142 			switch (I_OP(i)) {
143 			case I_DEPSTART:
144 				lev++;
145 				break;
146 			case I_DEPEND:
147 				lev--;
148 				if (lev == 0) return;
149 				break;
150 			default:
151 				break;
152 			}
153 	}
154 }
155 
interpret(Aaddr adr)156 void interpret(Aaddr adr) {
157 	Context ctx;
158 	interpret(ctx, adr);
159 }
160 
interpret(CONTEXT,Aaddr adr)161 void interpret(CONTEXT, Aaddr adr) {
162 	Aaddr oldpc;
163 	Aword i;
164 
165 	if (stpflg) printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++");
166 
167 	oldpc = pc;
168 	pc = adr;
169 	while (TRUE) {
170 		if (stpflg) printf("\n%4x: ", pc);
171 		if (pc > (int)memTop)
172 			syserr("Interpreting outside program.");
173 
174 		i = memory[pc++];
175 
176 		switch (I_CLASS(i)) {
177 		case C_CONST:
178 			if (stpflg) printf("PUSH  \t%5u", I_OP(i));
179 			push(I_OP(i));
180 			break;
181 		case C_CURVAR:
182 			switch (I_OP(i)) {
183 			case V_PARAM:
184 				if (stpflg) printf("PARAM \t%5lu\t\t(%u)", top(), params[top() - 1].code);
185 				push(params[pop() - 1].code);
186 				break;
187 			case V_CURLOC:
188 				if (stpflg) printf("CURLOC \t\t\t(%d)", cur.loc);
189 				push(cur.loc);
190 				break;
191 			case V_CURACT:
192 				if (stpflg) printf("CURACT \t\t\t(%d)", cur.act);
193 				push(cur.act);
194 				break;
195 			case V_CURVRB:
196 				if (stpflg) printf("CURVRB \t\t\t(%d)", cur.vrb);
197 				push(cur.vrb);
198 				break;
199 			case V_SCORE:
200 				if (stpflg) printf("CURSCORE \t\t\t(%d)", cur.score);
201 				push(cur.score);
202 				break;
203 			default:
204 				syserr("Unknown CURVAR instruction.");
205 				break;
206 			}
207 			break;
208 
209 		case C_STMOP:
210 			switch (I_OP(i)) {
211 			case I_PRINT: {
212 				Aptr fpos, len;
213 				fpos = pop();
214 				len = pop();
215 				if (stpflg) {
216 					printf("PRINT \t%5ld, %5ld\t\"", fpos, len);
217 					col = 34;     /* To format it better! */
218 				}
219 				print(fpos, len);
220 				if (stpflg)
221 					printf("\"");
222 				break;
223 			}
224 			case I_SYSTEM: {
225 				Aptr fpos, len;
226 				fpos = pop();
227 				len = pop();
228 				if (stpflg) {
229 					printf("SYSTEM \t%5ld, %5ld\t\"", fpos, len);
230 					col = 34;     /* To format it better! */
231 				}
232 				sys(fpos, len);
233 				break;
234 			}
235 			case I_GETSTR: {
236 				Aptr fpos, len;
237 				fpos = pop();
238 				len = pop();
239 				if (stpflg)
240 					printf("GETSTR\t%5ld, %5ld", fpos, len);
241 				getstr(fpos, len);
242 				if (stpflg)
243 					printf("\t(%ld)", top());
244 				break;
245 			}
246 			case I_QUIT: {
247 				if (stpflg)
248 					printf("QUIT");
249 				CALL0(quit)
250 				break;
251 			}
252 			case I_LOOK: {
253 				if (stpflg)
254 					printf("LOOK");
255 				look();
256 				break;
257 			}
258 			case I_SAVE: {
259 				if (stpflg)
260 					printf("SAVE");
261 				save();
262 				break;
263 			}
264 			case I_RESTORE: {
265 				if (stpflg)
266 					printf("RESTORE");
267 				restore();
268 				break;
269 			}
270 			case I_RESTART: {
271 				if (stpflg)
272 					printf("RESTART");
273 				restart();
274 				break;
275 			}
276 			case I_LIST: {
277 				Aptr cnt;
278 				cnt = pop();
279 				if (stpflg)
280 					printf("LIST \t%5ld", cnt);
281 				list(cnt);
282 				break;
283 			}
284 			case I_EMPTY: {
285 				Aptr cnt, whr;
286 				cnt = pop();
287 				whr = pop();
288 				if (stpflg)
289 					printf("EMPTY \t%5ld, %5ld", cnt, whr);
290 				empty(cnt, whr);
291 				break;
292 			}
293 			case I_SCORE: {
294 				Aptr sc;
295 				sc = pop();
296 				if (stpflg)
297 					printf("SCORE \t%5ld\t\t(%u)", sc, scores[sc - 1]);
298 				score(sc);
299 				break;
300 			}
301 			case I_VISITS: {
302 				Aptr v;
303 				v = pop();
304 				if (stpflg)
305 					printf("VISITS \t%5ld", v);
306 				visits(v);
307 				break;
308 			}
309 			case I_SCHEDULE: {
310 				Aptr evt, whr, aft;
311 				evt = pop();
312 				whr = pop();
313 				aft = pop();
314 				if (stpflg)
315 					printf("SCHEDULE \t%5ld, %5ld, %5ld", evt, whr, aft);
316 				schedule(evt, whr, aft);
317 				break;
318 			}
319 			case I_CANCEL: {
320 				Aptr evt;
321 				evt = pop();
322 				if (stpflg)
323 					printf("CANCEL \t%5ld", evt);
324 				cancl(evt);
325 				break;
326 			}
327 			case I_MAKE: {
328 				Aptr id, atr, val;
329 				id = pop();
330 				atr = pop();
331 				val = pop();
332 				if (stpflg) {
333 					printf("MAKE \t%5ld, %5ld, ", id, atr);
334 					if (val) printf("TRUE");
335 					else printf("FALSE");
336 				}
337 				make(id, atr, val);
338 				break;
339 			}
340 			case I_SET: {
341 				Aptr id, atr, val;
342 				id = pop();
343 				atr = pop();
344 				val = pop();
345 				if (stpflg) {
346 					printf("SET \t%5ld, %5ld, %5ld", id, atr, val);
347 				}
348 				set(id, atr, val);
349 				break;
350 			}
351 			case I_STRSET: {
352 				Aptr id, atr, str;
353 				id = pop();
354 				atr = pop();
355 				str = pop();
356 				if (stpflg) {
357 					printf("STRSET\t%5ld, %5ld, %5ld", id, atr, str);
358 				}
359 				setstr(id, atr, str);
360 				break;
361 			}
362 			case I_INCR: {
363 				Aptr id, atr, step;
364 				id = pop();
365 				atr = pop();
366 				step = pop();
367 				if (stpflg) {
368 					printf("INCR\t%5ld, %5ld, %5ld", id, atr, step);
369 				}
370 				incr(id, atr, step);
371 				break;
372 			}
373 			case I_DECR: {
374 				Aptr id, atr, step;
375 				id = pop();
376 				atr = pop();
377 				step = pop();
378 				if (stpflg) {
379 					printf("DECR\t%5ld, %5ld, %5ld", id, atr, step);
380 				}
381 				decr(id, atr, step);
382 				break;
383 			}
384 			case I_ATTRIBUTE: {
385 				Aptr id, atr;
386 				id = pop();
387 				atr = pop();
388 				if (stpflg)
389 					printf("ATTRIBUTE %5ld, %5ld", id, atr);
390 				push(attribute(id, atr));
391 				if (stpflg)
392 					printf("\t(%ld)", top());
393 				break;
394 			}
395 			case I_STRATTR: {
396 				Aptr id, atr;
397 				id = pop();
398 				atr = pop();
399 				if (stpflg)
400 					printf("STRATTR \t%5ld, %5ld", id, atr);
401 				push(strattr(id, atr));
402 				if (stpflg)
403 					printf("\t(%ld)", top());
404 				break;
405 			}
406 			case I_LOCATE: {
407 				Aptr id, whr;
408 				id = pop();
409 				whr = pop();
410 				if (stpflg)
411 					printf("LOCATE \t%5ld, %5ld", id, whr);
412 				locate(id, whr);
413 				break;
414 			}
415 			case I_WHERE: {
416 				Aptr id;
417 				id = pop();
418 				if (stpflg)
419 					printf("WHERE \t%5ld", id);
420 				push(where(id));
421 				if (stpflg)
422 					printf("\t\t(%ld)", top());
423 				break;
424 			}
425 			case I_HERE: {
426 				Aptr id;
427 				id = pop();
428 				if (stpflg)
429 					printf("HERE \t%5ld", id);
430 				push(isHere(id));
431 				if (stpflg) {
432 					if (top()) printf("\t(TRUE)");
433 					else printf("\t(FALSE)");
434 				}
435 				break;
436 			}
437 			case I_NEAR: {
438 				Aptr id;
439 				id = pop();
440 				if (stpflg)
441 					printf("NEAR \t%5ld", id);
442 				push(isNear(id));
443 				if (stpflg) {
444 					if (top()) printf("\t(TRUE)");
445 					else printf("\t(FALSE)");
446 				}
447 				break;
448 			}
449 			case I_USE: {
450 				Aptr act, scr;
451 				act = pop();
452 				scr = pop();
453 				if (stpflg)
454 					printf("USE \t%5ld, %5ld", act, scr);
455 				use(act, scr);
456 				break;
457 			}
458 			case I_IN: {
459 				Aptr obj, cnt;
460 				obj = pop();
461 				cnt = pop();
462 				if (stpflg)
463 					printf("IN \t%5ld, %5ld ", obj, cnt);
464 				push(in(obj, cnt));
465 				if (stpflg) {
466 					if (top()) printf("\t(TRUE)");
467 					else printf("\t(FALSE)");
468 				}
469 				break;
470 			}
471 			case I_DESCRIBE: {
472 				Aptr id;
473 				id = pop();
474 				if (stpflg) {
475 					printf("DESCRIBE \t%5ld\t", id);
476 					col = 34;     /* To format it better! */
477 				}
478 				describe(id);
479 				break;
480 			}
481 			case I_SAY: {
482 				Aptr id;
483 				id = pop();
484 				if (stpflg)
485 					printf("SAY \t%5ld\t\t\"", id);
486 				say(id);
487 				if (stpflg)
488 					printf("\"");
489 				break;
490 			}
491 			case I_SAYINT: {
492 				Aptr val;
493 				val = pop();
494 				if (stpflg)
495 					printf("SAYINT\t%5ld\t\t\"", val);
496 				sayint(val);
497 				if (stpflg)
498 					printf("\"");
499 				break;
500 			}
501 			case I_SAYSTR: {
502 				Aptr sayAdr;
503 				sayAdr = pop();
504 				if (stpflg)
505 					printf("SAYSTR\t%5ld\t\t\"", sayAdr);
506 				saystr((char *)sayAdr);
507 				if (stpflg)
508 					printf("\"");
509 				break;
510 			}
511 			case I_IF: {
512 				Aptr v;
513 				v = pop();
514 				if (stpflg) {
515 					printf("IF \t");
516 					if (v) printf(" TRUE");
517 					else printf("FALSE");
518 				}
519 				if_(v);
520 				break;
521 			}
522 			case I_ELSE: {
523 				if (stpflg)
524 					printf("ELSE");
525 				else_();
526 				break;
527 			}
528 			case I_ENDIF: {
529 				if (stpflg)
530 					printf("ENDIF");
531 				break;
532 			}
533 			case I_AND: {
534 				Aptr lh, rh;
535 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
536 					swap();
537 				rh = pop();
538 				lh = pop();
539 				if (stpflg) {
540 					printf("AND \t");
541 					if (lh) printf("TRUE, ");
542 					else printf("FALSE, ");
543 					if (rh) printf("TRUE");
544 					else printf("FALSE");
545 				}
546 				push(lh && rh);
547 				if (stpflg) {
548 					if (top()) printf("\t(TRUE)");
549 					else printf("\t(FALSE)");
550 				}
551 				break;
552 			}
553 			case I_OR: {
554 				Aptr lh, rh;
555 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
556 					swap();
557 				rh = pop();
558 				lh = pop();
559 				if (stpflg) {
560 					printf("OR \t");
561 					if (lh) printf("TRUE, ");
562 					else printf("FALSE, ");
563 					if (rh) printf("TRUE");
564 					else printf("FALSE");
565 				}
566 				push(lh || rh);
567 				if (stpflg) {
568 					if (top()) printf("\t(TRUE)");
569 					else printf("\t(FALSE)");
570 				}
571 				break;
572 			}
573 			case I_NE: {
574 				Aptr lh, rh;
575 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
576 					swap();
577 				rh = pop();
578 				lh = pop();
579 				if (stpflg)
580 					printf("NE \t%5ld, %5ld", lh, rh);
581 				push(lh != rh);
582 				if (stpflg) {
583 					if (top()) printf("\t(TRUE)");
584 					else printf("\t(FALSE)");
585 				}
586 				break;
587 			}
588 			case I_EQ: {
589 				Aptr lh, rh;
590 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
591 					swap();
592 				rh = pop();
593 				lh = pop();
594 				if (stpflg)
595 					printf("EQ \t%5ld, %5ld", lh, rh);
596 				push(lh == rh);
597 				if (stpflg) {
598 					if (top()) printf("\t(TRUE)");
599 					else printf("\t(FALSE)");
600 				}
601 				break;
602 			}
603 			case I_STREQ: {
604 				Aptr lh, rh;
605 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
606 					swap();
607 				rh = pop();
608 				lh = pop();
609 				if (stpflg)
610 					printf("STREQ \t%5ld, %5ld", lh, rh);
611 				push(streq((char *)lh, (char *)rh));
612 				if (stpflg) {
613 					if (top()) printf("\t(TRUE)");
614 					else printf("\t(FALSE)");
615 				}
616 				break;
617 			}
618 			case I_STREXACT: {
619 				Aptr lh, rh;
620 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
621 					swap();
622 				rh = pop();
623 				lh = pop();
624 				if (stpflg)
625 					printf("STREXACT \t%5ld, %5ld", lh, rh);
626 				push(strcmp((char *)lh, (char *)rh) == 0);
627 				if (stpflg) {
628 					if (top()) printf("\t(TRUE)");
629 					else printf("\t(FALSE)");
630 				}
631 				free((void *)lh);
632 				free((void *)rh);
633 				break;
634 			}
635 			case I_LE: {
636 				Aint lh, rh;
637 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
638 					swap();
639 				rh = pop();
640 				lh = pop();
641 				if (stpflg)
642 					printf("LE \t%5d, %5d", lh, rh);
643 				push(lh <= rh);
644 				if (stpflg) {
645 					if (top()) printf("\t(TRUE)");
646 					else printf("\t(FALSE)");
647 				}
648 				break;
649 			}
650 			case I_GE: {
651 				Aint lh, rh;
652 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
653 					swap();
654 				rh = pop();
655 				lh = pop();
656 				if (stpflg)
657 					printf("GE \t%5d, %5d", lh, rh);
658 				push(lh >= rh);
659 				if (stpflg) {
660 					if (top()) printf("\t(TRUE)");
661 					else printf("\t(FALSE)");
662 				}
663 				break;
664 			}
665 			case I_LT: {
666 				Aint lh, rh;
667 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
668 					swap();
669 				rh = pop();
670 				lh = pop();
671 				if (stpflg)
672 					printf("LT \t%5d, %5d", lh, rh);
673 				push((signed int)lh < (signed int)rh);
674 				if (stpflg) {
675 					if (top()) printf("\t(TRUE)");
676 					else printf("\t(FALSE)");
677 				}
678 				break;
679 			}
680 			case I_GT: {
681 				Aint lh, rh;
682 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
683 					swap();
684 				rh = pop();
685 				lh = pop();
686 				if (stpflg)
687 					printf("GT \t%5d, %5d", lh, rh);
688 				push(lh > rh);
689 				if (stpflg) {
690 					if (top()) printf("\t(TRUE)");
691 					else printf("\t(FALSE)");
692 				}
693 				break;
694 			}
695 			case I_PLUS: {
696 				Aint lh, rh;
697 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
698 					swap();
699 				rh = pop();
700 				lh = pop();
701 				if (stpflg)
702 					printf("PLUS \t%5d, %5d", lh, rh);
703 				push(lh + rh);
704 				if (stpflg)
705 					printf("\t(%ld)", top());
706 				break;
707 			}
708 			case I_MINUS: {
709 				Aint lh, rh;
710 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
711 					swap();
712 				rh = pop();
713 				lh = pop();
714 				if (stpflg)
715 					printf("MINUS \t%5d, %5d", lh, rh);
716 				push(lh - rh);
717 				if (stpflg)
718 					printf("\t(%ld)", top());
719 				break;
720 			}
721 			case I_MULT: {
722 				Aint lh, rh;
723 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
724 					swap();
725 				rh = pop();
726 				lh = pop();
727 				if (stpflg)
728 					printf("MULT \t%5d, %5d", lh, rh);
729 				push(lh * rh);
730 				if (stpflg)
731 					printf("\t(%ld)", top());
732 				break;
733 			}
734 			case I_DIV: {
735 				Aint lh, rh;
736 				if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
737 					swap();
738 				rh = pop();
739 				lh = pop();
740 				if (stpflg)
741 					printf("DIV \t%5d, %5d", lh, rh);
742 				push(lh / rh);
743 				if (stpflg)
744 					printf("\t(%ld)", top());
745 				break;
746 			}
747 			case I_NOT: {
748 				Aptr val;
749 				val = pop();
750 				if (stpflg) {
751 					printf("NOT \t");
752 					if (val) printf("TRUE");
753 					else printf("FALSE");
754 				}
755 				push(!val);
756 				if (stpflg) {
757 					if (top()) printf("\t\t(TRUE)");
758 					else printf("\t\t(FALSE)");
759 				}
760 				break;
761 			}
762 			case I_MAX: {
763 				Aptr atr, whr;
764 				atr = pop();
765 				whr = pop();
766 				if (stpflg)
767 					printf("MAX \t%5ld, %5ld", atr, whr);
768 				push(agrmax(atr, whr));
769 				if (stpflg)
770 					printf("\t(%ld)", top());
771 				break;
772 			}
773 			case I_SUM: {
774 				Aptr atr, whr;
775 				atr = pop();
776 				whr = pop();
777 				if (stpflg)
778 					printf("SUM \t%5ld, %5ld", atr, whr);
779 				push(agrsum(atr, whr));
780 				if (stpflg)
781 					printf("\t(%ld)", top());
782 				break;
783 			}
784 			case I_COUNT: {
785 				Aptr whr;
786 				whr = pop();
787 				if (stpflg)
788 					printf("COUNT \t%5ld", whr);
789 				push(agrcount(whr));
790 				if (stpflg)
791 					printf("\t(%ld)", top());
792 				break;
793 			}
794 			case I_RND: {
795 				Aptr  from, to;
796 				from = pop();
797 				to = pop();
798 				if (stpflg)
799 					printf("RANDOM \t%5ld, %5ld", from, to);
800 				push(rnd(from, to));
801 				if (stpflg)
802 					printf("\t(%ld)", top());
803 				break;
804 			}
805 			case I_BTW: {
806 				Aint low, high, val;
807 				high = pop();
808 				low = pop();
809 				val = pop();
810 				if (stpflg)
811 					printf("BETWEEN \t%5d, %5d, %5d", val, low, high);
812 				push(btw(val, low, high));
813 				if (stpflg)
814 					printf("\t(%ld)", top());
815 				break;
816 			}
817 			case I_CONTAINS: {
818 				Aptr string, substring;
819 				substring = pop();
820 				string = pop();
821 				if (stpflg)
822 					printf("CONTAINS \t%5ld, %5ld", string, substring);
823 				push(contains(string, substring));
824 				if (stpflg)
825 					printf("\t(%ld)", top());
826 				break;
827 			}
828 
829 			case I_DEPSTART:
830 				if (stpflg)
831 					printf("DEPSTART");
832 				depstart();
833 				break;
834 
835 			case I_DEPCASE:
836 				if (stpflg)
837 					printf("DEPCASE");
838 				depcase();
839 				break;
840 
841 			case I_DEPEXEC: {
842 				Aptr v;
843 				v = pop();
844 				if (stpflg) {
845 					printf("DEPEXEC \t");
846 					if (v) printf(" TRUE");
847 					else printf("FALSE");
848 				}
849 				depexec(v);
850 				break;
851 			}
852 
853 			case I_DEPELSE:
854 				if (stpflg)
855 					printf("DEPELSE");
856 				depcase();
857 				break;
858 
859 			case I_DEPEND:
860 				if (stpflg)
861 					printf("DEPEND");
862 				break;
863 
864 			case I_RETURN:
865 				if (stpflg)
866 					printf("RETURN\n--------------------------------------------------\n");
867 				pc = oldpc;
868 				return;
869 
870 			default:
871 				syserr("Unknown STMOP instruction.");
872 				break;
873 			}
874 			if (fail) {
875 				pc = oldpc;
876 				return;
877 			}
878 			break;
879 
880 		default:
881 			syserr("Unknown instruction class.");
882 			break;
883 		}
884 	}
885 }
886 
887 } // End of namespace Alan2
888 } // End of namespace Glk
889