diff options
Diffstat (limited to 'engines/director/lingo/lingo-codegen.cpp')
-rw-r--r-- | engines/director/lingo/lingo-codegen.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp new file mode 100644 index 0000000000..07fb52290c --- /dev/null +++ b/engines/director/lingo/lingo-codegen.cpp @@ -0,0 +1,266 @@ +/* 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. + * + */ + +// Heavily inspired by hoc +// Copyright (C) AT&T 1995 +// All Rights Reserved +// +// Permission to use, copy, modify, and distribute this software and +// its documentation for any purpose and without fee is hereby +// granted, provided that the above copyright notice appear in all +// copies and that both that the copyright notice and this +// permission notice and warranty disclaimer appear in supporting +// documentation, and that the name of AT&T or any of its entities +// not be used in advertising or publicity pertaining to +// distribution of the software without specific, written prior +// permission. +// +// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +// THIS SOFTWARE. + +#include "engines/director/lingo/lingo.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + +#include "director/lingo/lingo-gr.h" + +namespace Director { + +void Lingo::execute(int pc) { + for(_pc = pc; (*_currentScript)[_pc] != STOP && !_returning;) { + + for (int i = 0; i < _stack.size(); i++) { + debugN(5, "%d ", _stack[i].u.i); + } + debug(5, ""); + + _pc++; + (*((*_currentScript)[_pc - 1]))(); + } +} + +Symbol *Lingo::lookupVar(const char *name, bool create, bool putInGlobalList) { + Symbol *sym; + + // Looking for the cast member constants + if (_vm->getVersion() < 4) { // TODO: There could be a flag 'Allow Outdated Lingo' in Movie Info in D4 + if (strlen(name) == 3) { + if (tolower(name[0]) >= 'a' && tolower(name[0]) <= 'h' && + name[1] >= '1' && name[1] <= '8' && + name[2] >= '1' && name[2] <= '8') { + + if (!create) + error("Cast reference used in wrong context: %s", name); + + int val = (tolower(name[0]) - 'a') * 64 + (name[1] - '1') * 8 + (name[2] - '1') + 1; + sym = new Symbol; + + sym->type = CASTREF; + sym->u.i = val; + + return sym; + } + } + } + + if (!_localvars->contains(name)) { // Create variable if it was not defined + if (!create) + return NULL; + + sym = new Symbol; + sym->name = (char *)calloc(strlen(name) + 1, 1); + Common::strlcpy(sym->name, name, strlen(name) + 1); + sym->type = VOID; + sym->u.i = 0; + + (*_localvars)[name] = sym; + + if (putInGlobalList) { + sym->global = true; + _globalvars[name] = sym; + } + } else { + sym = (*_localvars)[name]; + + if (sym->global) + sym = _globalvars[name]; + } + + return sym; +} + +void Lingo::cleanLocalVars() { + // Clean up current scope local variables and clean up memory + for (SymbolHash::const_iterator h = _localvars->begin(); h != _localvars->end(); ++h) { + if (!h->_value->global) + delete h->_value; + } + delete g_lingo->_localvars; +} + +void Lingo::define(Common::String &name, int start, int nargs, Common::String *prefix) { + Symbol *sym; + + if (prefix) + name = *prefix + "-" + name; + + debug(3, "define(\"%s\", %d, %d, %d)", name.c_str(), start, _currentScript->size() - 1, nargs); + + if (!_handlers.contains(name)) { // Create variable if it was not defined + sym = new Symbol; + + sym->name = (char *)calloc(name.size() + 1, 1); + Common::strlcpy(sym->name, name.c_str(), name.size() + 1); + sym->type = HANDLER; + + _handlers[name] = sym; + } else { + sym = g_lingo->_handlers[name]; + + warning("Redefining handler '%s'", name.c_str()); + delete sym->u.defn; + } + + sym->u.defn = new ScriptData(&(*_currentScript)[start], _currentScript->size() - start + 1); + sym->nargs = nargs; +} + +int Lingo::codeString(const char *str) { + int numInsts = calcStringAlignment(str); + + // Where we copy the string over + int pos = _currentScript->size(); + + // Allocate needed space in script + for (int i = 0; i < numInsts; i++) + _currentScript->push_back(0); + + byte *dst = (byte *)&_currentScript->front() + pos * sizeof(inst); + + memcpy(dst, str, strlen(str) + 1); + + return _currentScript->size(); +} + +int Lingo::codeFloat(double f) { + int numInsts = calcCodeAlignment(sizeof(double)); + + // Where we copy the string over + int pos = _currentScript->size(); + + // Allocate needed space in script + for (int i = 0; i < numInsts; i++) + _currentScript->push_back(0); + + double *dst = (double *)((byte *)&_currentScript->front() + pos * sizeof(inst)); + + *dst = f; + + return _currentScript->size(); +} + +void Lingo::codeArg(Common::String *s) { + _argstack.push_back(s); +} + +void Lingo::codeArgStore() { + while (true) { + if (_argstack.empty()) { + break; + } + + Common::String *arg = _argstack.back(); + _argstack.pop_back(); + + code1(c_varpush); + codeString(arg->c_str()); + code1(c_assign); + code1(c_xpop); + + delete arg; + } +} + +int Lingo::codeFunc(Common::String *s, int numpar) { + int ret = g_lingo->code1(g_lingo->c_call); + + if (s->equalsIgnoreCase("me")) { + if (!g_lingo->_currentFactory.empty()) { + g_lingo->codeString(g_lingo->_currentFactory.c_str()); + debug(2, "Repaced 'me' with %s", g_lingo->_currentFactory.c_str()); + } else { + warning("'me' out of factory method"); + g_lingo->codeString(s->c_str()); + } + } else { + g_lingo->codeString(s->c_str()); + } + + inst num = 0; + WRITE_UINT32(&num, numpar); + g_lingo->code1(num); + + return ret; +} + +void Lingo::codeLabel(int label) { + _labelstack.push_back(label); +} + +void Lingo::processIf(int elselabel, int endlabel) { + inst ielse1, iend; + int else1 = elselabel; + + WRITE_UINT32(&iend, endlabel); + + while (true) { + if (_labelstack.empty()) { + warning("Label stack underflow"); + break; + } + + int label = _labelstack.back(); + _labelstack.pop_back(); + + // This is beginning of our if() + if (!label) + break; + + WRITE_UINT32(&ielse1, else1); + (*_currentScript)[label + 2] = ielse1; /* elsepart */ + (*_currentScript)[label + 3] = iend; /* end, if cond fails */ + + else1 = label; + } +} + +void Lingo::codeFactory(Common::String &name) { + _currentFactory = name; +} + +} |