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