From c3aafec1fb516d76fa03c0ffaf2248b90dada7b4 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Mon, 22 Jun 2009 16:30:35 +0000 Subject: Renaming parse.h and parse.cpp to expression.h and expression.cpp svn-id: r41773 --- engines/gob/expression.cpp | 1145 ++++++++++++++++++++++++++++++++++++++++++++ engines/gob/expression.h | 178 +++++++ engines/gob/gob.cpp | 1 - engines/gob/inter.cpp | 2 +- engines/gob/inter_v1.cpp | 2 +- engines/gob/inter_v2.cpp | 2 +- engines/gob/inter_v6.cpp | 2 +- engines/gob/module.mk | 2 +- engines/gob/parse.cpp | 1145 -------------------------------------------- engines/gob/parse.h | 178 ------- engines/gob/script.cpp | 2 +- 11 files changed, 1329 insertions(+), 1330 deletions(-) create mode 100644 engines/gob/expression.cpp create mode 100644 engines/gob/expression.h delete mode 100644 engines/gob/parse.cpp delete mode 100644 engines/gob/parse.h (limited to 'engines/gob') diff --git a/engines/gob/expression.cpp b/engines/gob/expression.cpp new file mode 100644 index 0000000000..eb465534c7 --- /dev/null +++ b/engines/gob/expression.cpp @@ -0,0 +1,1145 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/expression.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/script.h" +#include "gob/inter.h" + +namespace Gob { + +Expression::Stack::Stack(size_t size) { + opers = new byte[size]; + values = new int32[size]; + memset(opers , 0, size * sizeof(byte )); + memset(values, 0, size * sizeof(int32)); +} + +Expression::Stack::~Stack() { + delete[] opers; + delete[] values; +} + +Expression::StackFrame::StackFrame(const Stack &stack) { + opers = stack.opers - 1; + values = stack.values - 1; + pos = -1; +} + +void Expression::StackFrame::push(int count) { + opers += count; + values += count; + pos += count; +} + +void Expression::StackFrame::pop(int count) { + opers -= count; + values -= count; + pos -= count; +} + +Expression::Expression(GobEngine *vm) : _vm(vm) { + _resultStr[0] = 0; + _resultInt = 0; +} + +int32 Expression::encodePtr(byte *ptr, int type) { + int32 offset = 0; + + switch (type) { + case kExecPtr: + offset = _vm->_game->_script->getOffset(ptr); + break; + case kInterVar: + offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0)); + break; + case kResStr: + offset = ptr - ((byte *) _resultStr); + break; + default: + error("Expression::encodePtr(): Unknown pointer type"); + } + assert((offset & 0xF0000000) == 0); + return (type << 28) | offset; +} + +byte *Expression::decodePtr(int32 n) { + byte *ptr; + + switch (n >> 28) { + case kExecPtr: + ptr = _vm->_game->_script->getData(); + break; + case kInterVar: + ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0); + break; + case kResStr: + ptr = (byte *) _resultStr; + break; + default: + error("Expression::decodePtr(): Unknown pointer type"); + } + return ptr + (n & 0x0FFFFFFF); +} + +void Expression::skipExpr(char stopToken) { + int16 dimCount; + byte operation; + int16 num; + int16 dim; + + num = 0; + while (true) { + operation = _vm->_game->_script->readByte(); + + if ((operation >= 14) && (operation <= OP_FUNC)) { + switch (operation) { + case 14: + _vm->_game->_script->skip(4); + if (_vm->_game->_script->peekByte() == 97) + _vm->_game->_script->skip(1); + break; + + case OP_LOAD_VAR_INT16: + case OP_LOAD_VAR_INT8: + case OP_LOAD_IMM_INT16: + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + _vm->_game->_script->skip(2); + break; + + case OP_LOAD_IMM_INT32: + _vm->_game->_script->skip(4); + break; + + case OP_LOAD_IMM_INT8: + _vm->_game->_script->skip(1); + break; + + case OP_LOAD_IMM_STR: + _vm->_game->_script->skip(strlen(_vm->_game->_script->peekString()) + 1); + break; + + case OP_LOAD_VAR_STR: + _vm->_game->_script->skip(2); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + skipExpr(OP_END_MARKER); + } + break; + + case 15: + _vm->_game->_script->skip(2); + + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + dimCount = _vm->_game->_script->peekByte(2); + // skip header and dimensions + _vm->_game->_script->skip(3 + dimCount); + // skip indices + for (dim = 0; dim < dimCount; dim++) + skipExpr(OP_END_MARKER); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + skipExpr(OP_END_MARKER); + } + break; + + case OP_FUNC: + _vm->_game->_script->skip(1); + skipExpr(OP_END_EXPR); + } + continue; + } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) + + if (operation == OP_BEGIN_EXPR) { + num++; + continue; + } + + if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) + continue; + + if ((operation >= OP_OR) && (operation <= OP_NEQ)) + continue; + + if (operation == OP_END_EXPR) + num--; + + if (operation != stopToken) + continue; + + if ((stopToken != OP_END_EXPR) || (num < 0)) + return; + } +} + +void Expression::printExpr(char stopToken) { + // Expression printing disabled by default + return; + + int32 savedPos = _vm->_game->_script->pos(); + printExpr_internal(stopToken); + + // restore IP to start of expression + _vm->_game->_script->seek(savedPos); +} + +void Expression::printExpr_internal(char stopToken) { + int16 dimCount; + byte operation; + int16 num; + int16 dim; + byte *arrDesc; + byte func; + + num = 0; + while (true) { + operation = _vm->_game->_script->readByte(); + + if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { + // operands + + switch (operation) { + case OP_LOAD_VAR_INT16: // int16 variable load + debugN(5, "var16_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_VAR_INT8: // int8 variable load: + debugN(5, "var8_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_IMM_INT32: // int32/uint32 immediate + debugN(5, "%d", _vm->_game->_script->readInt32()); + break; + + case OP_LOAD_IMM_INT16: // int16 immediate + debugN(5, "%d", _vm->_game->_script->readInt16()); + break; + + case OP_LOAD_IMM_INT8: // int8 immediate + debugN(5, "%d", _vm->_game->_script->readInt8()); + break; + + case OP_LOAD_IMM_STR: // string immediate + debugN(5, "\42%s\42", _vm->_game->_script->readString()); + break; + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + debugN(5, "var_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_VAR_STR: // string variable load + debugN(5, "(&var_%d)", _vm->_game->_script->readUint16()); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + debugN(5, "{"); + printExpr_internal(OP_END_MARKER); // this also prints the closing } + } + break; + + case OP_ARRAY_INT8: // int8 array access + case OP_ARRAY_INT32: // int32 array access + case OP_ARRAY_INT16: // int16 array access + case OP_ARRAY_STR: // string array access + debugN(5, "\n"); + if (operation == OP_ARRAY_STR) + debugN(5, "(&"); + + debugN(5, "var_%d[", _vm->_game->_script->readInt16()); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + for (dim = 0; dim < dimCount; dim++) { + printExpr_internal(OP_END_MARKER); + debugN(5, " of %d", (int16) arrDesc[dim]); + if (dim != dimCount - 1) + debugN(5, ","); + } + debugN(5, "]"); + if (operation == OP_ARRAY_STR) + debugN(5, ")"); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "{"); + printExpr_internal(OP_END_MARKER); // this also prints the closing } + } + break; + + case OP_FUNC: // function + func = _vm->_game->_script->readByte(); + if (func == FUNC_SQR) + debugN(5, "sqr("); + else if (func == FUNC_RAND) + debugN(5, "rand("); + else if (func == FUNC_ABS) + debugN(5, "abs("); + else if ((func == FUNC_SQRT1) || (func == FUNC_SQRT2) || (func == FUNC_SQRT3)) + debugN(5, "sqrt("); + else + debugN(5, "id("); + printExpr_internal(OP_END_EXPR); + break; + } + continue; + } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) + + // operators + switch (operation) { + case OP_BEGIN_EXPR: + debugN(5, "("); + break; + + case OP_NOT: + debugN(5, "!"); + break; + + case OP_END_EXPR: + debugN(5, ")"); + break; + + case OP_NEG: + debugN(5, "-"); + break; + + case OP_ADD: + debugN(5, "+"); + break; + + case OP_SUB: + debugN(5, "-"); + break; + + case OP_BITOR: + debugN(5, "|"); + break; + + case OP_MUL: + debugN(5, "*"); + break; + + case OP_DIV: + debugN(5, "/"); + break; + + case OP_MOD: + debugN(5, "%%"); + break; + + case OP_BITAND: + debugN(5, "&"); + break; + + case OP_OR: + debugN(5, "||"); + break; + + case 31: + debugN(5, "&&"); + break; + + case OP_LESS: + debugN(5, "<"); + break; + + case OP_LEQ: + debugN(5, "<="); + break; + + case OP_GREATER: + debugN(5, ">"); + break; + + case OP_GEQ: + debugN(5, ">="); + break; + + case OP_EQ: + debugN(5, "=="); + break; + + case OP_NEQ: + debugN(5, "!="); + break; + + case 99: + debugN(5, "\n"); + break; + + case OP_END_MARKER: + debugN(5, "}"); + if (stopToken != OP_END_MARKER) { + debugN(5, "Closing paren without opening?"); + } + break; + + default: + debugN(5, "<%d>", (int16) operation); + error("Expression::printExpr(): invalid operator in expression"); + break; + } + + if (operation == OP_BEGIN_EXPR) { + num++; + continue; + } + + if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) + continue; + + if ((operation >= OP_OR) && (operation <= OP_NEQ)) + continue; + + if (operation == OP_END_EXPR) + num--; + + if (operation == stopToken) { + if ((stopToken != OP_END_EXPR) || (num < 0)) { + return; + } + } + } +} + + +void Expression::printVarIndex() { + byte *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + + int32 pos = _vm->_game->_script->pos(); + + operation = _vm->_game->_script->readByte(); + switch (operation) { + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_STR: + temp = _vm->_game->_script->readUint16() * 4; + debugN(5, "&var_%d", temp); + if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "+"); + printExpr(OP_END_MARKER); + } + break; + + case OP_ARRAY_INT32: + case OP_ARRAY_STR: + debugN(5, "&var_%d[", _vm->_game->_script->readUint16()); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + for (dim = 0; dim < dimCount; dim++) { + printExpr(OP_END_MARKER); + debugN(5, " of %d", (int16) arrDesc[dim]); + if (dim != dimCount - 1) + debugN(5, ","); + } + debugN(5, "]"); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "+"); + printExpr(OP_END_MARKER); + } + break; + + default: + debugN(5, "var_0"); + break; + } + debugN(5, "\n"); + + _vm->_game->_script->seek(pos); + return; +} + +int Expression::cmpHelper(const StackFrame &stackFrame) { + byte type = stackFrame.opers[-3]; + int cmpTemp = 0; + + if (type == OP_LOAD_IMM_INT16) { + cmpTemp = (int)stackFrame.values[-3] - (int)stackFrame.values[-1]; + } else if (type == OP_LOAD_IMM_STR) { + if ((char *)decodePtr(stackFrame.values[-3]) != _resultStr) { + strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-3])); + stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); + } + cmpTemp = strcmp(_resultStr, (char *)decodePtr(stackFrame.values[-1])); + } + + return cmpTemp; +} + +bool Expression::getVarBase(uint32 &varBase, bool mindStop, + uint16 *size, uint16 *type) { + + varBase = 0; + + byte operation = _vm->_game->_script->peekByte(); + while ((operation == 14) || (operation == 15)) { + _vm->_game->_script->skip(1); + + if (operation == 14) { + // Add a direct offset + + varBase += _vm->_game->_script->readInt16() * 4; + + if (size) + *size = _vm->_game->_script->peekUint16(); + if (type) + *type = 14; + + _vm->_game->_script->skip(2); + + debugC(2, kDebugParser, "varBase: %d, by %d", varBase, operation); + + if (_vm->_game->_script->peekByte() != 97) { + if (mindStop) + return true; + } else + _vm->_game->_script->skip(1); + + } else if (operation == 15) { + // Add an offset from an array + + varBase += _vm->_game->_script->readInt16() * 4; + + uint16 offset1 = _vm->_game->_script->readUint16(); + + if (size) + *size = offset1; + if (type) + *type = 15; + + uint8 dimCount = _vm->_game->_script->readByte(); + byte *dimArray = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + + _vm->_game->_script->skip(dimCount); + + uint16 offset2 = 0; + for (int i = 0; i < dimCount; i++) { + int16 dim = CLIP(parseValExpr(OP_END_MARKER), 0, dimArray[i] - 1); + + offset2 = offset2 * dimArray[i] + dim; + } + + varBase += offset2 * offset1 * 4; + + debugC(2, kDebugParser, "varBase: %d, by %d", varBase, operation); + + if (_vm->_game->_script->peekByte() != 97) { + if (mindStop) + return true; + } else + _vm->_game->_script->skip(1); + } + + operation = _vm->_game->_script->peekByte(); + } + + return false; +} + +int16 Expression::parseVarIndex(uint16 *size, uint16 *type) { + int16 temp2; + byte *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + int16 offset; + int16 val; + uint32 varBase; + + if (getVarBase(varBase, true, size, type)) + return varBase; + + operation = _vm->_game->_script->readByte(); + + if (size) + *size = 0; + if (type) + *type = operation; + + debugC(5, kDebugParser, "var parse = %d", operation); + switch (operation) { + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + temp = _vm->_game->_script->readInt16(); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parseValExpr(OP_END_MARKER); + offset = arrDesc[dim] * offset + temp2; + } + if (operation == OP_ARRAY_INT8) + return varBase + temp + offset; + if (operation == OP_ARRAY_INT32) + return varBase + (temp + offset) * 4; + if (operation == OP_ARRAY_INT16) + return varBase + (temp + offset) * 2; + temp *= 4; + offset *= 4; + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp += parseValExpr(OP_END_MARKER); + } + return varBase + offset * _vm->_global->_inter_animDataSize + temp; + + case OP_LOAD_VAR_INT16: + return varBase + _vm->_game->_script->readInt16() * 2; + + case OP_LOAD_VAR_INT8: + return varBase + _vm->_game->_script->readInt16(); + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + case OP_LOAD_VAR_STR: + temp = _vm->_game->_script->readInt16() * 4; + debugC(5, kDebugParser, "oper = %d", _vm->_game->_script->peekInt16()); + if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + val = parseValExpr(OP_END_MARKER); + temp += val; + debugC(5, kDebugParser, "parse subscript = %d", val); + } + return varBase + temp; + + default: + return 0; + } +} + +int16 Expression::parseValExpr(byte stopToken) { + parseExpr(stopToken, 0); + + return _resultInt; +} + +// Load a value according to the operation +void Expression::loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame) { + int16 dimCount; + int16 temp; + int16 temp2; + int16 offset; + int16 dim; + byte *arrDescPtr; + int32 prevPrevVal; + int32 prevVal; + int32 curVal; + + switch (operation) { + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + *stackFrame.opers = (operation == OP_ARRAY_STR) ? OP_LOAD_IMM_STR : OP_LOAD_IMM_INT16; + temp = _vm->_game->_script->readInt16(); + dimCount = _vm->_game->_script->readByte(); + arrDescPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parseValExpr(OP_END_MARKER); + offset = offset * arrDescPtr[dim] + temp2; + } + if (operation == OP_ARRAY_INT8) + *stackFrame.values = (int8) READ_VARO_UINT8(varBase + temp + offset); + else if (operation == OP_ARRAY_INT32) + *stackFrame.values = READ_VARO_UINT32(varBase + temp * 4 + offset * 4); + else if (operation == OP_ARRAY_INT16) + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + temp * 2 + offset * 2); + else if (operation == OP_ARRAY_STR) { + *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8( + varBase + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), + kInterVar); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp2 = parseValExpr(OP_END_MARKER); + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT8(varBase + temp * 4 + + offset * 4 * _vm->_global->_inter_animDataSize + temp2); + } + } + break; + + case OP_LOAD_VAR_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 2); + break; + + case OP_LOAD_VAR_INT8: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int8) READ_VARO_UINT8(varBase + _vm->_game->_script->readInt16()); + break; + + case OP_LOAD_IMM_INT32: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt32(); + break; + + case OP_LOAD_IMM_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt16(); + break; + + case OP_LOAD_IMM_INT8: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt8(); + break; + + case OP_LOAD_IMM_STR: + *stackFrame.opers = OP_LOAD_IMM_STR; + *stackFrame.values = encodePtr((byte *) _vm->_game->_script->readString(), kExecPtr); + break; + + case OP_LOAD_VAR_INT32: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT32(varBase + _vm->_game->_script->readInt16() * 4); + break; + + case OP_LOAD_VAR_INT32_AS_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 4); + break; + + case OP_LOAD_VAR_STR: + *stackFrame.opers = OP_LOAD_IMM_STR; + temp = _vm->_game->_script->readInt16() * 4; + *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8(varBase + temp), kInterVar); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp += parseValExpr(OP_END_MARKER); + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT8(varBase + temp); + } + break; + + case OP_FUNC: + operation = _vm->_game->_script->readByte(); + parseExpr(OP_END_EXPR, 0); + + switch (operation) { + case FUNC_SQRT1: + case FUNC_SQRT2: + case FUNC_SQRT3: + curVal = 1; + prevVal = 1; + + do { + prevPrevVal = prevVal; + prevVal = curVal; + curVal = (curVal + _resultInt / curVal) / 2; + } while ((curVal != prevVal) && (curVal != prevPrevVal)); + _resultInt = curVal; + break; + + case FUNC_SQR: + _resultInt = + _resultInt * _resultInt; + break; + + case FUNC_ABS: + if (_resultInt < 0) + _resultInt = -_resultInt; + break; + + case FUNC_RAND: + _resultInt = + _vm->_util->getRandom(_resultInt); + break; + } + + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _resultInt; + break; + } +} + +void Expression::simpleArithmetic1(StackFrame &stackFrame) { + switch (stackFrame.opers[-1]) { + case OP_ADD: + if (stackFrame.opers[-2] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stackFrame.values[-2]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-2])); + stackFrame.values[-2] = encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[0])); + stackFrame.pop(2); + } + break; + + case OP_MUL: + stackFrame.values[-2] *= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-2] /= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-2] %= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-2] &= stackFrame.values[0]; + stackFrame.pop(2); + break; + } +} + +void Expression::simpleArithmetic2(StackFrame &stackFrame) { + if (stackFrame.pos > 1) { + if (stackFrame.opers[-2] == OP_NEG) { + stackFrame.opers[-2] = OP_LOAD_IMM_INT16; + stackFrame.values[-2] = -stackFrame.values[-1]; + stackFrame.pop(); + } else if (stackFrame.opers[-2] == OP_NOT) { + stackFrame.opers[-2] = (stackFrame.opers[-1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(); + } + } + + if (stackFrame.pos > 2) { + switch (stackFrame.opers[-2]) { + case OP_MUL: + stackFrame.values[-3] *= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-3] /= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-3] %= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-3] &= stackFrame.values[-1]; + stackFrame.pop(2); + break; + } + } + +} + +// Complex arithmetics with brackets +bool Expression::complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart) { + switch (stackFrame.opers[-2]) { + case OP_ADD: + if (stack.opers[brackStart] == OP_LOAD_IMM_INT16) { + stack.values[brackStart] += stackFrame.values[-1]; + } else if (stack.opers[brackStart] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stack.values[brackStart]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stack.values[brackStart])); + stack.values[brackStart] = + encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); + } + stackFrame.pop(2); + break; + + case OP_SUB: + stack.values[brackStart] -= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITOR: + stack.values[brackStart] |= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MUL: + stackFrame.values[-3] *= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-3] /= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-3] %= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-3] &= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_OR: + // (x OR false) == x + // (x OR true) == true + if (stackFrame.opers[-3] == GOB_FALSE) + stackFrame.opers[-3] = stackFrame.opers[-1]; + stackFrame.pop(2); + break; + + case OP_AND: + // (x AND false) == false + // (x AND true) == x + if (stackFrame.opers[-3] == GOB_TRUE) + stackFrame.opers[-3] = stackFrame.opers[-1]; + stackFrame.pop(2); + break; + + case OP_LESS: + stackFrame.opers[-3] = (cmpHelper(stackFrame) < 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_LEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) <= 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_GREATER: + stackFrame.opers[-3] = (cmpHelper(stackFrame) > 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_GEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) >= 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_EQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) == 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_NEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) != 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + default: + return true; + } + + return false; +} + +// Assign the result to the appropriate _result variable +void Expression::getResult(byte operation, int32 value, byte *type) { + if (type != 0) + *type = operation; + + switch (operation) { + case OP_NOT: + if (type != 0) + *type ^= 1; + break; + + case OP_LOAD_IMM_INT16: + _resultInt = value; + break; + + case OP_LOAD_IMM_STR: + if ((char *) decodePtr(value) != _resultStr) + strcpy(_resultStr, (char *) decodePtr(value)); + break; + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + break; + + default: + _resultInt = 0; + if (type != 0) + *type = OP_LOAD_IMM_INT16; + break; + } +} + +int16 Expression::parseExpr(byte stopToken, byte *type) { + Stack stack; + StackFrame stackFrame(stack); + byte operation; + bool escape; + int16 brackStart; + uint32 varBase; + + while (true) { + getVarBase(varBase); + + stackFrame.push(); + + operation = _vm->_game->_script->readByte(); + if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { + + loadValue(operation, varBase, stackFrame); + + if ((stackFrame.pos > 0) && ((stackFrame.opers[-1] == OP_NEG) || (stackFrame.opers[-1] == OP_NOT))) { + stackFrame.pop(); + + if (*stackFrame.opers == OP_NEG) { + *stackFrame.opers = OP_LOAD_IMM_INT16; + stackFrame.values[0] = -stackFrame.values[1]; + } else + *stackFrame.opers = (stackFrame.opers[1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; + } + + if (stackFrame.pos <= 0) + continue; + + simpleArithmetic1(stackFrame); + + continue; + } // (op >= OP_ARRAY_INT8) && (op <= OP_FUNC) + + if ((operation == stopToken) || (operation == OP_OR) || + (operation == OP_AND) || (operation == OP_END_EXPR)) { + while (stackFrame.pos >= 2) { + escape = false; + if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && + ((operation == OP_END_EXPR) || (operation == stopToken))) { + stackFrame.opers[-2] = stackFrame.opers[-1]; + if ((stackFrame.opers[-2] == OP_LOAD_IMM_INT16) || (stackFrame.opers[-2] == OP_LOAD_IMM_STR)) + stackFrame.values[-2] = stackFrame.values[-1]; + + stackFrame.pop(); + + simpleArithmetic2(stackFrame); + + if (operation != stopToken) + break; + } // if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && ...) + + for (brackStart = (stackFrame.pos - 2); (brackStart > 0) && + (stack.opers[brackStart] < OP_OR) && (stack.opers[brackStart] != OP_BEGIN_EXPR); + brackStart--) + ; + + if ((stack.opers[brackStart] >= OP_OR) || (stack.opers[brackStart] == OP_BEGIN_EXPR)) + brackStart++; + + if (complexArithmetic(stack, stackFrame, brackStart)) + break; + + } // while (stackFrame.pos >= 2) + + if ((operation == OP_OR) || (operation == OP_AND)) { + if (stackFrame.opers[-1] == OP_LOAD_IMM_INT16) { + if (stackFrame.values[-1] != 0) + stackFrame.opers[-1] = GOB_TRUE; + else + stackFrame.opers[-1] = GOB_FALSE; + } + + if (((operation == OP_OR) && (stackFrame.opers[-1] == GOB_TRUE)) || + ((operation == OP_AND) && (stackFrame.opers[-1] == GOB_FALSE))) { + if ((stackFrame.pos > 1) && (stackFrame.opers[-2] == OP_BEGIN_EXPR)) { + skipExpr(OP_END_EXPR); + stackFrame.opers[-2] = stackFrame.opers[-1]; + stackFrame.pop(2); + } else { + skipExpr(stopToken); + } + operation = _vm->_game->_script->peekByte(-1); + if ((stackFrame.pos > 0) && (stackFrame.opers[-1] == OP_NOT)) { + if (stackFrame.opers[0] == GOB_FALSE) + stackFrame.opers[-1] = GOB_TRUE; + else + stackFrame.opers[-1] = GOB_FALSE; + + stackFrame.pop(); + } + } else + stackFrame.opers[0] = operation; + } else + stackFrame.pop(); + + if (operation != stopToken) + continue; + + getResult(stack.opers[0], stack.values[0], type); + + return 0; + } // (operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR) + + if ((operation < OP_NEG) || (operation > OP_NOT)) { + if ((operation < OP_LESS) || (operation > OP_NEQ)) + continue; + + if (stackFrame.pos > 2) { + if (stackFrame.opers[-2] == OP_ADD) { + if (stackFrame.opers[-3] == OP_LOAD_IMM_INT16) { + stackFrame.values[-3] += stackFrame.values[-1]; + } else if (stackFrame.opers[-3] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stackFrame.values[-3]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-3])); + stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); + } + stackFrame.pop(2); + + } else if (stackFrame.opers[-2] == OP_SUB) { + stackFrame.values[-3] -= stackFrame.values[-1]; + stackFrame.pop(2); + } else if (stackFrame.opers[-2] == OP_BITOR) { + stackFrame.values[-3] |= stackFrame.values[-1]; + stackFrame.pop(2); + } + } + } + *stackFrame.opers = operation; + } +} + +int32 Expression::getResultInt() { + return _resultInt; +} + +char *Expression::getResultStr() { + return _resultStr; +} + +} // End of namespace Gob diff --git a/engines/gob/expression.h b/engines/gob/expression.h new file mode 100644 index 0000000000..894704e2a9 --- /dev/null +++ b/engines/gob/expression.h @@ -0,0 +1,178 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_EXPRESSION_H +#define GOB_EXPRESSION_H + +#include "common/scummsys.h" + +namespace Gob { + +class GobEngine; + +enum { + OP_NEG = 1, + OP_ADD = 2, + OP_SUB = 3, + OP_BITOR = 4, + OP_MUL = 5, + OP_DIV = 6, + OP_MOD = 7, + OP_BITAND = 8, + OP_BEGIN_EXPR = 9, + OP_END_EXPR = 10, + OP_NOT = 11, + + OP_END_MARKER = 12, // Marks end of an array or string + + + OP_ARRAY_INT8 = 16, + OP_LOAD_VAR_INT16 = 17, + OP_LOAD_VAR_INT8 = 18, + OP_LOAD_IMM_INT32 = 19, + OP_LOAD_IMM_INT16 = 20, + OP_LOAD_IMM_INT8 = 21, + OP_LOAD_IMM_STR = 22, + OP_LOAD_VAR_INT32 = 23, + OP_LOAD_VAR_INT32_AS_INT16 = 24, + OP_LOAD_VAR_STR = 25, + OP_ARRAY_INT32 = 26, + OP_ARRAY_INT16 = 27, + OP_ARRAY_STR = 28, + + OP_FUNC = 29, + + OP_OR = 30, // Logical OR + OP_AND = 31, // Logical AND + OP_LESS = 32, + OP_LEQ = 33, + OP_GREATER = 34, + OP_GEQ = 35, + OP_EQ = 36, + OP_NEQ = 37 +}; + +enum { + FUNC_SQRT1 = 0, + FUNC_SQRT2 = 1, + FUNC_SQRT3 = 6, + + FUNC_SQR = 5, + FUNC_ABS = 7, + FUNC_RAND = 10 +}; + +enum { + TYPE_IMM_INT8 = OP_LOAD_IMM_INT8, // 21 + TYPE_IMM_INT32 = OP_LOAD_IMM_INT32, // 19 + TYPE_IMM_INT16 = OP_LOAD_IMM_INT16, // 20 + TYPE_IMM_STR = OP_LOAD_IMM_STR, // 22 + TYPE_VAR_INT8 = OP_LOAD_VAR_INT8, // 18 + TYPE_VAR_INT16 = OP_LOAD_VAR_INT16, // 17 + TYPE_VAR_INT32 = OP_LOAD_VAR_INT32, // 23 + TYPE_VAR_STR = OP_LOAD_VAR_STR, // 25 + TYPE_ARRAY_INT8 = OP_ARRAY_INT8, // 16 + TYPE_ARRAY_INT16 = OP_ARRAY_INT16, // 27 + TYPE_ARRAY_INT32 = OP_ARRAY_INT32, // 26 + TYPE_ARRAY_STR = OP_ARRAY_STR, // 28 + TYPE_VAR_INT32_AS_INT16 = OP_LOAD_VAR_INT32_AS_INT16 // 24 +}; + +enum { + // FIXME: The following two 'truth values' are stored inside the list + // of "operators". So they somehow coincide with OP_LOAD_VAR_INT32 + // and OP_LOAD_VAR_INT32_AS_INT16. I haven't yet quite understood + // how, resp. what that means. You have been warned. + GOB_TRUE = 24, + GOB_FALSE = 23 +}; + +class Expression { +public: + Expression(GobEngine *vm); + virtual ~Expression() {} + + void skipExpr(char stopToken); + void printExpr(char stopToken); + void printVarIndex(void); + + int16 parseVarIndex(uint16 *size = 0, uint16 *type = 0); + int16 parseValExpr(byte stopToken = 99); + int16 parseExpr(byte stopToken, byte *type); + + int32 getResultInt(); + char *getResultStr(); + +private: + class Stack { + public: + byte *opers; + int32 *values; + + Stack(size_t size = 20); + ~Stack(); + }; + class StackFrame { + public: + byte *opers; + int32 *values; + int16 pos; + + StackFrame(const Stack &stack); + + void push(int count = 1); + void pop(int count = 1); + }; + + enum PointerType { + kExecPtr = 0, + kInterVar = 1, + kResStr = 2 + }; + + GobEngine *_vm; + + int32 _resultInt; + char _resultStr[200]; + + int32 encodePtr(byte *ptr, int type); + byte *decodePtr(int32 n); + + void printExpr_internal(char stopToken); + + bool getVarBase(uint32 &varBase, bool mindStop = false, + uint16 *size = 0, uint16 *type = 0); + int cmpHelper(const StackFrame &stackFrame); + void loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame); + + void simpleArithmetic1(StackFrame &stackFrame); + void simpleArithmetic2(StackFrame &stackFrame); + bool complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart); + void getResult(byte operation, int32 value, byte *type); +}; + +} // End of namespace Gob + +#endif // GOB_EXPRESSION_H diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 3f448e7eb8..f1a96a7a65 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -47,7 +47,6 @@ #include "gob/map.h" #include "gob/mult.h" #include "gob/palanim.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/videoplayer.h" #include "gob/save/saveload.h" diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 08bec120d9..8be07034c6 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -33,10 +33,10 @@ #include "gob/util.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/expression.h" #include "gob/script.h" #include "gob/scenery.h" #include "gob/sound/sound.h" -#include "gob/parse.h" namespace Gob { diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 0d14818dd9..388e87743a 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -34,8 +34,8 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/expression.h" #include "gob/script.h" -#include "gob/parse.h" #include "gob/goblin.h" #include "gob/inter.h" #include "gob/map.h" diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index acd36137f0..c4395bb329 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -36,8 +36,8 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/expression.h" #include "gob/script.h" -#include "gob/parse.h" #include "gob/goblin.h" #include "gob/map.h" #include "gob/mult.h" diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp index cd510dce1e..c9fed80578 100644 --- a/engines/gob/inter_v6.cpp +++ b/engines/gob/inter_v6.cpp @@ -32,8 +32,8 @@ #include "gob/helper.h" #include "gob/global.h" #include "gob/game.h" +#include "gob/expression.h" #include "gob/script.h" -#include "gob/parse.h" #include "gob/draw.h" #include "gob/sound/sound.h" #include "gob/videoplayer.h" diff --git a/engines/gob/module.mk b/engines/gob/module.mk index c988d616f0..550bc0f6f5 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -9,6 +9,7 @@ MODULE_OBJS := \ draw_bargon.o \ draw_fascin.o \ driver_vga.o \ + expression.o \ game.o \ game_v1.o \ game_v2.o \ @@ -43,7 +44,6 @@ MODULE_OBJS := \ mult_v1.o \ mult_v2.o \ palanim.o \ - parse.o \ scenery.o \ scenery_v1.o \ scenery_v2.o \ diff --git a/engines/gob/parse.cpp b/engines/gob/parse.cpp deleted file mode 100644 index cd03612c14..0000000000 --- a/engines/gob/parse.cpp +++ /dev/null @@ -1,1145 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/parse.h" -#include "gob/global.h" -#include "gob/game.h" -#include "gob/script.h" -#include "gob/inter.h" - -namespace Gob { - -Expression::Stack::Stack(size_t size) { - opers = new byte[size]; - values = new int32[size]; - memset(opers , 0, size * sizeof(byte )); - memset(values, 0, size * sizeof(int32)); -} - -Expression::Stack::~Stack() { - delete[] opers; - delete[] values; -} - -Expression::StackFrame::StackFrame(const Stack &stack) { - opers = stack.opers - 1; - values = stack.values - 1; - pos = -1; -} - -void Expression::StackFrame::push(int count) { - opers += count; - values += count; - pos += count; -} - -void Expression::StackFrame::pop(int count) { - opers -= count; - values -= count; - pos -= count; -} - -Expression::Expression(GobEngine *vm) : _vm(vm) { - _resultStr[0] = 0; - _resultInt = 0; -} - -int32 Expression::encodePtr(byte *ptr, int type) { - int32 offset = 0; - - switch (type) { - case kExecPtr: - offset = _vm->_game->_script->getOffset(ptr); - break; - case kInterVar: - offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0)); - break; - case kResStr: - offset = ptr - ((byte *) _resultStr); - break; - default: - error("Expression::encodePtr(): Unknown pointer type"); - } - assert((offset & 0xF0000000) == 0); - return (type << 28) | offset; -} - -byte *Expression::decodePtr(int32 n) { - byte *ptr; - - switch (n >> 28) { - case kExecPtr: - ptr = _vm->_game->_script->getData(); - break; - case kInterVar: - ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0); - break; - case kResStr: - ptr = (byte *) _resultStr; - break; - default: - error("Expression::decodePtr(): Unknown pointer type"); - } - return ptr + (n & 0x0FFFFFFF); -} - -void Expression::skipExpr(char stopToken) { - int16 dimCount; - byte operation; - int16 num; - int16 dim; - - num = 0; - while (true) { - operation = _vm->_game->_script->readByte(); - - if ((operation >= 14) && (operation <= OP_FUNC)) { - switch (operation) { - case 14: - _vm->_game->_script->skip(4); - if (_vm->_game->_script->peekByte() == 97) - _vm->_game->_script->skip(1); - break; - - case OP_LOAD_VAR_INT16: - case OP_LOAD_VAR_INT8: - case OP_LOAD_IMM_INT16: - case OP_LOAD_VAR_INT32: - case OP_LOAD_VAR_INT32_AS_INT16: - _vm->_game->_script->skip(2); - break; - - case OP_LOAD_IMM_INT32: - _vm->_game->_script->skip(4); - break; - - case OP_LOAD_IMM_INT8: - _vm->_game->_script->skip(1); - break; - - case OP_LOAD_IMM_STR: - _vm->_game->_script->skip(strlen(_vm->_game->_script->peekString()) + 1); - break; - - case OP_LOAD_VAR_STR: - _vm->_game->_script->skip(2); - if (_vm->_game->_script->peekByte() == 13) { - _vm->_game->_script->skip(1); - skipExpr(OP_END_MARKER); - } - break; - - case 15: - _vm->_game->_script->skip(2); - - case OP_ARRAY_INT8: - case OP_ARRAY_INT32: - case OP_ARRAY_INT16: - case OP_ARRAY_STR: - dimCount = _vm->_game->_script->peekByte(2); - // skip header and dimensions - _vm->_game->_script->skip(3 + dimCount); - // skip indices - for (dim = 0; dim < dimCount; dim++) - skipExpr(OP_END_MARKER); - - if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { - _vm->_game->_script->skip(1); - skipExpr(OP_END_MARKER); - } - break; - - case OP_FUNC: - _vm->_game->_script->skip(1); - skipExpr(OP_END_EXPR); - } - continue; - } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) - - if (operation == OP_BEGIN_EXPR) { - num++; - continue; - } - - if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) - continue; - - if ((operation >= OP_OR) && (operation <= OP_NEQ)) - continue; - - if (operation == OP_END_EXPR) - num--; - - if (operation != stopToken) - continue; - - if ((stopToken != OP_END_EXPR) || (num < 0)) - return; - } -} - -void Expression::printExpr(char stopToken) { - // Expression printing disabled by default - return; - - int32 savedPos = _vm->_game->_script->pos(); - printExpr_internal(stopToken); - - // restore IP to start of expression - _vm->_game->_script->seek(savedPos); -} - -void Expression::printExpr_internal(char stopToken) { - int16 dimCount; - byte operation; - int16 num; - int16 dim; - byte *arrDesc; - byte func; - - num = 0; - while (true) { - operation = _vm->_game->_script->readByte(); - - if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { - // operands - - switch (operation) { - case OP_LOAD_VAR_INT16: // int16 variable load - debugN(5, "var16_%d", _vm->_game->_script->readUint16()); - break; - - case OP_LOAD_VAR_INT8: // int8 variable load: - debugN(5, "var8_%d", _vm->_game->_script->readUint16()); - break; - - case OP_LOAD_IMM_INT32: // int32/uint32 immediate - debugN(5, "%d", _vm->_game->_script->readInt32()); - break; - - case OP_LOAD_IMM_INT16: // int16 immediate - debugN(5, "%d", _vm->_game->_script->readInt16()); - break; - - case OP_LOAD_IMM_INT8: // int8 immediate - debugN(5, "%d", _vm->_game->_script->readInt8()); - break; - - case OP_LOAD_IMM_STR: // string immediate - debugN(5, "\42%s\42", _vm->_game->_script->readString()); - break; - - case OP_LOAD_VAR_INT32: - case OP_LOAD_VAR_INT32_AS_INT16: - debugN(5, "var_%d", _vm->_game->_script->readUint16()); - break; - - case OP_LOAD_VAR_STR: // string variable load - debugN(5, "(&var_%d)", _vm->_game->_script->readUint16()); - if (_vm->_game->_script->peekByte() == 13) { - _vm->_game->_script->skip(1); - debugN(5, "{"); - printExpr_internal(OP_END_MARKER); // this also prints the closing } - } - break; - - case OP_ARRAY_INT8: // int8 array access - case OP_ARRAY_INT32: // int32 array access - case OP_ARRAY_INT16: // int16 array access - case OP_ARRAY_STR: // string array access - debugN(5, "\n"); - if (operation == OP_ARRAY_STR) - debugN(5, "(&"); - - debugN(5, "var_%d[", _vm->_game->_script->readInt16()); - dimCount = _vm->_game->_script->readByte(); - arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); - _vm->_game->_script->skip(dimCount); - for (dim = 0; dim < dimCount; dim++) { - printExpr_internal(OP_END_MARKER); - debugN(5, " of %d", (int16) arrDesc[dim]); - if (dim != dimCount - 1) - debugN(5, ","); - } - debugN(5, "]"); - if (operation == OP_ARRAY_STR) - debugN(5, ")"); - - if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { - _vm->_game->_script->skip(1); - debugN(5, "{"); - printExpr_internal(OP_END_MARKER); // this also prints the closing } - } - break; - - case OP_FUNC: // function - func = _vm->_game->_script->readByte(); - if (func == FUNC_SQR) - debugN(5, "sqr("); - else if (func == FUNC_RAND) - debugN(5, "rand("); - else if (func == FUNC_ABS) - debugN(5, "abs("); - else if ((func == FUNC_SQRT1) || (func == FUNC_SQRT2) || (func == FUNC_SQRT3)) - debugN(5, "sqrt("); - else - debugN(5, "id("); - printExpr_internal(OP_END_EXPR); - break; - } - continue; - } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) - - // operators - switch (operation) { - case OP_BEGIN_EXPR: - debugN(5, "("); - break; - - case OP_NOT: - debugN(5, "!"); - break; - - case OP_END_EXPR: - debugN(5, ")"); - break; - - case OP_NEG: - debugN(5, "-"); - break; - - case OP_ADD: - debugN(5, "+"); - break; - - case OP_SUB: - debugN(5, "-"); - break; - - case OP_BITOR: - debugN(5, "|"); - break; - - case OP_MUL: - debugN(5, "*"); - break; - - case OP_DIV: - debugN(5, "/"); - break; - - case OP_MOD: - debugN(5, "%%"); - break; - - case OP_BITAND: - debugN(5, "&"); - break; - - case OP_OR: - debugN(5, "||"); - break; - - case 31: - debugN(5, "&&"); - break; - - case OP_LESS: - debugN(5, "<"); - break; - - case OP_LEQ: - debugN(5, "<="); - break; - - case OP_GREATER: - debugN(5, ">"); - break; - - case OP_GEQ: - debugN(5, ">="); - break; - - case OP_EQ: - debugN(5, "=="); - break; - - case OP_NEQ: - debugN(5, "!="); - break; - - case 99: - debugN(5, "\n"); - break; - - case OP_END_MARKER: - debugN(5, "}"); - if (stopToken != OP_END_MARKER) { - debugN(5, "Closing paren without opening?"); - } - break; - - default: - debugN(5, "<%d>", (int16) operation); - error("Expression::printExpr(): invalid operator in expression"); - break; - } - - if (operation == OP_BEGIN_EXPR) { - num++; - continue; - } - - if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) - continue; - - if ((operation >= OP_OR) && (operation <= OP_NEQ)) - continue; - - if (operation == OP_END_EXPR) - num--; - - if (operation == stopToken) { - if ((stopToken != OP_END_EXPR) || (num < 0)) { - return; - } - } - } -} - - -void Expression::printVarIndex() { - byte *arrDesc; - int16 dim; - int16 dimCount; - int16 operation; - int16 temp; - - int32 pos = _vm->_game->_script->pos(); - - operation = _vm->_game->_script->readByte(); - switch (operation) { - case OP_LOAD_VAR_INT32: - case OP_LOAD_VAR_STR: - temp = _vm->_game->_script->readUint16() * 4; - debugN(5, "&var_%d", temp); - if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { - _vm->_game->_script->skip(1); - debugN(5, "+"); - printExpr(OP_END_MARKER); - } - break; - - case OP_ARRAY_INT32: - case OP_ARRAY_STR: - debugN(5, "&var_%d[", _vm->_game->_script->readUint16()); - dimCount = _vm->_game->_script->readByte(); - arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); - _vm->_game->_script->skip(dimCount); - for (dim = 0; dim < dimCount; dim++) { - printExpr(OP_END_MARKER); - debugN(5, " of %d", (int16) arrDesc[dim]); - if (dim != dimCount - 1) - debugN(5, ","); - } - debugN(5, "]"); - - if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { - _vm->_game->_script->skip(1); - debugN(5, "+"); - printExpr(OP_END_MARKER); - } - break; - - default: - debugN(5, "var_0"); - break; - } - debugN(5, "\n"); - - _vm->_game->_script->seek(pos); - return; -} - -int Expression::cmpHelper(const StackFrame &stackFrame) { - byte type = stackFrame.opers[-3]; - int cmpTemp = 0; - - if (type == OP_LOAD_IMM_INT16) { - cmpTemp = (int)stackFrame.values[-3] - (int)stackFrame.values[-1]; - } else if (type == OP_LOAD_IMM_STR) { - if ((char *)decodePtr(stackFrame.values[-3]) != _resultStr) { - strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-3])); - stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); - } - cmpTemp = strcmp(_resultStr, (char *)decodePtr(stackFrame.values[-1])); - } - - return cmpTemp; -} - -bool Expression::getVarBase(uint32 &varBase, bool mindStop, - uint16 *size, uint16 *type) { - - varBase = 0; - - byte operation = _vm->_game->_script->peekByte(); - while ((operation == 14) || (operation == 15)) { - _vm->_game->_script->skip(1); - - if (operation == 14) { - // Add a direct offset - - varBase += _vm->_game->_script->readInt16() * 4; - - if (size) - *size = _vm->_game->_script->peekUint16(); - if (type) - *type = 14; - - _vm->_game->_script->skip(2); - - debugC(2, kDebugParser, "varBase: %d, by %d", varBase, operation); - - if (_vm->_game->_script->peekByte() != 97) { - if (mindStop) - return true; - } else - _vm->_game->_script->skip(1); - - } else if (operation == 15) { - // Add an offset from an array - - varBase += _vm->_game->_script->readInt16() * 4; - - uint16 offset1 = _vm->_game->_script->readUint16(); - - if (size) - *size = offset1; - if (type) - *type = 15; - - uint8 dimCount = _vm->_game->_script->readByte(); - byte *dimArray = _vm->_game->_script->getData() + _vm->_game->_script->pos(); - - _vm->_game->_script->skip(dimCount); - - uint16 offset2 = 0; - for (int i = 0; i < dimCount; i++) { - int16 dim = CLIP(parseValExpr(OP_END_MARKER), 0, dimArray[i] - 1); - - offset2 = offset2 * dimArray[i] + dim; - } - - varBase += offset2 * offset1 * 4; - - debugC(2, kDebugParser, "varBase: %d, by %d", varBase, operation); - - if (_vm->_game->_script->peekByte() != 97) { - if (mindStop) - return true; - } else - _vm->_game->_script->skip(1); - } - - operation = _vm->_game->_script->peekByte(); - } - - return false; -} - -int16 Expression::parseVarIndex(uint16 *size, uint16 *type) { - int16 temp2; - byte *arrDesc; - int16 dim; - int16 dimCount; - int16 operation; - int16 temp; - int16 offset; - int16 val; - uint32 varBase; - - if (getVarBase(varBase, true, size, type)) - return varBase; - - operation = _vm->_game->_script->readByte(); - - if (size) - *size = 0; - if (type) - *type = operation; - - debugC(5, kDebugParser, "var parse = %d", operation); - switch (operation) { - case OP_ARRAY_INT8: - case OP_ARRAY_INT32: - case OP_ARRAY_INT16: - case OP_ARRAY_STR: - temp = _vm->_game->_script->readInt16(); - dimCount = _vm->_game->_script->readByte(); - arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); - _vm->_game->_script->skip(dimCount); - offset = 0; - for (dim = 0; dim < dimCount; dim++) { - temp2 = parseValExpr(OP_END_MARKER); - offset = arrDesc[dim] * offset + temp2; - } - if (operation == OP_ARRAY_INT8) - return varBase + temp + offset; - if (operation == OP_ARRAY_INT32) - return varBase + (temp + offset) * 4; - if (operation == OP_ARRAY_INT16) - return varBase + (temp + offset) * 2; - temp *= 4; - offset *= 4; - if (_vm->_game->_script->peekByte() == 13) { - _vm->_game->_script->skip(1); - temp += parseValExpr(OP_END_MARKER); - } - return varBase + offset * _vm->_global->_inter_animDataSize + temp; - - case OP_LOAD_VAR_INT16: - return varBase + _vm->_game->_script->readInt16() * 2; - - case OP_LOAD_VAR_INT8: - return varBase + _vm->_game->_script->readInt16(); - - case OP_LOAD_VAR_INT32: - case OP_LOAD_VAR_INT32_AS_INT16: - case OP_LOAD_VAR_STR: - temp = _vm->_game->_script->readInt16() * 4; - debugC(5, kDebugParser, "oper = %d", _vm->_game->_script->peekInt16()); - if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { - _vm->_game->_script->skip(1); - val = parseValExpr(OP_END_MARKER); - temp += val; - debugC(5, kDebugParser, "parse subscript = %d", val); - } - return varBase + temp; - - default: - return 0; - } -} - -int16 Expression::parseValExpr(byte stopToken) { - parseExpr(stopToken, 0); - - return _resultInt; -} - -// Load a value according to the operation -void Expression::loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame) { - int16 dimCount; - int16 temp; - int16 temp2; - int16 offset; - int16 dim; - byte *arrDescPtr; - int32 prevPrevVal; - int32 prevVal; - int32 curVal; - - switch (operation) { - case OP_ARRAY_INT8: - case OP_ARRAY_INT32: - case OP_ARRAY_INT16: - case OP_ARRAY_STR: - *stackFrame.opers = (operation == OP_ARRAY_STR) ? OP_LOAD_IMM_STR : OP_LOAD_IMM_INT16; - temp = _vm->_game->_script->readInt16(); - dimCount = _vm->_game->_script->readByte(); - arrDescPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); - _vm->_game->_script->skip(dimCount); - offset = 0; - for (dim = 0; dim < dimCount; dim++) { - temp2 = parseValExpr(OP_END_MARKER); - offset = offset * arrDescPtr[dim] + temp2; - } - if (operation == OP_ARRAY_INT8) - *stackFrame.values = (int8) READ_VARO_UINT8(varBase + temp + offset); - else if (operation == OP_ARRAY_INT32) - *stackFrame.values = READ_VARO_UINT32(varBase + temp * 4 + offset * 4); - else if (operation == OP_ARRAY_INT16) - *stackFrame.values = (int16) READ_VARO_UINT16(varBase + temp * 2 + offset * 2); - else if (operation == OP_ARRAY_STR) { - *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8( - varBase + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), - kInterVar); - if (_vm->_game->_script->peekByte() == 13) { - _vm->_game->_script->skip(1); - temp2 = parseValExpr(OP_END_MARKER); - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = READ_VARO_UINT8(varBase + temp * 4 + - offset * 4 * _vm->_global->_inter_animDataSize + temp2); - } - } - break; - - case OP_LOAD_VAR_INT16: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 2); - break; - - case OP_LOAD_VAR_INT8: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = (int8) READ_VARO_UINT8(varBase + _vm->_game->_script->readInt16()); - break; - - case OP_LOAD_IMM_INT32: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = _vm->_game->_script->readInt32(); - break; - - case OP_LOAD_IMM_INT16: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = _vm->_game->_script->readInt16(); - break; - - case OP_LOAD_IMM_INT8: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = _vm->_game->_script->readInt8(); - break; - - case OP_LOAD_IMM_STR: - *stackFrame.opers = OP_LOAD_IMM_STR; - *stackFrame.values = encodePtr((byte *) _vm->_game->_script->readString(), kExecPtr); - break; - - case OP_LOAD_VAR_INT32: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = READ_VARO_UINT32(varBase + _vm->_game->_script->readInt16() * 4); - break; - - case OP_LOAD_VAR_INT32_AS_INT16: - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 4); - break; - - case OP_LOAD_VAR_STR: - *stackFrame.opers = OP_LOAD_IMM_STR; - temp = _vm->_game->_script->readInt16() * 4; - *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8(varBase + temp), kInterVar); - if (_vm->_game->_script->peekByte() == 13) { - _vm->_game->_script->skip(1); - temp += parseValExpr(OP_END_MARKER); - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = READ_VARO_UINT8(varBase + temp); - } - break; - - case OP_FUNC: - operation = _vm->_game->_script->readByte(); - parseExpr(OP_END_EXPR, 0); - - switch (operation) { - case FUNC_SQRT1: - case FUNC_SQRT2: - case FUNC_SQRT3: - curVal = 1; - prevVal = 1; - - do { - prevPrevVal = prevVal; - prevVal = curVal; - curVal = (curVal + _resultInt / curVal) / 2; - } while ((curVal != prevVal) && (curVal != prevPrevVal)); - _resultInt = curVal; - break; - - case FUNC_SQR: - _resultInt = - _resultInt * _resultInt; - break; - - case FUNC_ABS: - if (_resultInt < 0) - _resultInt = -_resultInt; - break; - - case FUNC_RAND: - _resultInt = - _vm->_util->getRandom(_resultInt); - break; - } - - *stackFrame.opers = OP_LOAD_IMM_INT16; - *stackFrame.values = _resultInt; - break; - } -} - -void Expression::simpleArithmetic1(StackFrame &stackFrame) { - switch (stackFrame.opers[-1]) { - case OP_ADD: - if (stackFrame.opers[-2] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(stackFrame.values[-2]) != _resultStr) { - strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-2])); - stackFrame.values[-2] = encodePtr((byte *) _resultStr, kResStr); - } - strcat(_resultStr, (char *) decodePtr(stackFrame.values[0])); - stackFrame.pop(2); - } - break; - - case OP_MUL: - stackFrame.values[-2] *= stackFrame.values[0]; - stackFrame.pop(2); - break; - - case OP_DIV: - stackFrame.values[-2] /= stackFrame.values[0]; - stackFrame.pop(2); - break; - - case OP_MOD: - stackFrame.values[-2] %= stackFrame.values[0]; - stackFrame.pop(2); - break; - - case OP_BITAND: - stackFrame.values[-2] &= stackFrame.values[0]; - stackFrame.pop(2); - break; - } -} - -void Expression::simpleArithmetic2(StackFrame &stackFrame) { - if (stackFrame.pos > 1) { - if (stackFrame.opers[-2] == OP_NEG) { - stackFrame.opers[-2] = OP_LOAD_IMM_INT16; - stackFrame.values[-2] = -stackFrame.values[-1]; - stackFrame.pop(); - } else if (stackFrame.opers[-2] == OP_NOT) { - stackFrame.opers[-2] = (stackFrame.opers[-1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(); - } - } - - if (stackFrame.pos > 2) { - switch (stackFrame.opers[-2]) { - case OP_MUL: - stackFrame.values[-3] *= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_DIV: - stackFrame.values[-3] /= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_MOD: - stackFrame.values[-3] %= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_BITAND: - stackFrame.values[-3] &= stackFrame.values[-1]; - stackFrame.pop(2); - break; - } - } - -} - -// Complex arithmetics with brackets -bool Expression::complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart) { - switch (stackFrame.opers[-2]) { - case OP_ADD: - if (stack.opers[brackStart] == OP_LOAD_IMM_INT16) { - stack.values[brackStart] += stackFrame.values[-1]; - } else if (stack.opers[brackStart] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(stack.values[brackStart]) != _resultStr) { - strcpy(_resultStr, (char *) decodePtr(stack.values[brackStart])); - stack.values[brackStart] = - encodePtr((byte *) _resultStr, kResStr); - } - strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); - } - stackFrame.pop(2); - break; - - case OP_SUB: - stack.values[brackStart] -= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_BITOR: - stack.values[brackStart] |= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_MUL: - stackFrame.values[-3] *= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_DIV: - stackFrame.values[-3] /= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_MOD: - stackFrame.values[-3] %= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_BITAND: - stackFrame.values[-3] &= stackFrame.values[-1]; - stackFrame.pop(2); - break; - - case OP_OR: - // (x OR false) == x - // (x OR true) == true - if (stackFrame.opers[-3] == GOB_FALSE) - stackFrame.opers[-3] = stackFrame.opers[-1]; - stackFrame.pop(2); - break; - - case OP_AND: - // (x AND false) == false - // (x AND true) == x - if (stackFrame.opers[-3] == GOB_TRUE) - stackFrame.opers[-3] = stackFrame.opers[-1]; - stackFrame.pop(2); - break; - - case OP_LESS: - stackFrame.opers[-3] = (cmpHelper(stackFrame) < 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - case OP_LEQ: - stackFrame.opers[-3] = (cmpHelper(stackFrame) <= 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - case OP_GREATER: - stackFrame.opers[-3] = (cmpHelper(stackFrame) > 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - case OP_GEQ: - stackFrame.opers[-3] = (cmpHelper(stackFrame) >= 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - case OP_EQ: - stackFrame.opers[-3] = (cmpHelper(stackFrame) == 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - case OP_NEQ: - stackFrame.opers[-3] = (cmpHelper(stackFrame) != 0) ? GOB_TRUE : GOB_FALSE; - stackFrame.pop(2); - break; - - default: - return true; - } - - return false; -} - -// Assign the result to the appropriate _result variable -void Expression::getResult(byte operation, int32 value, byte *type) { - if (type != 0) - *type = operation; - - switch (operation) { - case OP_NOT: - if (type != 0) - *type ^= 1; - break; - - case OP_LOAD_IMM_INT16: - _resultInt = value; - break; - - case OP_LOAD_IMM_STR: - if ((char *) decodePtr(value) != _resultStr) - strcpy(_resultStr, (char *) decodePtr(value)); - break; - - case OP_LOAD_VAR_INT32: - case OP_LOAD_VAR_INT32_AS_INT16: - break; - - default: - _resultInt = 0; - if (type != 0) - *type = OP_LOAD_IMM_INT16; - break; - } -} - -int16 Expression::parseExpr(byte stopToken, byte *type) { - Stack stack; - StackFrame stackFrame(stack); - byte operation; - bool escape; - int16 brackStart; - uint32 varBase; - - while (true) { - getVarBase(varBase); - - stackFrame.push(); - - operation = _vm->_game->_script->readByte(); - if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { - - loadValue(operation, varBase, stackFrame); - - if ((stackFrame.pos > 0) && ((stackFrame.opers[-1] == OP_NEG) || (stackFrame.opers[-1] == OP_NOT))) { - stackFrame.pop(); - - if (*stackFrame.opers == OP_NEG) { - *stackFrame.opers = OP_LOAD_IMM_INT16; - stackFrame.values[0] = -stackFrame.values[1]; - } else - *stackFrame.opers = (stackFrame.opers[1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; - } - - if (stackFrame.pos <= 0) - continue; - - simpleArithmetic1(stackFrame); - - continue; - } // (op >= OP_ARRAY_INT8) && (op <= OP_FUNC) - - if ((operation == stopToken) || (operation == OP_OR) || - (operation == OP_AND) || (operation == OP_END_EXPR)) { - while (stackFrame.pos >= 2) { - escape = false; - if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && - ((operation == OP_END_EXPR) || (operation == stopToken))) { - stackFrame.opers[-2] = stackFrame.opers[-1]; - if ((stackFrame.opers[-2] == OP_LOAD_IMM_INT16) || (stackFrame.opers[-2] == OP_LOAD_IMM_STR)) - stackFrame.values[-2] = stackFrame.values[-1]; - - stackFrame.pop(); - - simpleArithmetic2(stackFrame); - - if (operation != stopToken) - break; - } // if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && ...) - - for (brackStart = (stackFrame.pos - 2); (brackStart > 0) && - (stack.opers[brackStart] < OP_OR) && (stack.opers[brackStart] != OP_BEGIN_EXPR); - brackStart--) - ; - - if ((stack.opers[brackStart] >= OP_OR) || (stack.opers[brackStart] == OP_BEGIN_EXPR)) - brackStart++; - - if (complexArithmetic(stack, stackFrame, brackStart)) - break; - - } // while (stackFrame.pos >= 2) - - if ((operation == OP_OR) || (operation == OP_AND)) { - if (stackFrame.opers[-1] == OP_LOAD_IMM_INT16) { - if (stackFrame.values[-1] != 0) - stackFrame.opers[-1] = GOB_TRUE; - else - stackFrame.opers[-1] = GOB_FALSE; - } - - if (((operation == OP_OR) && (stackFrame.opers[-1] == GOB_TRUE)) || - ((operation == OP_AND) && (stackFrame.opers[-1] == GOB_FALSE))) { - if ((stackFrame.pos > 1) && (stackFrame.opers[-2] == OP_BEGIN_EXPR)) { - skipExpr(OP_END_EXPR); - stackFrame.opers[-2] = stackFrame.opers[-1]; - stackFrame.pop(2); - } else { - skipExpr(stopToken); - } - operation = _vm->_game->_script->peekByte(-1); - if ((stackFrame.pos > 0) && (stackFrame.opers[-1] == OP_NOT)) { - if (stackFrame.opers[0] == GOB_FALSE) - stackFrame.opers[-1] = GOB_TRUE; - else - stackFrame.opers[-1] = GOB_FALSE; - - stackFrame.pop(); - } - } else - stackFrame.opers[0] = operation; - } else - stackFrame.pop(); - - if (operation != stopToken) - continue; - - getResult(stack.opers[0], stack.values[0], type); - - return 0; - } // (operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR) - - if ((operation < OP_NEG) || (operation > OP_NOT)) { - if ((operation < OP_LESS) || (operation > OP_NEQ)) - continue; - - if (stackFrame.pos > 2) { - if (stackFrame.opers[-2] == OP_ADD) { - if (stackFrame.opers[-3] == OP_LOAD_IMM_INT16) { - stackFrame.values[-3] += stackFrame.values[-1]; - } else if (stackFrame.opers[-3] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(stackFrame.values[-3]) != _resultStr) { - strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-3])); - stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); - } - strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); - } - stackFrame.pop(2); - - } else if (stackFrame.opers[-2] == OP_SUB) { - stackFrame.values[-3] -= stackFrame.values[-1]; - stackFrame.pop(2); - } else if (stackFrame.opers[-2] == OP_BITOR) { - stackFrame.values[-3] |= stackFrame.values[-1]; - stackFrame.pop(2); - } - } - } - *stackFrame.opers = operation; - } -} - -int32 Expression::getResultInt() { - return _resultInt; -} - -char *Expression::getResultStr() { - return _resultStr; -} - -} // End of namespace Gob diff --git a/engines/gob/parse.h b/engines/gob/parse.h deleted file mode 100644 index 894704e2a9..0000000000 --- a/engines/gob/parse.h +++ /dev/null @@ -1,178 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GOB_EXPRESSION_H -#define GOB_EXPRESSION_H - -#include "common/scummsys.h" - -namespace Gob { - -class GobEngine; - -enum { - OP_NEG = 1, - OP_ADD = 2, - OP_SUB = 3, - OP_BITOR = 4, - OP_MUL = 5, - OP_DIV = 6, - OP_MOD = 7, - OP_BITAND = 8, - OP_BEGIN_EXPR = 9, - OP_END_EXPR = 10, - OP_NOT = 11, - - OP_END_MARKER = 12, // Marks end of an array or string - - - OP_ARRAY_INT8 = 16, - OP_LOAD_VAR_INT16 = 17, - OP_LOAD_VAR_INT8 = 18, - OP_LOAD_IMM_INT32 = 19, - OP_LOAD_IMM_INT16 = 20, - OP_LOAD_IMM_INT8 = 21, - OP_LOAD_IMM_STR = 22, - OP_LOAD_VAR_INT32 = 23, - OP_LOAD_VAR_INT32_AS_INT16 = 24, - OP_LOAD_VAR_STR = 25, - OP_ARRAY_INT32 = 26, - OP_ARRAY_INT16 = 27, - OP_ARRAY_STR = 28, - - OP_FUNC = 29, - - OP_OR = 30, // Logical OR - OP_AND = 31, // Logical AND - OP_LESS = 32, - OP_LEQ = 33, - OP_GREATER = 34, - OP_GEQ = 35, - OP_EQ = 36, - OP_NEQ = 37 -}; - -enum { - FUNC_SQRT1 = 0, - FUNC_SQRT2 = 1, - FUNC_SQRT3 = 6, - - FUNC_SQR = 5, - FUNC_ABS = 7, - FUNC_RAND = 10 -}; - -enum { - TYPE_IMM_INT8 = OP_LOAD_IMM_INT8, // 21 - TYPE_IMM_INT32 = OP_LOAD_IMM_INT32, // 19 - TYPE_IMM_INT16 = OP_LOAD_IMM_INT16, // 20 - TYPE_IMM_STR = OP_LOAD_IMM_STR, // 22 - TYPE_VAR_INT8 = OP_LOAD_VAR_INT8, // 18 - TYPE_VAR_INT16 = OP_LOAD_VAR_INT16, // 17 - TYPE_VAR_INT32 = OP_LOAD_VAR_INT32, // 23 - TYPE_VAR_STR = OP_LOAD_VAR_STR, // 25 - TYPE_ARRAY_INT8 = OP_ARRAY_INT8, // 16 - TYPE_ARRAY_INT16 = OP_ARRAY_INT16, // 27 - TYPE_ARRAY_INT32 = OP_ARRAY_INT32, // 26 - TYPE_ARRAY_STR = OP_ARRAY_STR, // 28 - TYPE_VAR_INT32_AS_INT16 = OP_LOAD_VAR_INT32_AS_INT16 // 24 -}; - -enum { - // FIXME: The following two 'truth values' are stored inside the list - // of "operators". So they somehow coincide with OP_LOAD_VAR_INT32 - // and OP_LOAD_VAR_INT32_AS_INT16. I haven't yet quite understood - // how, resp. what that means. You have been warned. - GOB_TRUE = 24, - GOB_FALSE = 23 -}; - -class Expression { -public: - Expression(GobEngine *vm); - virtual ~Expression() {} - - void skipExpr(char stopToken); - void printExpr(char stopToken); - void printVarIndex(void); - - int16 parseVarIndex(uint16 *size = 0, uint16 *type = 0); - int16 parseValExpr(byte stopToken = 99); - int16 parseExpr(byte stopToken, byte *type); - - int32 getResultInt(); - char *getResultStr(); - -private: - class Stack { - public: - byte *opers; - int32 *values; - - Stack(size_t size = 20); - ~Stack(); - }; - class StackFrame { - public: - byte *opers; - int32 *values; - int16 pos; - - StackFrame(const Stack &stack); - - void push(int count = 1); - void pop(int count = 1); - }; - - enum PointerType { - kExecPtr = 0, - kInterVar = 1, - kResStr = 2 - }; - - GobEngine *_vm; - - int32 _resultInt; - char _resultStr[200]; - - int32 encodePtr(byte *ptr, int type); - byte *decodePtr(int32 n); - - void printExpr_internal(char stopToken); - - bool getVarBase(uint32 &varBase, bool mindStop = false, - uint16 *size = 0, uint16 *type = 0); - int cmpHelper(const StackFrame &stackFrame); - void loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame); - - void simpleArithmetic1(StackFrame &stackFrame); - void simpleArithmetic2(StackFrame &stackFrame); - bool complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart); - void getResult(byte operation, int32 value, byte *type); -}; - -} // End of namespace Gob - -#endif // GOB_EXPRESSION_H diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp index 500bab5964..50a21014de 100644 --- a/engines/gob/script.cpp +++ b/engines/gob/script.cpp @@ -29,7 +29,7 @@ #include "gob/gob.h" #include "gob/script.h" #include "gob/dataio.h" -#include "gob/parse.h" +#include "gob/expression.h" #include "gob/videoplayer.h" namespace Gob { -- cgit v1.2.3