/* 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 #include "glk/alan2/types.h" #include "glk/alan2/exe.h" #include "glk/alan2/inter.h" #include "glk/alan2/glkio.h" #include "glk/alan2/main.h" #include "glk/alan2/parse.h" #include "glk/alan2/stack.h" #include "glk/alan2/sysdep.h" namespace Glk { namespace Alan2 { /* PRIVATE DATA */ static int pc; static void if_(Aword v) { int lev = 1; Aword i; if (!v) { /* Skip to next ELSE or ENDIF on same level */ while (TRUE) { i = memory[pc++]; if (I_CLASS(i) == (Aword)C_STMOP) switch (I_OP(i)) { case I_ELSE: if (lev == 1) return; break; case I_IF: lev++; break; case I_ENDIF: lev--; if (lev == 0) return; break; } } } } static void else_() { int lev = 1; Aword i; while (TRUE) { /* Skip to ENDIF on the same level */ i = memory[pc++]; if (I_CLASS(i) == (Aword)C_STMOP) switch (I_OP(i)) { case I_ENDIF: lev--; if (lev == 0) return; break; case I_IF: lev++; break; } } } static void depstart() { /* A DEPSTART was executed so skip across the redundant DEPCASE to start at the first expression */ pc++; } static void swap() { Aptr v1 = pop(); Aptr v2 = pop(); push(v1); push(v2); } static void depexec(Aword v) { int lev = 1; Aword i; if (!v) /* The expression was not true, skip to next CASE on the same level which could be a DEPCASE or DEPELSE */ while (TRUE) { i = memory[pc++]; if (I_CLASS(i) == (Aword)C_STMOP) switch (I_OP(i)) { case I_DEPSTART: lev++; break; case I_DEPEND: if (lev == 1) return; lev--; break; case I_DEPCASE: case I_DEPELSE: if (lev == 1) return; break; } } } static void depcase() { int lev = 1; Aword i; /* Skip to end of DEPENDING block (next DEPEND on same level) because we have just executed a DEPCASE/DEPELSE statement as a result of a DEPCASE catching */ while (TRUE) { i = memory[pc++]; if (I_CLASS(i) == (Aword)C_STMOP) switch (I_OP(i)) { case I_DEPSTART: lev++; break; case I_DEPEND: lev--; if (lev == 0) return; break; } } } void interpret(Aaddr adr) { Aaddr oldpc; Aword i; if (stpflg) printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++"); oldpc = pc; pc = adr; while (TRUE) { if (stpflg) printf("\n%4x: ", pc); if (pc > (int)memTop) syserr("Interpreting outside program."); i = memory[pc++]; switch (I_CLASS(i)) { case C_CONST: if (stpflg) printf("PUSH \t%5ld", I_OP(i)); push(I_OP(i)); break; case C_CURVAR: switch (I_OP(i)) { case V_PARAM: if (stpflg) printf("PARAM \t%5ld\t\t(%ld)", top(), params[top() - 1].code); push(params[pop() - 1].code); break; case V_CURLOC: if (stpflg) printf("CURLOC \t\t\t(%d)", cur.loc); push(cur.loc); break; case V_CURACT: if (stpflg) printf("CURACT \t\t\t(%d)", cur.act); push(cur.act); break; case V_CURVRB: if (stpflg) printf("CURVRB \t\t\t(%d)", cur.vrb); push(cur.vrb); break; case V_SCORE: if (stpflg) printf("CURSCORE \t\t\t(%d)", cur.score); push(cur.score); break; default: syserr("Unknown CURVAR instruction."); break; } break; case C_STMOP: switch (I_OP(i)) { case I_PRINT: { Aptr fpos, len; fpos = pop(); len = pop(); if (stpflg) { printf("PRINT \t%5ld, %5ld\t\"", fpos, len); col = 34; /* To format it better! */ } print(fpos, len); if (stpflg) printf("\""); break; } case I_SYSTEM: { Aptr fpos, len; fpos = pop(); len = pop(); if (stpflg) { printf("SYSTEM \t%5ld, %5ld\t\"", fpos, len); col = 34; /* To format it better! */ } sys(fpos, len); break; } case I_GETSTR: { Aptr fpos, len; fpos = pop(); len = pop(); if (stpflg) printf("GETSTR\t%5ld, %5ld", fpos, len); getstr(fpos, len); if (stpflg) printf("\t(%ld)", top()); break; } case I_QUIT: { if (stpflg) printf("QUIT"); quit(); break; } case I_LOOK: { if (stpflg) printf("LOOK"); look(); break; } case I_SAVE: { if (stpflg) printf("SAVE"); save(); break; } case I_RESTORE: { if (stpflg) printf("RESTORE"); restore(); break; } case I_RESTART: { if (stpflg) printf("RESTART"); restart(); break; } case I_LIST: { Aptr cnt; cnt = pop(); if (stpflg) printf("LIST \t%5ld", cnt); list(cnt); break; } case I_EMPTY: { Aptr cnt, whr; cnt = pop(); whr = pop(); if (stpflg) printf("EMPTY \t%5ld, %5ld", cnt, whr); empty(cnt, whr); break; } case I_SCORE: { Aptr sc; sc = pop(); if (stpflg) printf("SCORE \t%5ld\t\t(%ld)", sc, scores[sc - 1]); score(sc); break; } case I_VISITS: { Aptr v; v = pop(); if (stpflg) printf("VISITS \t%5ld", v); visits(v); break; } case I_SCHEDULE: { Aptr evt, whr, aft; evt = pop(); whr = pop(); aft = pop(); if (stpflg) printf("SCHEDULE \t%5ld, %5ld, %5ld", evt, whr, aft); schedule(evt, whr, aft); break; } case I_CANCEL: { Aptr evt; evt = pop(); if (stpflg) printf("CANCEL \t%5ld", evt); cancl(evt); break; } case I_MAKE: { Aptr id, atr, val; id = pop(); atr = pop(); val = pop(); if (stpflg) { printf("MAKE \t%5ld, %5ld, ", id, atr); if (val) printf("TRUE"); else printf("FALSE"); } make(id, atr, val); break; } case I_SET: { Aptr id, atr, val; id = pop(); atr = pop(); val = pop(); if (stpflg) { printf("SET \t%5ld, %5ld, %5ld", id, atr, val); } set(id, atr, val); break; } case I_STRSET: { Aptr id, atr, str; id = pop(); atr = pop(); str = pop(); if (stpflg) { printf("STRSET\t%5ld, %5ld, %5ld", id, atr, str); } setstr(id, atr, str); break; } case I_INCR: { Aptr id, atr, step; id = pop(); atr = pop(); step = pop(); if (stpflg) { printf("INCR\t%5ld, %5ld, %5ld", id, atr, step); } incr(id, atr, step); break; } case I_DECR: { Aptr id, atr, step; id = pop(); atr = pop(); step = pop(); if (stpflg) { printf("DECR\t%5ld, %5ld, %5ld", id, atr, step); } decr(id, atr, step); break; } case I_ATTRIBUTE: { Aptr id, atr; id = pop(); atr = pop(); if (stpflg) printf("ATTRIBUTE %5ld, %5ld", id, atr); push(attribute(id, atr)); if (stpflg) printf("\t(%ld)", top()); break; } case I_STRATTR: { Aptr id, atr; id = pop(); atr = pop(); if (stpflg) printf("STRATTR \t%5ld, %5ld", id, atr); push(strattr(id, atr)); if (stpflg) printf("\t(%ld)", top()); break; } case I_LOCATE: { Aptr id, whr; id = pop(); whr = pop(); if (stpflg) printf("LOCATE \t%5ld, %5ld", id, whr); locate(id, whr); break; } case I_WHERE: { Aptr id; id = pop(); if (stpflg) printf("WHERE \t%5ld", id); push(where(id)); if (stpflg) printf("\t\t(%ld)", top()); break; } case I_HERE: { Aptr id; id = pop(); if (stpflg) printf("HERE \t%5ld", id); push(isHere(id)); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_NEAR: { Aptr id; id = pop(); if (stpflg) printf("NEAR \t%5ld", id); push(isNear(id)); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_USE: { Aptr act, scr; act = pop(); scr = pop(); if (stpflg) printf("USE \t%5ld, %5ld", act, scr); use(act, scr); break; } case I_IN: { Aptr obj, cnt; obj = pop(); cnt = pop(); if (stpflg) printf("IN \t%5ld, %5ld ", obj, cnt); push(in(obj, cnt)); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_DESCRIBE: { Aptr id; id = pop(); if (stpflg) { printf("DESCRIBE \t%5ld\t", id); col = 34; /* To format it better! */ } describe(id); break; } case I_SAY: { Aptr id; id = pop(); if (stpflg) printf("SAY \t%5ld\t\t\"", id); say(id); if (stpflg) printf("\""); break; } case I_SAYINT: { Aptr val; val = pop(); if (stpflg) printf("SAYINT\t%5ld\t\t\"", val); sayint(val); if (stpflg) printf("\""); break; } case I_SAYSTR: { Aptr sayAdr; sayAdr = pop(); if (stpflg) printf("SAYSTR\t%5ld\t\t\"", sayAdr); saystr((char *)sayAdr); if (stpflg) printf("\""); break; } case I_IF: { Aptr v; v = pop(); if (stpflg) { printf("IF \t"); if (v) printf(" TRUE"); else printf("FALSE"); } if_(v); break; } case I_ELSE: { if (stpflg) printf("ELSE"); else_(); break; } case I_ENDIF: { if (stpflg) printf("ENDIF"); break; } case I_AND: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) { printf("AND \t"); if (lh) printf("TRUE, "); else printf("FALSE, "); if (rh) printf("TRUE"); else printf("FALSE"); } push(lh && rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_OR: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) { printf("OR \t"); if (lh) printf("TRUE, "); else printf("FALSE, "); if (rh) printf("TRUE"); else printf("FALSE"); } push(lh || rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_NE: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("NE \t%5ld, %5ld", lh, rh); push(lh != rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_EQ: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("EQ \t%5ld, %5ld", lh, rh); push(lh == rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_STREQ: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("STREQ \t%5ld, %5ld", lh, rh); push(streq((char *)lh, (char *)rh)); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_STREXACT: { Aptr lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("STREXACT \t%5ld, %5ld", lh, rh); push(strcmp((char *)lh, (char *)rh) == 0); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); free((void *)lh); free((void *)rh); break; } case I_LE: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("LE \t%5ld, %5ld", lh, rh); push(lh <= rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_GE: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("GE \t%5ld, %5ld", lh, rh); push(lh >= rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_LT: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("LT \t%5ld, %5ld", lh, rh); push((signed int)lh < (signed int)rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_GT: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("GT \t%5ld, %5ld", lh, rh); push(lh > rh); if (stpflg) if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); break; } case I_PLUS: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("PLUS \t%5ld, %5ld", lh, rh); push(lh + rh); if (stpflg) printf("\t(%ld)", top()); break; } case I_MINUS: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("MINUS \t%5ld, %5ld", lh, rh); push(lh - rh); if (stpflg) printf("\t(%ld)", top()); break; } case I_MULT: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("MULT \t%5ld, %5ld", lh, rh); push(lh * rh); if (stpflg) printf("\t(%ld)", top()); break; } case I_DIV: { Aint lh, rh; if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ swap(); rh = pop(); lh = pop(); if (stpflg) printf("DIV \t%5ld, %5ld", lh, rh); push(lh / rh); if (stpflg) printf("\t(%ld)", top()); break; } case I_NOT: { Aptr val; val = pop(); if (stpflg) { printf("NOT \t"); if (val) printf("TRUE"); else printf("FALSE"); } push(!val); if (stpflg) if (top()) printf("\t\t(TRUE)"); else printf("\t\t(FALSE)"); break; } case I_MAX: { Aptr atr, whr; atr = pop(); whr = pop(); if (stpflg) printf("MAX \t%5ld, %5ld", atr, whr); push(agrmax(atr, whr)); if (stpflg) printf("\t(%ld)", top()); break; } case I_SUM: { Aptr atr, whr; atr = pop(); whr = pop(); if (stpflg) printf("SUM \t%5ld, %5ld", atr, whr); push(agrsum(atr, whr)); if (stpflg) printf("\t(%ld)", top()); break; } case I_COUNT: { Aptr whr; whr = pop(); if (stpflg) printf("COUNT \t%5ld", whr); push(agrcount(whr)); if (stpflg) printf("\t(%ld)", top()); break; } case I_RND: { Aptr from, to; from = pop(); to = pop(); if (stpflg) printf("RANDOM \t%5ld, %5ld", from, to); push(rnd(from, to)); if (stpflg) printf("\t(%ld)", top()); break; } case I_BTW: { Aint low, high, val; high = pop(); low = pop(); val = pop(); if (stpflg) printf("BETWEEN \t%5ld, %5ld, %5ld", val, low, high); push(btw(val, low, high)); if (stpflg) printf("\t(%ld)", top()); break; } case I_CONTAINS: { Aptr string, substring; substring = pop(); string = pop(); if (stpflg) printf("CONTAINS \t%5ld, %5ld", string, substring); push(contains(string, substring)); if (stpflg) printf("\t(%ld)", top()); break; } case I_DEPSTART: if (stpflg) printf("DEPSTART"); depstart(); break; case I_DEPCASE: if (stpflg) printf("DEPCASE"); depcase(); break; case I_DEPEXEC: { Aptr v; v = pop(); if (stpflg) { printf("DEPEXEC \t"); if (v) printf(" TRUE"); else printf("FALSE"); } depexec(v); break; } case I_DEPELSE: if (stpflg) printf("DEPELSE"); depcase(); break; case I_DEPEND: if (stpflg) printf("DEPEND"); break; case I_RETURN: if (stpflg) printf("RETURN\n--------------------------------------------------\n"); pc = oldpc; return; default: syserr("Unknown STMOP instruction."); break; } if (fail) { pc = oldpc; return; } break; default: syserr("Unknown instruction class."); break; } } } } // End of namespace Alan2 } // End of namespace Glk