mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-24 18:56:33 +00:00
5b22991f34
svn-id: r24044
338 lines
6.4 KiB
C++
338 lines
6.4 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2006 The ScummVM project
|
|
*
|
|
* 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/stdafx.h"
|
|
#include "common/system.h"
|
|
#include "gui/eval.h"
|
|
#include "gui/widget.h"
|
|
#include "gui/newgui.h"
|
|
|
|
#include "graphics/scaler.h"
|
|
|
|
namespace GUI {
|
|
|
|
static bool isdelim(char c) {
|
|
if (strchr(" ;,+-<>/*%^=()", c) || c == 9 || c == '\n' || !c)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
Eval::Eval() {
|
|
loadConstants();
|
|
}
|
|
|
|
Eval::~Eval() {
|
|
_vars.clear();
|
|
_aliases.clear();
|
|
}
|
|
|
|
int Eval::eval(const String &input, const String §ion, const String &name, int startpos) {
|
|
int result;
|
|
|
|
debug(5, "%s=%s", name.c_str(), input.c_str());
|
|
|
|
strncpy(_input, input.c_str(), 256);
|
|
_section = section;
|
|
_name = name;
|
|
_startpos = startpos;
|
|
|
|
_pos = 0;
|
|
|
|
getToken();
|
|
|
|
if (_tokenType == tString)
|
|
return EVAL_STRING_VAR;
|
|
|
|
if (!*_token)
|
|
exprError(eBadExpr);
|
|
|
|
level2(&result);
|
|
|
|
debug(5, "Result: %d", result);
|
|
|
|
return result;
|
|
}
|
|
|
|
void Eval::level2(int *result) {
|
|
char op;
|
|
int hold;
|
|
|
|
level3(result);
|
|
|
|
while ((op = *_token) == '+' || op == '-') {
|
|
getToken();
|
|
level3(&hold);
|
|
arith(op, result, &hold);
|
|
}
|
|
}
|
|
|
|
void Eval::level3(int *result) {
|
|
char op;
|
|
int hold;
|
|
|
|
level4(result);
|
|
|
|
while ((op = *_token) == '*' || op == '/' || op == '%') {
|
|
getToken();
|
|
level4(&hold);
|
|
arith(op, result, &hold);
|
|
}
|
|
}
|
|
|
|
void Eval::level4(int *result) {
|
|
char op;
|
|
|
|
op = 0;
|
|
if ((_tokenType == tDelimiter) && *_token == '+' || *_token == '-') {
|
|
op = *_token;
|
|
getToken();
|
|
}
|
|
|
|
level5(result);
|
|
|
|
if (op)
|
|
unary(op, result);
|
|
}
|
|
|
|
void Eval::level5(int *result) {
|
|
if ((*_token == '(') && (_tokenType == tDelimiter)) {
|
|
getToken();
|
|
|
|
level2(result);
|
|
|
|
if (*_token != ')')
|
|
exprError(eUnclosedBracket);
|
|
getToken();
|
|
} else {
|
|
primitive(result);
|
|
}
|
|
}
|
|
|
|
void Eval::primitive(int *result) {
|
|
if (*_token == ')')
|
|
exprError(eExtraBracket);
|
|
|
|
switch (_tokenType) {
|
|
case tVariable:
|
|
*result = getVar_(_token);
|
|
if (*result == EVAL_UNDEF_VAR)
|
|
exprError(eUndefVar);
|
|
getToken();
|
|
return;
|
|
case tNumber:
|
|
*result = atoi(_token);
|
|
getToken();
|
|
return;
|
|
default:
|
|
exprError(eSyntaxError);
|
|
}
|
|
}
|
|
|
|
void Eval::arith(char op, int *r, int *h) {
|
|
int t;
|
|
|
|
switch (op) {
|
|
case '-':
|
|
*r = *r - *h;
|
|
break;
|
|
case '+':
|
|
*r = *r + *h;
|
|
break;
|
|
case '*':
|
|
*r = *r * *h;
|
|
break;
|
|
case '/':
|
|
*r = (*r) / (*h);
|
|
break;
|
|
case '%':
|
|
t = (*r) / (*h);
|
|
*r = *r - (t * (*h));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Eval::unary(char op, int *r) {
|
|
if (op == '-')
|
|
*r = -(*r);
|
|
}
|
|
|
|
void Eval::getToken() {
|
|
char *temp;
|
|
|
|
_tokenType = tNone;
|
|
temp = _token;
|
|
|
|
if (_input[_pos] == 0) {
|
|
*_token = 0;
|
|
_tokenType = tDelimiter;
|
|
return;
|
|
}
|
|
while (isspace(_input[_pos]))
|
|
_pos++;
|
|
|
|
if (_input[_pos] == '"') {
|
|
_pos++;
|
|
while (_input[_pos] != '"' && _input[_pos] != '\n')
|
|
*temp++ = _input[_pos++];
|
|
|
|
if (_input[_pos] == '\n')
|
|
exprError(eMissingQuote);
|
|
|
|
_pos++;
|
|
*temp = 0;
|
|
|
|
_tokenType = tString;
|
|
return;
|
|
}
|
|
|
|
if (isdigit(_input[_pos])) {
|
|
while (!isdelim(_input[_pos]))
|
|
*temp++ = _input[_pos++];
|
|
*temp = 0;
|
|
|
|
_tokenType = tNumber;
|
|
return;
|
|
}
|
|
|
|
if (isalpha(_input[_pos])) {
|
|
while (!isdelim(_input[_pos]))
|
|
*temp++ = _input[_pos++];
|
|
*temp = 0;
|
|
_tokenType = tVariable;
|
|
return;
|
|
}
|
|
|
|
if (!_tokenType && isdelim(_input[_pos])) {
|
|
*temp++ = _input[_pos++];
|
|
*temp = 0;
|
|
_tokenType = tDelimiter;
|
|
}
|
|
}
|
|
|
|
void Eval::exprError(EvalErrors err) {
|
|
static const char *errors[] = {
|
|
"Syntax error",
|
|
"Extra ')'",
|
|
"Missing ')'",
|
|
"Bad expression",
|
|
"Undefined variable",
|
|
"Missing '\"'"
|
|
};
|
|
|
|
error("%s in section [%s] expression: \"%s\" start is at: %d near token '%s'",
|
|
errors[err], _section.c_str(), _name.c_str(), _pos + _startpos, _token);
|
|
}
|
|
|
|
struct BuiltinConsts {
|
|
const char *name;
|
|
int value;
|
|
};
|
|
|
|
static const BuiltinConsts builtinConsts[] = {
|
|
{"kButtonWidth", GUI::kButtonWidth},
|
|
{"kButtonHeight", GUI::kButtonHeight},
|
|
{"kSliderWidth", GUI::kSliderWidth},
|
|
{"kSliderHeight", GUI::kSliderHeight},
|
|
|
|
{"kBigButtonWidth", GUI::kBigButtonWidth},
|
|
{"kBigButtonHeight", GUI::kBigButtonHeight},
|
|
{"kBigSliderWidth", GUI::kBigSliderWidth},
|
|
{"kBigSliderHeight", GUI::kBigSliderHeight},
|
|
|
|
{"kNormalWidgetSize", GUI::kNormalWidgetSize},
|
|
{"kBigWidgetSize", GUI::kBigWidgetSize},
|
|
|
|
{"kThumbnailWidth", kThumbnailWidth},
|
|
|
|
{"kTextAlignLeft", kTextAlignLeft},
|
|
{"kTextAlignRight", kTextAlignRight},
|
|
{"kTextAlignCenter", kTextAlignCenter},
|
|
|
|
{"kFontStyleBold", Theme::kFontStyleBold},
|
|
{"kFontStyleNormal", Theme::kFontStyleNormal},
|
|
{"kFontStyleItalic", Theme::kFontStyleItalic},
|
|
|
|
{"kFontStyleFixedBold", Theme::kFontStyleFixedBold},
|
|
{"kFontStyleFixedNormal", Theme::kFontStyleFixedNormal},
|
|
{"kFontStyleFixedItalic", Theme::kFontStyleFixedItalic},
|
|
|
|
{"kShadingNone", Theme::kShadingNone},
|
|
{"kShadingDim", Theme::kShadingDim},
|
|
{"kShadingLuminance", Theme::kShadingLuminance},
|
|
|
|
{"false", 0},
|
|
{"true", 1},
|
|
{NULL, 0}
|
|
};
|
|
|
|
void Eval::loadConstants() {
|
|
int i;
|
|
|
|
for (i = 0; builtinConsts[i].name; i++)
|
|
_vars[builtinConsts[i].name] = builtinConsts[i].value;
|
|
}
|
|
|
|
int Eval::getBuiltinVar(const char *s) {
|
|
if (!strcmp(s, "w"))
|
|
return g_system->getOverlayWidth();
|
|
|
|
if (!strcmp(s, "h"))
|
|
return g_system->getOverlayHeight();
|
|
|
|
return EVAL_UNDEF_VAR;
|
|
}
|
|
|
|
int Eval::getVar_(const Common::String &s, bool includeAliases) {
|
|
int val;
|
|
|
|
val = getBuiltinVar(s.c_str());
|
|
|
|
if (val != EVAL_UNDEF_VAR)
|
|
return val;
|
|
|
|
const Common::String *var = &s;
|
|
if (includeAliases) {
|
|
AliasesMap::const_iterator itera = _aliases.find(s);
|
|
if (itera != _aliases.end())
|
|
var = &(itera->_value);
|
|
}
|
|
|
|
VariablesMap::const_iterator iterv = _vars.find(*var);
|
|
if (iterv != _vars.end())
|
|
return iterv->_value;
|
|
|
|
return EVAL_UNDEF_VAR;
|
|
}
|
|
|
|
void Eval::setVar(const String §ion, const String &name, const String &value) {
|
|
_vars[name.c_str() + 4] = eval(value, section, name, 0);
|
|
}
|
|
|
|
void Eval::reset() {
|
|
_vars.clear();
|
|
_aliases.clear();
|
|
loadConstants();
|
|
}
|
|
|
|
} // end of namespace GUI
|