mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-10 03:40:25 +00:00
b8c1b46ae0
This is mainly removal of extraneous blank lines, reformatting indents to tab characters and other minor non-functional changes to improve compliance with Code Formatting Conventions.
362 lines
7.5 KiB
C++
362 lines
7.5 KiB
C++
/* 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.
|
|
*
|
|
*
|
|
*/
|
|
/*
|
|
* This code is based on original Tony Tough source code
|
|
*
|
|
* Copyright (c) 1997-2003 Nayma Software
|
|
*/
|
|
|
|
#include "tony/mpal/mpal.h"
|
|
#include "tony/mpal/memory.h"
|
|
#include "tony/mpal/mpaldll.h"
|
|
#include "tony/tony.h"
|
|
|
|
namespace Tony {
|
|
|
|
namespace MPAL {
|
|
|
|
/**
|
|
* Duplicate a mathematical expression.
|
|
*
|
|
* @param h Handle to the original expression
|
|
* @retruns Pointer to the cloned expression
|
|
*/
|
|
static byte *duplicateExpression(MpalHandle h) {
|
|
byte *orig, *clone;
|
|
|
|
orig = (byte *)globalLock(h);
|
|
|
|
int num = *(byte *)orig;
|
|
LpExpression one = (LpExpression)(orig+1);
|
|
|
|
clone = (byte *)globalAlloc(GMEM_FIXED, sizeof(Expression) * num + 1);
|
|
LpExpression two = (LpExpression)(clone + 1);
|
|
|
|
memcpy(clone, orig, sizeof(Expression) * num + 1);
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
if (one->_type == ELT_PARENTH) {
|
|
two->_type = ELT_PARENTH2;
|
|
two->_val._pson = duplicateExpression(two->_val._son);
|
|
}
|
|
|
|
++one;
|
|
++two;
|
|
}
|
|
|
|
globalUnlock(h);
|
|
return clone;
|
|
}
|
|
|
|
static int Compute(int a, int b, byte symbol) {
|
|
switch (symbol) {
|
|
case OP_MUL:
|
|
return a * b;
|
|
case OP_DIV:
|
|
return a / b;
|
|
case OP_MODULE:
|
|
return a % b;
|
|
case OP_ADD:
|
|
return a + b;
|
|
case OP_SUB:
|
|
return a - b;
|
|
case OP_SHL:
|
|
return a << b;
|
|
case OP_SHR:
|
|
return a >> b;
|
|
case OP_MINOR:
|
|
return a < b;
|
|
case OP_MAJOR:
|
|
return a > b;
|
|
case OP_MINEQ:
|
|
return a <= b;
|
|
case OP_MAJEQ:
|
|
return a >= b;
|
|
case OP_EQUAL:
|
|
return a == b;
|
|
case OP_NOEQUAL:
|
|
return a != b;
|
|
case OP_BITAND:
|
|
return a & b;
|
|
case OP_BITXOR:
|
|
return a ^ b;
|
|
case OP_BITOR:
|
|
return a | b;
|
|
case OP_AND:
|
|
return a && b;
|
|
case OP_OR:
|
|
return a || b;
|
|
default:
|
|
GLOBALS._mpalError = 1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void solve(LpExpression one, int num) {
|
|
LpExpression two, three;
|
|
|
|
while (num > 1) {
|
|
two = one + 1;
|
|
if ((two->_symbol == 0) || (one->_symbol & 0xF0) <= (two->_symbol & 0xF0)) {
|
|
two->_val._num = Compute(one->_val._num, two->_val._num, one->_symbol);
|
|
memmove(one, two, (num - 1) * sizeof(Expression));
|
|
--num;
|
|
} else {
|
|
int j = 1;
|
|
three = two + 1;
|
|
while ((three->_symbol != 0) && (two->_symbol & 0xF0) > (three->_symbol & 0xF0)) {
|
|
++two;
|
|
++three;
|
|
++j;
|
|
}
|
|
|
|
three->_val._num = Compute(two->_val._num, three->_val._num, two->_symbol);
|
|
memmove(two, three, (num - j - 1) * sizeof(Expression));
|
|
--num;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculates the result of a mathematical expression, replacing the current
|
|
* value of any variable.
|
|
*
|
|
* @param expr Pointer to an expression duplicated by DuplicateExpression
|
|
* @returns Value
|
|
*/
|
|
static int evaluateAndFreeExpression(byte *expr) {
|
|
int num = *expr;
|
|
LpExpression one = (LpExpression)(expr + 1);
|
|
|
|
// 1) Substitutions of variables
|
|
LpExpression cur = one;
|
|
for (int i = 0; i < num; i++, cur++) {
|
|
if (cur->_type == ELT_VAR) {
|
|
cur->_type = ELT_NUMBER;
|
|
cur->_val._num = varGetValue(cur->_val._name);
|
|
}
|
|
}
|
|
|
|
// 2) Replacement of brackets (using recursive calls)
|
|
cur = one;
|
|
for (int i = 0; i < num; i++, cur++) {
|
|
if (cur->_type == ELT_PARENTH2) {
|
|
cur->_type = ELT_NUMBER;
|
|
cur->_val._num = evaluateAndFreeExpression(cur->_val._pson);
|
|
}
|
|
}
|
|
|
|
// 3) algebraic resolution
|
|
solve(one, num);
|
|
int val = one->_val._num;
|
|
globalDestroy(expr);
|
|
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* Parses a mathematical expression from the MPC file
|
|
*
|
|
* @param buf Buffer containing the expression to evaluate
|
|
* @param h Pointer to a handle that, at the end of execution,
|
|
* will point to the area of memory containing the parsed expression
|
|
* @returns Pointer to the buffer immediately after the expression, or NULL if error.
|
|
*/
|
|
const byte *parseExpression(const byte *lpBuf, MpalHandle *h) {
|
|
byte *start;
|
|
|
|
uint32 num = *lpBuf;
|
|
lpBuf++;
|
|
|
|
if (num == 0)
|
|
return NULL;
|
|
|
|
*h = globalAllocate(GMEM_MOVEABLE | GMEM_ZEROINIT, num * sizeof(Expression) + 1);
|
|
if (*h == NULL)
|
|
return NULL;
|
|
|
|
start = (byte *)globalLock(*h);
|
|
*start = (byte)num;
|
|
|
|
LpExpression cur = (LpExpression)(start + 1);
|
|
|
|
for (uint32 i = 0;i < num; i++) {
|
|
cur->_type = *(lpBuf);
|
|
|
|
// *(lpBuf + 1) contains the unary operator, unused => skipped
|
|
lpBuf += 2;
|
|
|
|
switch (cur->_type) {
|
|
case ELT_NUMBER:
|
|
cur->_val._num = (int32)READ_LE_UINT32(lpBuf);
|
|
lpBuf += 4;
|
|
break;
|
|
|
|
case ELT_VAR:
|
|
cur->_val._name = (char *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, (*lpBuf) + 1);
|
|
if (cur->_val._name == NULL)
|
|
return NULL;
|
|
memcpy(cur->_val._name, lpBuf + 1, *lpBuf);
|
|
lpBuf += *lpBuf + 1;
|
|
break;
|
|
|
|
case ELT_PARENTH:
|
|
lpBuf = parseExpression(lpBuf, &cur->_val._son);
|
|
if (lpBuf == NULL)
|
|
return NULL;
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
cur->_symbol = *lpBuf;
|
|
lpBuf++;
|
|
|
|
cur++;
|
|
}
|
|
|
|
if (*lpBuf != 0)
|
|
return NULL;
|
|
|
|
lpBuf++;
|
|
|
|
return lpBuf;
|
|
}
|
|
|
|
/**
|
|
* Calculate the value of a mathamatical expression
|
|
*
|
|
* @param h Handle to the expression
|
|
* @returns Numeric value
|
|
*/
|
|
int evaluateExpression(MpalHandle h) {
|
|
lockVar();
|
|
int ret = evaluateAndFreeExpression(duplicateExpression(h));
|
|
unlockVar();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Compare two mathematical expressions together
|
|
*
|
|
* @param h1 Expression to be compared
|
|
* @param h2 Expression to be compared
|
|
*/
|
|
bool compareExpressions(MpalHandle h1, MpalHandle h2) {
|
|
byte *e1, *e2;
|
|
|
|
e1 = (byte *)globalLock(h1);
|
|
e2 = (byte *)globalLock(h2);
|
|
|
|
int num1 = *(byte *)e1;
|
|
int num2 = *(byte *)e2;
|
|
|
|
if (num1 != num2) {
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
return false;
|
|
}
|
|
|
|
LpExpression one = (LpExpression)(e1 + 1);
|
|
LpExpression two = (LpExpression)(e2 + 1);
|
|
|
|
for (int i = 0; i < num1; i++) {
|
|
if (one->_type != two->_type || (i != num1 - 1 && one->_symbol != two->_symbol)) {
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
return false;
|
|
}
|
|
|
|
switch (one->_type) {
|
|
case ELT_NUMBER:
|
|
if (one->_val._num != two->_val._num) {
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case ELT_VAR:
|
|
if (strcmp(one->_val._name, two->_val._name) != 0) {
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case ELT_PARENTH:
|
|
if (!compareExpressions(one->_val._son, two->_val._son)) {
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
++one;
|
|
++two;
|
|
}
|
|
|
|
globalUnlock(h1);
|
|
globalUnlock(h2);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Frees an expression that was previously parsed
|
|
*
|
|
* @param h Handle for the expression
|
|
*/
|
|
void freeExpression(MpalHandle h) {
|
|
byte *data = (byte *)globalLock(h);
|
|
int num = *data;
|
|
LpExpression cur = (LpExpression)(data + 1);
|
|
|
|
for (int i = 0; i < num; ++i, ++cur) {
|
|
switch (cur->_type) {
|
|
case ELT_VAR:
|
|
globalDestroy(cur->_val._name);
|
|
break;
|
|
|
|
case ELT_PARENTH:
|
|
freeExpression(cur->_val._son);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
globalUnlock(h);
|
|
globalFree(h);
|
|
}
|
|
|
|
} // end of namespace MPAL
|
|
|
|
} // end of namespace Tony
|