scummvm/engines/tony/mpal/expr.cpp
2012-05-13 23:44:08 +10:00

473 lines
12 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.
*
*
*/
/**************************************************************************
* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ *
* ... Spyral Software snc *
* . x#""*$Nu -= We create much MORE than ALL =- *
* d*#R$. R ^#$o ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ *
* .F ^$k $ "$b *
* ." $b u "$ #$L *
* P $c :*$L"$L '$k Project: MPAL................... *
* d @$N. $. d ^$b^$k $c *
* F 4 "$c '$ $ #$u#$u '$ Module: Expression gestor...... *
* 4 4k *N #b .> '$N'*$u * *
* M $L #$ $ 8 "$c'#$b.. .@ Author: Giovanni Bajo.......... *
* M '$u "$u :" *$. "#*#" *
* M '$N. " F ^$k Desc: Gestisce le espressioni *
* 4> ^R$oue# d matematiche............ *
* '$ "" @ ....................... *
* #b u# *
* $b .@" OS: [ ] DOS [X] WIN95 [ ] OS/2 *
* #$u .d" *
* '*$e. .zR".@ ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ *
* "*$$beooee$*" @"M This source code is *
* """ '$.? Copyright (C) Spyral Software *
* '$d> ALL RIGHTS RESERVED *
* '$> ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ *
* *
**************************************************************************/
#include "mpal.h"
#include "memory.h"
#include "mpaldll.h"
#include "stubs.h"
#include "tony/tony.h"
/*
#include "lzo1x.h"
*/
namespace Tony {
namespace MPAL {
/****************************************************************************\
* Operazioni matematiche gestite
\****************************************************************************/
#define OP_MUL ((1<<4)|0)
#define OP_DIV ((1<<4)|1)
#define OP_MODULE ((1<<4)|2)
#define OP_ADD ((2<<4)|0)
#define OP_SUB ((2<<4)|1)
#define OP_SHL ((3<<4)|0)
#define OP_SHR ((3<<4)|1)
#define OP_MINOR ((4<<4)|0)
#define OP_MAJOR ((4<<4)|1)
#define OP_MINEQ ((4<<4)|2)
#define OP_MAJEQ ((4<<4)|3)
#define OP_EQUAL ((5<<4)|0)
#define OP_NOEQUAL ((5<<4)|1)
#define OP_BITAND ((6<<4)|0)
#define OP_BITXOR ((7<<4)|0)
#define OP_BITOR ((8<<4)|0)
#define OP_AND ((9<<4)|0)
#define OP_OR ((10<<4)|0)
/****************************************************************************\
* enum ExprListTypes
* ------------------
* Description: Tipi di oggetto che possono essere contenuti in una struttura
* EXPRESSION.
\****************************************************************************/
enum ExprListTypes
{
ELT_NUMBER=1,
ELT_VAR=2,
ELT_PARENTH=3,
ELT_PARENTH2=4
};
/****************************************************************************\
* Structures
\****************************************************************************/
/****************************************************************************\
* typedef EXPRESSION
* ------------------
* Description: Struttura per gestire le operazioni matematiche
\****************************************************************************/
typedef struct {
byte type; // Tipo di oggetto (vedi enum ExprListTypes)
byte unary; // Unary operatore (NON SUPPORTATO)
union {
int num; // Numero (se type==ELT_NUMBER)
char *name; // Nome variabile (se type==ELT_VAR)
HGLOBAL son; // Handle a espressione (type==ELT_PARENTH)
byte *pson; // Handle lockato (type==ELT_PARENTH2)
} val;
byte symbol; // Simbolo matematico (vedi #define OP_*)
} EXPRESSION;
typedef EXPRESSION* LPEXPRESSION;
/****************************************************************************\
*
* Function: LPEXPRESSION DuplicateExpression(HGLOBAL h);
*
* Description: Duplica un'espressione matematica. L'espressione duplicata
* sara' formata da memoria non swappabile.
*
* Input: HGLOBAL h Handle dell'espressione originale
*
* Return: Pointer all'espressione clone della prima
*
\****************************************************************************/
static byte *DuplicateExpression(HGLOBAL h) {
int i, num;
byte *orig, *clone;
LPEXPRESSION one, two;
orig=(byte *)GlobalLock(h);
num=*(byte *)orig;
one=(LPEXPRESSION)(orig+1);
clone = (byte *)GlobalAlloc(GMEM_FIXED, sizeof(EXPRESSION)*num+1);
two=(LPEXPRESSION)(clone+1);
CopyMemory(clone,orig,sizeof(EXPRESSION)*num+1);
for (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;
int j;
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);
CopyMemory(one,two,(num-1)*sizeof(EXPRESSION));
num--;
} else {
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);
CopyMemory(two,three,(num-j-1)*sizeof(EXPRESSION));
num--;
}
}
}
/****************************************************************************\
*
* Function: int EvaluateAndFreeExpression(byte *expr);
*
* Description: Calcola il risultato di una espressione matematica, sosti-
* tuendo ad eventuali variabili il valore corrente.
*
* Input: byte *expr Pointer all'espressione duplicata
* tramite DuplicateExpression
*
* Return: Valore dell'espressione
*
\****************************************************************************/
static int EvaluateAndFreeExpression(byte *expr) {
int i,num,val;
LPEXPRESSION one,cur;
num=*expr;
one=(LPEXPRESSION)(expr+1);
// 1) Sostituzioni delle variabili
for (i=0,cur=one;i<num;i++,cur++) {
if (cur->type==ELT_VAR) {
cur->type=ELT_NUMBER;
cur->val.num=varGetValue(cur->val.name);
}
}
// 2) Sostituzioni delle parentesi (tramite ricorsione)
for (i=0,cur=one;i<num;i++,cur++) {
if (cur->type==ELT_PARENTH2) {
cur->type=ELT_NUMBER;
cur->val.num=EvaluateAndFreeExpression(cur->val.pson);
}
}
// 3) Risoluzione algebrica
Solve(one,num);
val=one->val.num;
GlobalFree(expr);
return val;
}
/****************************************************************************\
*
* Function: byte *ParseExpression(byte *buf, HGLOBAL *h);
*
* Description: Esegue il parsing da file .MPC di un'espressione matematica.
*
* Input: byte *buf Buffer contenente l'espressione
* compilata.
* HGLOBAL *h Pointer a un handle che, alla fine
* dell'esecuzione, puntera' alla
* zona di memoria contenete l'espres-
* sione parsata
*
* Return: Puntatore al buffer subito dopo l'espressione, o NULL in caso
* di errore.
*
\****************************************************************************/
const byte *ParseExpression(const byte *lpBuf, HGLOBAL *h) {
LPEXPRESSION cur;
byte *start;
uint32 num, i;
num = *lpBuf;
lpBuf++;
if (num == 0)
return NULL;
*h = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, num * sizeof(EXPRESSION) + 1);
if (*h==NULL)
return NULL;
start=(byte *)GlobalLock(*h);
*start=(byte)num;
cur=(LPEXPRESSION)(start+1);
for (i=0;i<num;i++) {
cur->type=*(lpBuf);
cur->unary=*(lpBuf+1);
lpBuf+=2;
switch (cur->type) {
case ELT_NUMBER:
cur->val.num=*(int *)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;
CopyMemory(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;
}
/****************************************************************************\
*
* Function: int EvaluateExpression(HGLOBAL h);
*
* Description: Calcola il valore di un'espressione matematica
*
* Input: HGLOBAL h Handle all'espressione
*
* Return: Valore numerico
*
\****************************************************************************/
int EvaluateExpression(HGLOBAL h) {
int ret;
LockVar();
ret=EvaluateAndFreeExpression(DuplicateExpression(h));
UnlockVar();
return ret;
}
/****************************************************************************\
*
* Function: bool CompareExpressions(HGLOBAL h1, HGLOBAL h2);
*
* Description: Confronta due espressioni matematiche tra loro
*
* Input: HGLOBAL h1,h2 Espressioni da confrontare
*
* Return: true se sono uguali, false se sono diverse
*
\****************************************************************************/
bool CompareExpressions(HGLOBAL h1, HGLOBAL h2) {
int i,num1,num2;
byte *e1, *e2;
LPEXPRESSION one, two;
e1=(byte *)GlobalLock(h1);
e2=(byte *)GlobalLock(h2);
num1=*(byte *)e1;
num2=*(byte *)e2;
if (num1 != num2) {
GlobalUnlock(h1);
GlobalUnlock(h2);
return false;
}
one=(LPEXPRESSION)(e1+1);
two=(LPEXPRESSION)(e2+1);
for (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;
}
} // end of namespace MPAL
} // end of namespace Tony