DIRECTOR: LINGO: Move compiler logic to new class

This commit is contained in:
djsrv 2021-06-15 21:17:09 -04:00 committed by D.J. Servilla
parent a4df3c3d8e
commit 0a708b9c8f
15 changed files with 746 additions and 678 deletions

View File

@ -23,6 +23,7 @@
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-object.h"
namespace Director {
@ -38,52 +39,52 @@ void ScriptNode::compile() {
/* FactoryNode */
void FactoryNode::compile() {
g_lingo->_inFactory = true;
ScriptContext *mainContext = g_lingo->_assemblyContext;
g_lingo->_assemblyContext = new ScriptContext(mainContext->getName(), mainContext->_archive, mainContext->_scriptType, mainContext->_id);
g_lingo->_compiler->_inFactory = true;
ScriptContext *mainContext = g_lingo->_compiler->_assemblyContext;
g_lingo->_compiler->_assemblyContext = new ScriptContext(mainContext->getName(), mainContext->_archive, mainContext->_scriptType, mainContext->_id);
g_lingo->codeFactory(*name);
g_lingo->_compiler->codeFactory(*name);
for (uint i = 0; i < methods->size(); i++) {
(*methods)[i]->compile();
}
g_lingo->_inFactory = false;
g_lingo->_assemblyContext = mainContext;
g_lingo->_compiler->_inFactory = false;
g_lingo->_compiler->_assemblyContext = mainContext;
}
/* HandlerNode */
void HandlerNode::compile() {
g_lingo->_indef = true;
VarTypeHash *mainMethodVars = g_lingo->_methodVars;
g_lingo->_methodVars = new VarTypeHash;
g_lingo->_compiler->_indef = true;
VarTypeHash *mainMethodVars = g_lingo->_compiler->_methodVars;
g_lingo->_compiler->_methodVars = new VarTypeHash;
for (VarTypeHash::iterator i = mainMethodVars->begin(); i != mainMethodVars->end(); ++i) {
if (i->_value == kVarGlobal || i->_value == kVarProperty)
(*g_lingo->_methodVars)[i->_key] = i->_value;
(*g_lingo->_compiler->_methodVars)[i->_key] = i->_value;
}
if (g_lingo->_inFactory) {
for (DatumHash::iterator i = g_lingo->_assemblyContext->_properties.begin(); i != g_lingo->_assemblyContext->_properties.end(); ++i) {
(*g_lingo->_methodVars)[i->_key] = kVarInstance;
if (g_lingo->_compiler->_inFactory) {
for (DatumHash::iterator i = g_lingo->_compiler->_assemblyContext->_properties.begin(); i != g_lingo->_compiler->_assemblyContext->_properties.end(); ++i) {
(*g_lingo->_compiler->_methodVars)[i->_key] = kVarInstance;
}
}
for (uint i = 0; i < args->size(); i++) { // TODO: eliminate argstack
g_lingo->codeArg((*args)[i]);
g_lingo->_compiler->codeArg((*args)[i]);
}
uint start = g_lingo->_currentAssembly->size(); // TODO: should always be zero
uint start = g_lingo->_compiler->_currentAssembly->size(); // TODO: should always be zero
for (uint i = 0; i < stmts->size(); i++) {
(*stmts)[i]->compile();
}
g_lingo->code1(LC::c_procret);
g_lingo->codeDefine(*name, start, args->size());
g_lingo->_compiler->code1(LC::c_procret);
g_lingo->_compiler->codeDefine(*name, start, args->size());
g_lingo->clearArgStack();
g_lingo->_indef = false;
delete g_lingo->_methodVars;
g_lingo->_methodVars = mainMethodVars;
g_lingo->_compiler->clearArgStack();
g_lingo->_compiler->_indef = false;
delete g_lingo->_compiler->_methodVars;
g_lingo->_compiler->_methodVars = mainMethodVars;
}
/* CmdNode */
@ -92,14 +93,14 @@ void CmdNode::compile() {
for (uint i = 0; i < args->size(); i++) {
(*args)[i]->compile();
}
g_lingo->codeCmd(name, args->size());
g_lingo->_compiler->codeCmd(name, args->size());
}
/* GlobalNode */
void GlobalNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->registerMethodVar(*(*names)[i], kVarGlobal);
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarGlobal);
}
}
@ -107,7 +108,7 @@ void GlobalNode::compile() {
void PropertyNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->registerMethodVar(*(*names)[i], kVarProperty);
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarProperty);
}
}
@ -115,36 +116,36 @@ void PropertyNode::compile() {
void InstanceNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->registerMethodVar(*(*names)[i], kVarInstance);
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarInstance);
}
}
/* IntNode */
void IntNode::compile() {
g_lingo->code1(LC::c_intpush);
g_lingo->codeInt(val);
g_lingo->_compiler->code1(LC::c_intpush);
g_lingo->_compiler->codeInt(val);
}
/* FloatNode */
void FloatNode::compile() {
g_lingo->code1(LC::c_floatpush);
g_lingo->codeFloat(val);
g_lingo->_compiler->code1(LC::c_floatpush);
g_lingo->_compiler->codeFloat(val);
}
/* SymbolNode */
void SymbolNode::compile() {
g_lingo->code1(LC::c_symbolpush);
g_lingo->codeString(val->c_str());
g_lingo->_compiler->code1(LC::c_symbolpush);
g_lingo->_compiler->codeString(val->c_str());
}
/* StringNode */
void StringNode::compile() {
g_lingo->code1(LC::c_stringpush);
g_lingo->codeString(val->c_str());
g_lingo->_compiler->code1(LC::c_stringpush);
g_lingo->_compiler->codeString(val->c_str());
}
/* FuncNode */
@ -153,18 +154,18 @@ void FuncNode::compile() {
for (uint i = 0; i < args->size(); i++) {
(*args)[i]->compile();
}
g_lingo->codeFunc(name, args->size());
g_lingo->_compiler->codeFunc(name, args->size());
}
/* VarNode */
void VarNode::compile() {
if (g_lingo->_builtinConsts.contains(*name)) {
g_lingo->code1(LC::c_constpush);
g_lingo->_compiler->code1(LC::c_constpush);
} else {
g_lingo->code1(LC::c_eval);
g_lingo->_compiler->code1(LC::c_eval);
}
g_lingo->codeString(name->c_str());
g_lingo->_compiler->codeString(name->c_str());
}
/* ParensNode */
@ -177,7 +178,7 @@ void ParensNode::compile() {
void UnaryOpNode::compile() {
arg->compile();
g_lingo->code1(op);
g_lingo->_compiler->code1(op);
}
/* BinaryOpNode */
@ -185,7 +186,7 @@ void UnaryOpNode::compile() {
void BinaryOpNode::compile() {
a->compile();
b->compile();
g_lingo->code1(op);
g_lingo->_compiler->code1(op);
}
} // End of namespace Director

View File

@ -45,6 +45,7 @@
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-builtins.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-object.h"
namespace Director {
@ -628,7 +629,7 @@ void LB::b_value(int nargs) {
}
Common::String code = "scummvm_returnNumber " + expr;
// Compile the code to an anonymous function and call it
ScriptContext *sc = g_lingo->compileAnonymous(code.c_str());
ScriptContext *sc = g_lingo->_compiler->compileAnonymous(code.c_str());
Symbol sym = sc->_eventHandlers[kEventGeneric];
LC::call(sym, 0, true);
}
@ -1759,7 +1760,7 @@ void LB::b_installMenu(int nargs) {
}
TextCastMember *field = static_cast<TextCastMember *>(member);
Common::String menuStxt = g_lingo->codePreprocessor(field->getText().c_str(), field->getCast()->_lingoArchive, kNoneScript, castId, true);
Common::String menuStxt = g_lingo->_compiler->codePreprocessor(field->getText().c_str(), field->getCast()->_lingoArchive, kNoneScript, castId, true);
Common::String line;
int linenum = -1; // We increment it before processing

View File

@ -31,6 +31,7 @@
#include "director/util.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-builtins.h"
#include "director/lingo/lingo-bytecode.h"
#include "director/lingo/lingo-object.h"
@ -828,7 +829,7 @@ void LC::cb_zeropush() {
g_lingo->push(d);
}
ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, LingoArchive *archive, const Common::String &archName, uint16 version) {
ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &stream, LingoArchive *archive, const Common::String &archName, uint16 version) {
if (stream.size() < 0x5c) {
warning("Lscr header too small");
return nullptr;
@ -1277,13 +1278,13 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
Datum constant = _assemblyContext->_constants[arg];
switch (constant.type) {
case INT:
g_lingo->code1(LC::c_intpush);
code1(LC::c_intpush);
break;
case FLOAT:
g_lingo->code1(LC::c_floatpush);
code1(LC::c_floatpush);
break;
case STRING:
g_lingo->code1(LC::c_stringpush);
code1(LC::c_stringpush);
break;
default:
error("Unknown constant type %d", constant.type);
@ -1297,27 +1298,27 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
}
switch (constant.type) {
case INT:
g_lingo->codeInt(constant.u.i);
codeInt(constant.u.i);
break;
case FLOAT:
g_lingo->codeFloat(constant.u.f);
codeFloat(constant.u.f);
break;
case STRING:
g_lingo->codeString(constant.u.s->c_str());
codeString(constant.u.s->c_str());
break;
default:
error("Unknown constant type %d", constant.type);
break;
}
} else if (_lingoV4.contains(opcode)) {
} else if (g_lingo->_lingoV4.contains(opcode)) {
offsetList.push_back(_currentAssembly->size());
g_lingo->code1(_lingoV4[opcode]->func);
code1(g_lingo->_lingoV4[opcode]->func);
size_t argc = strlen(_lingoV4[opcode]->proto);
size_t argc = strlen(g_lingo->_lingoV4[opcode]->proto);
if (argc) {
int arg = 0;
for (uint c = 0; c < argc; c++) {
switch (_lingoV4[opcode]->proto[c]) {
switch (g_lingo->_lingoV4[opcode]->proto[c]) {
case 'b':
// read one uint8 as an argument
offsetList.push_back(_currentAssembly->size());
@ -1368,39 +1369,39 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
break;
}
}
g_lingo->codeInt(arg);
codeInt(arg);
}
} else {
// unimplemented instruction
if (opcode < 0x40) { // 1 byte instruction
debugC(5, kDebugCompile, "Unimplemented opcode: 0x%02x", opcode);
offsetList.push_back(_currentAssembly->size());
g_lingo->code1(LC::cb_unk);
g_lingo->codeInt(opcode);
code1(LC::cb_unk);
codeInt(opcode);
} else if (opcode < 0x80) { // 2 byte instruction
debugC(5, kDebugCompile, "Unimplemented opcode: 0x%02x (%d)", opcode, (uint)codeStore[pointer]);
offsetList.push_back(_currentAssembly->size());
g_lingo->code1(LC::cb_unk1);
g_lingo->codeInt(opcode);
code1(LC::cb_unk1);
codeInt(opcode);
offsetList.push_back(_currentAssembly->size());
g_lingo->codeInt((uint)codeStore[pointer]);
codeInt((uint)codeStore[pointer]);
pointer += 1;
} else { // 3 byte instruction
debugC(5, kDebugCompile, "Unimplemented opcode: 0x%02x (%d, %d)", opcode, (uint)codeStore[pointer], (uint)codeStore[pointer+1]);
offsetList.push_back(_currentAssembly->size());
g_lingo->code1(LC::cb_unk2);
g_lingo->codeInt(opcode);
code1(LC::cb_unk2);
codeInt(opcode);
offsetList.push_back(_currentAssembly->size());
g_lingo->codeInt((uint)codeStore[pointer]);
codeInt((uint)codeStore[pointer]);
offsetList.push_back(_currentAssembly->size());
g_lingo->codeInt((uint)codeStore[pointer+1]);
codeInt((uint)codeStore[pointer+1]);
pointer += 2;
}
}
}
// Add backstop
g_lingo->code1(STOP);
code1(STOP);
// Rewrite every offset flagged as a jump based on the new code alignment.
for (uint j = 0; j < jumpList.size(); j++) {
@ -1424,7 +1425,7 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
functionName = archive->names[nameIndex];
} else if (i == 0 && (scriptFlags & kScriptFlagEventScript)) {
// event script (lingo not contained within a handler)
functionName = _eventHandlerTypes[kEventGeneric];
functionName = g_lingo->_eventHandlerTypes[kEventGeneric];
}
Symbol sym;
@ -1460,7 +1461,7 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
uint pc = 0;
while (pc < _currentAssembly->size()) {
uint spc = pc;
Common::String instr = decodeInstruction(_assemblyArchive, _currentAssembly, pc, &pc);
Common::String instr = g_lingo->decodeInstruction(_assemblyArchive, _currentAssembly, pc, &pc);
out.writeString(Common::String::format("[%5d] %s\n", spc, instr.c_str()));
}
out.writeString(Common::String::format("<end code>\n\n"));
@ -1482,7 +1483,7 @@ ScriptContext *Lingo::compileLingoV4(Common::SeekableReadStreamEndian &stream, L
}
void LingoArchive::addCodeV4(Common::SeekableReadStreamEndian &stream, uint16 lctxIndex, const Common::String &archName, uint16 version) {
ScriptContext *ctx = g_lingo->compileLingoV4(stream, this, archName, version);
ScriptContext *ctx = g_lingo->_compiler->compileLingoV4(stream, this, archName, version);
if (ctx) {
lctxContexts[lctxIndex] = ctx;
*ctx->_refCount += 1;

View File

@ -47,56 +47,139 @@
#include "director/director.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-object.h"
namespace Director {
void Lingo::cleanLocalVars() {
// Clean up current scope local variables and clean up memory
debugC(3, kDebugLingoExec, "cleanLocalVars: have %d vars", _localvars->size());
LingoCompiler::LingoCompiler() {
_assemblyAST = nullptr;
_assemblyArchive = nullptr;
_currentAssembly = nullptr;
_assemblyContext = nullptr;
g_lingo->_localvars->clear();
delete g_lingo->_localvars;
_indef = false;
g_lingo->_localvars = nullptr;
_linenumber = _colnumber = _bytenumber = 0;
_lines[0] = _lines[1] = _lines[2] = nullptr;
_inFactory = false;
_hadError = false;
}
Symbol ScriptContext::define(Common::String &name, int nargs, ScriptData *code, Common::Array<Common::String> *argNames, Common::Array<Common::String> *varNames) {
Symbol sym;
sym.name = new Common::String(name);
sym.type = HANDLER;
sym.u.defn = code;
sym.nargs = nargs;
sym.maxArgs = nargs;
sym.argNames = argNames;
sym.varNames = varNames;
sym.ctx = this;
sym.archive = _archive;
ScriptContext *LingoCompiler::compileAnonymous(const char *code) {
debugC(1, kDebugCompile, "Compiling anonymous lingo\n"
"***********\n%s\n\n***********", code);
if (debugChannelSet(1, kDebugCompile)) {
uint pc = 0;
while (pc < sym.u.defn->size()) {
uint spc = pc;
Common::String instr = g_lingo->decodeInstruction(_archive, sym.u.defn, pc, &pc);
debugC(1, kDebugCompile, "[%5d] %s", spc, instr.c_str());
}
debugC(1, kDebugCompile, "<end define code>");
}
if (!g_lingo->_eventHandlerTypeIds.contains(name)) {
_functionHandlers[name] = sym;
if (_scriptType == kMovieScript && _archive && !_archive->functionHandlers.contains(name)) {
_archive->functionHandlers[name] = sym;
}
} else {
_eventHandlers[g_lingo->_eventHandlerTypeIds[name]] = sym;
}
return sym;
return compileLingo(code, nullptr, kNoneScript, 0, "[anonymous]", true);
}
Symbol Lingo::codeDefine(Common::String &name, int start, int nargs, int end, bool removeCode) {
ScriptContext *LingoCompiler::compileLingo(const char *code, LingoArchive *archive, ScriptType type, uint16 id, const Common::String &scriptName, bool anonymous) {
_assemblyArchive = archive;
_assemblyAST = nullptr;
ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, archive, type, id);
_currentAssembly = new ScriptData;
_methodVars = new VarTypeHash;
_linenumber = _colnumber = 1;
_hadError = false;
if (!strncmp(code, "menu:", 5) || scumm_strcasestr(code, "\nmenu:")) {
debugC(1, kDebugCompile, "Parsing menu");
parseMenu(code);
return nullptr;
}
// Preprocess the code for ease of the parser
Common::String codeNorm = codePreprocessor(code, archive, type, id);
code = codeNorm.c_str();
// Parse the Lingo and build an AST
parse(code);
// Generate bytecode
if (_assemblyAST) {
_assemblyAST->compile();
}
// for D4 and above, there usually won't be any code left.
// all scoped methods will be defined and stored by the code parser
// however D3 and below allow scopeless functions!
// and these can show up in D4 when imported from other movies
if (!_currentAssembly->empty()) {
// end of script, add a c_procret so stack frames work as expected
code1(LC::c_procret);
code1(STOP);
if (debugChannelSet(3, kDebugCompile)) {
if (_currentAssembly->size() && !_hadError)
Common::hexdump((byte *)&_currentAssembly->front(), _currentAssembly->size() * sizeof(inst));
debugC(2, kDebugCompile, "<resulting code>");
uint pc = 0;
while (pc < _currentAssembly->size()) {
uint spc = pc;
Common::String instr = g_lingo->decodeInstruction(_assemblyArchive, _currentAssembly, pc, &pc);
debugC(2, kDebugCompile, "[%5d] %s", spc, instr.c_str());
}
debugC(2, kDebugCompile, "<end code>");
}
Symbol currentFunc;
currentFunc.type = HANDLER;
currentFunc.u.defn = _currentAssembly;
Common::String typeStr = Common::String(scriptType2str(type));
currentFunc.name = new Common::String("[" + typeStr + " " + _assemblyContext->getName() + "]");
currentFunc.ctx = _assemblyContext;
currentFunc.archive = archive;
currentFunc.anonymous = anonymous;
// arg names should be empty, but just in case
Common::Array<Common::String> *argNames = new Common::Array<Common::String>;
for (uint i = 0; i < _argstack.size(); i++) {
argNames->push_back(Common::String(_argstack[i]->c_str()));
}
Common::Array<Common::String> *varNames = new Common::Array<Common::String>;
for (Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>::iterator it = _methodVars->begin(); it != _methodVars->end(); ++it) {
if (it->_value == kVarLocal)
varNames->push_back(Common::String(it->_key));
}
if (debugChannelSet(1, kDebugCompile)) {
debug("Function vars");
debugN(" Args: ");
for (uint i = 0; i < argNames->size(); i++) {
debugN("%s, ", (*argNames)[i].c_str());
}
debugN("\n");
debugN(" Local vars: ");
for (uint i = 0; i < varNames->size(); i++) {
debugN("%s, ", (*varNames)[i].c_str());
}
debugN("\n");
}
currentFunc.argNames = argNames;
currentFunc.varNames = varNames;
_assemblyContext->_eventHandlers[kEventGeneric] = currentFunc;
}
delete _methodVars;
_methodVars = nullptr;
_currentAssembly = nullptr;
delete _assemblyAST;
_assemblyAST = nullptr;
_assemblyContext = nullptr;
_assemblyArchive = nullptr;
return mainContext;
}
Symbol LingoCompiler::codeDefine(Common::String &name, int start, int nargs, int end, bool removeCode) {
if (debugChannelSet(-1, kDebugFewFramesOnly) || debugChannelSet(1, kDebugCompile))
debug("codeDefine(\"%s\"(len: %d), %d, %d, %d)",
name.c_str(), _currentAssembly->size() - 1, start, nargs, end);
@ -140,7 +223,7 @@ Symbol Lingo::codeDefine(Common::String &name, int start, int nargs, int end, bo
return sym;
}
int Lingo::codeString(const char *str) {
int LingoCompiler::codeString(const char *str) {
int numInsts = calcStringAlignment(str);
// Where we copy the string over
@ -157,7 +240,7 @@ int Lingo::codeString(const char *str) {
return _currentAssembly->size();
}
int Lingo::codeFloat(double f) {
int LingoCompiler::codeFloat(double f) {
int numInsts = calcCodeAlignment(sizeof(double));
// Where we copy the string over
@ -174,15 +257,15 @@ int Lingo::codeFloat(double f) {
return _currentAssembly->size();
}
int Lingo::codeInt(int val) {
int LingoCompiler::codeInt(int val) {
inst i = 0;
WRITE_UINT32(&i, val);
g_lingo->code1(i);
code1(i);
return _currentAssembly->size();
}
bool Lingo::isInArgStack(Common::String *s) {
bool LingoCompiler::isInArgStack(Common::String *s) {
for (uint i = 0; i < _argstack.size(); i++)
if (_argstack[i]->equalsIgnoreCase(*s))
return true;
@ -190,55 +273,55 @@ bool Lingo::isInArgStack(Common::String *s) {
return false;
}
void Lingo::codeArg(Common::String *s) {
void LingoCompiler::codeArg(Common::String *s) {
_argstack.push_back(new Common::String(*s));
}
void Lingo::clearArgStack() {
void LingoCompiler::clearArgStack() {
for (uint i = 0; i < _argstack.size(); i++)
delete _argstack[i];
_argstack.clear();
}
int Lingo::codeCmd(Common::String *s, int numpar) {
int LingoCompiler::codeCmd(Common::String *s, int numpar) {
// Insert current line number to our asserts
if (s->equalsIgnoreCase("scummvmAssert") || s->equalsIgnoreCase("scummvmAssertEqual")) {
g_lingo->code1(LC::c_intpush);
g_lingo->codeInt(g_lingo->_linenumber);
code1(LC::c_intpush);
codeInt(_linenumber);
numpar++;
}
int ret = g_lingo->code1(LC::c_callcmd);
int ret = code1(LC::c_callcmd);
g_lingo->codeString(s->c_str());
codeString(s->c_str());
inst num = 0;
WRITE_UINT32(&num, numpar);
g_lingo->code1(num);
code1(num);
return ret;
}
int Lingo::codeFunc(Common::String *s, int numpar) {
int ret = g_lingo->code1(LC::c_callfunc);
int LingoCompiler::codeFunc(Common::String *s, int numpar) {
int ret = code1(LC::c_callfunc);
g_lingo->codeString(s->c_str());
codeString(s->c_str());
inst num = 0;
WRITE_UINT32(&num, numpar);
g_lingo->code1(num);
code1(num);
return ret;
}
void Lingo::codeLabel(int label) {
void LingoCompiler::codeLabel(int label) {
_labelstack.push_back(label);
debugC(4, kDebugCompile, "codeLabel: Added label %d", label);
}
void Lingo::processIf(int toplabel, int endlabel) {
void LingoCompiler::processIf(int toplabel, int endlabel) {
inst iend;
debugC(4, kDebugCompile, "processIf(%d, %d)", toplabel, endlabel);
@ -264,27 +347,31 @@ void Lingo::processIf(int toplabel, int endlabel) {
}
}
void Lingo::registerMethodVar(const Common::String &name, VarType type) {
if (!g_lingo->_methodVars->contains(name)) {
(*g_lingo->_methodVars)[name] = type;
void LingoCompiler::registerMethodVar(const Common::String &name, VarType type) {
if (!_methodVars->contains(name)) {
(*_methodVars)[name] = type;
if (type == kVarProperty || type == kVarInstance) {
g_lingo->_assemblyContext->_properties[name] = Datum();
_assemblyContext->_properties[name] = Datum();
} else if (type == kVarGlobal) {
g_lingo->_globalvars[name] = Datum();
}
}
}
void Lingo::codeFactory(Common::String &name) {
void LingoCompiler::codeFactory(Common::String &name) {
// FIXME: The factory's context should not be tied to the LingoArchive
// but bytecode needs it to resolve names
_assemblyContext->setName(name);
_assemblyContext->setFactory(true);
if (!_globalvars.contains(name)) {
_globalvars[name] = _assemblyContext;
if (!g_lingo->_globalvars.contains(name)) {
g_lingo->_globalvars[name] = _assemblyContext;
} else {
warning("Factory '%s' already defined", name.c_str());
}
}
void LingoCompiler::parseMenu(const char *code) {
warning("STUB: parseMenu");
}
} // End of namespace Director

View File

@ -0,0 +1,91 @@
/* 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.
*
*/
#ifndef DIRECTOR_LINGO_LINGO_CODEGEN_H
#define DIRECTOR_LINGO_LINGO_CODEGEN_H
#include "director/types.h"
#include "director/lingo/lingo.h"
namespace Director {
class LingoCompiler {
public:
LingoCompiler();
ScriptContext *compileAnonymous(const char *code);
ScriptContext *compileLingo(const char *code, LingoArchive *archive, ScriptType type, uint16 id, const Common::String &scriptName, bool anonyomous = false);
ScriptContext *compileLingoV4(Common::SeekableReadStreamEndian &stream, LingoArchive *archive, const Common::String &archName, uint16 version);
bool isInArgStack(Common::String *s);
void clearArgStack();
int code1(inst code) { _currentAssembly->push_back(code); return _currentAssembly->size() - 1; }
int code2(inst code_1, inst code_2) { int o = code1(code_1); code1(code_2); return o; }
int code3(inst code_1, inst code_2, inst code_3) { int o = code1(code_1); code1(code_2); code1(code_3); return o; }
int code4(inst code_1, inst code_2, inst code_3, inst code_4) { int o = code1(code_1); code1(code_2); code1(code_3); code1(code_4); return o; }
void codeArg(Common::String *s);
int codeCmd(Common::String *s, int numpar);
Symbol codeDefine(Common::String &s, int start, int nargs, int end = -1, bool removeCode = true);
void codeFactory(Common::String &s);
int codeFloat(double f);
int codeFunc(Common::String *s, int numpar);
int codeInt(int val);
void codeLabel(int label);
int codeString(const char *s);
void processIf(int toplabel, int endlabel);
void registerMethodVar(const Common::String &name, VarType type);
LingoArchive *_assemblyArchive;
ScriptContext *_assemblyContext;
Node *_assemblyAST;
ScriptData *_currentAssembly;
bool _indef;
uint _linenumber;
uint _colnumber;
uint _bytenumber;
const char *_lines[3];
bool _inFactory;
Common::Array<Common::String *> _argstack;
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVars;
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVarsStash;
Common::Array<int> _labelstack;
bool _hadError;
private:
int parse(const char *code);
void parseMenu(const char *code);
public:
// lingo-preprocessor.cpp
Common::String codePreprocessor(const char *s, LingoArchive *archive, ScriptType type, uint16 id, bool simple = false);
// lingo-patcher.cpp
Common::String patchLingoCode(Common::String &line, LingoArchive *archive, ScriptType type, uint16 id, int linenumber);
};
} // End of namespace Director
#endif

View File

@ -79,6 +79,7 @@
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-gr.h"
#include "director/lingo/lingo-object.h"
@ -88,25 +89,26 @@ extern int yyparse();
using namespace Director;
static void yyerror(const char *s) {
g_lingo->_hadError = true;
LingoCompiler *compiler = g_lingo->_compiler;
compiler->_hadError = true;
warning("###################### LINGO: %s at line %d col %d in %s id: %d",
s, g_lingo->_linenumber, g_lingo->_colnumber, scriptType2str(g_lingo->_assemblyContext->_scriptType),
g_lingo->_assemblyContext->_id);
if (g_lingo->_lines[2] != g_lingo->_lines[1])
warning("# %3d: %s", g_lingo->_linenumber - 2, Common::String(g_lingo->_lines[2], g_lingo->_lines[1] - 1).c_str());
s, compiler->_linenumber, compiler->_colnumber, scriptType2str(compiler->_assemblyContext->_scriptType),
compiler->_assemblyContext->_id);
if (compiler->_lines[2] != compiler->_lines[1])
warning("# %3d: %s", compiler->_linenumber - 2, Common::String(compiler->_lines[2], compiler->_lines[1] - 1).c_str());
if (g_lingo->_lines[1] != g_lingo->_lines[0])
warning("# %3d: %s", g_lingo->_linenumber - 1, Common::String(g_lingo->_lines[1], g_lingo->_lines[0] - 1).c_str());
if (compiler->_lines[1] != compiler->_lines[0])
warning("# %3d: %s", compiler->_linenumber - 1, Common::String(compiler->_lines[1], compiler->_lines[0] - 1).c_str());
const char *ptr = g_lingo->_lines[0];
const char *ptr = compiler->_lines[0];
while (*ptr && *ptr != '\n')
ptr++;
warning("# %3d: %s", g_lingo->_linenumber, Common::String(g_lingo->_lines[0], ptr).c_str());
warning("# %3d: %s", compiler->_linenumber, Common::String(compiler->_lines[0], ptr).c_str());
Common::String arrow;
for (uint i = 0; i < g_lingo->_colnumber; i++)
for (uint i = 0; i < compiler->_colnumber; i++)
arrow += ' ';
warning("# %s^ about here", arrow.c_str());
@ -122,7 +124,7 @@ static void checkEnd(Common::String *token, Common::String *expect, bool require
}
#line 126 "engines/director/lingo/lingo-gr.cpp"
#line 128 "engines/director/lingo/lingo-gr.cpp"
# ifndef YY_CAST
# ifdef __cplusplus
@ -654,18 +656,18 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int16 yyrline[] =
{
0, 188, 188, 190, 196, 203, 204, 205, 206, 207,
236, 240, 242, 244, 245, 248, 254, 261, 262, 267,
271, 275, 276, 277, 282, 283, 284, 285, 286, 287,
288, 291, 293, 296, 298, 299, 300, 301, 304, 305,
306, 307, 308, 310, 311, 312, 313, 314, 316, 317,
318, 319, 320, 321, 323, 324, 325, 326, 327, 328,
329, 330, 331, 334, 335, 338, 342, 349, 351, 352,
355, 356, 359, 360, 361, 364, 365, 369, 375, 382,
383, 388, 389, 390, 391, 392, 393, 394, 395, 396,
399, 400, 403, 404, 405, 406, 407, 408, 409, 410,
411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
423, 424, 427, 431
0, 190, 190, 192, 198, 205, 206, 207, 208, 209,
238, 242, 244, 246, 247, 250, 256, 263, 264, 269,
273, 277, 278, 279, 284, 285, 286, 287, 288, 289,
290, 293, 295, 298, 300, 301, 302, 303, 306, 307,
308, 309, 310, 312, 313, 314, 315, 316, 318, 319,
320, 321, 322, 323, 325, 326, 327, 328, 329, 330,
331, 332, 333, 336, 337, 340, 344, 351, 353, 354,
357, 358, 361, 362, 363, 366, 367, 371, 377, 384,
385, 390, 391, 392, 393, 394, 395, 396, 397, 398,
401, 402, 405, 406, 407, 408, 409, 410, 411, 412,
413, 414, 415, 416, 417, 418, 419, 420, 421, 422,
425, 426, 429, 433
};
#endif
@ -1247,51 +1249,51 @@ yydestruct (const char *yymsg,
switch (yykind)
{
case YYSYMBOL_tTHEFUNC: /* tTHEFUNC */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1253 "engines/director/lingo/lingo-gr.cpp"
#line 1255 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tTHEFUNCINOF: /* tTHEFUNCINOF */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1259 "engines/director/lingo/lingo-gr.cpp"
#line 1261 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tVARID: /* tVARID */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1265 "engines/director/lingo/lingo-gr.cpp"
#line 1267 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tSTRING: /* tSTRING */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1271 "engines/director/lingo/lingo-gr.cpp"
#line 1273 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tSYMBOL: /* tSYMBOL */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1277 "engines/director/lingo/lingo-gr.cpp"
#line 1279 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tENDCLAUSE: /* tENDCLAUSE */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1283 "engines/director/lingo/lingo-gr.cpp"
#line 1285 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_tPLAYACCEL: /* tPLAYACCEL */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1289 "engines/director/lingo/lingo-gr.cpp"
#line 1291 "engines/director/lingo/lingo-gr.cpp"
break;
case YYSYMBOL_ID: /* ID */
#line 182 "engines/director/lingo/lingo-gr.y"
#line 184 "engines/director/lingo/lingo-gr.y"
{ delete ((*yyvaluep).s); }
#line 1295 "engines/director/lingo/lingo-gr.cpp"
#line 1297 "engines/director/lingo/lingo-gr.cpp"
break;
default:
@ -1557,624 +1559,624 @@ yyreduce:
switch (yyn)
{
case 2: /* script: scriptpartlist */
#line 188 "engines/director/lingo/lingo-gr.y"
{ g_lingo->_assemblyAST = new ScriptNode((yyvsp[0].nodelist)); }
#line 1563 "engines/director/lingo/lingo-gr.cpp"
#line 190 "engines/director/lingo/lingo-gr.y"
{ g_lingo->_compiler->_assemblyAST = new ScriptNode((yyvsp[0].nodelist)); }
#line 1565 "engines/director/lingo/lingo-gr.cpp"
break;
case 3: /* scriptpartlist: scriptpart */
#line 190 "engines/director/lingo/lingo-gr.y"
#line 192 "engines/director/lingo/lingo-gr.y"
{
NodeList *list = new NodeList;
if ((yyvsp[0].node)) {
list->push_back((yyvsp[0].node));
}
(yyval.nodelist) = list; }
#line 1574 "engines/director/lingo/lingo-gr.cpp"
#line 1576 "engines/director/lingo/lingo-gr.cpp"
break;
case 4: /* scriptpartlist: scriptpartlist scriptpart */
#line 196 "engines/director/lingo/lingo-gr.y"
#line 198 "engines/director/lingo/lingo-gr.y"
{
if ((yyvsp[0].node)) {
(yyvsp[-1].nodelist)->push_back((yyvsp[0].node));
}
(yyval.nodelist) = (yyvsp[-1].nodelist); }
#line 1584 "engines/director/lingo/lingo-gr.cpp"
#line 1586 "engines/director/lingo/lingo-gr.cpp"
break;
case 5: /* scriptpart: '\n' */
#line 203 "engines/director/lingo/lingo-gr.y"
#line 205 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = nullptr; }
#line 1590 "engines/director/lingo/lingo-gr.cpp"
#line 1592 "engines/director/lingo/lingo-gr.cpp"
break;
case 10: /* macro: tMACRO ID idlist '\n' stmtlist */
#line 236 "engines/director/lingo/lingo-gr.y"
#line 238 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new HandlerNode((yyvsp[-3].s), (yyvsp[-2].idlist), (yyvsp[0].nodelist)); }
#line 1596 "engines/director/lingo/lingo-gr.cpp"
#line 1598 "engines/director/lingo/lingo-gr.cpp"
break;
case 11: /* factory: tFACTORY ID '\n' methodlist */
#line 240 "engines/director/lingo/lingo-gr.y"
#line 242 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new FactoryNode((yyvsp[-2].s), (yyvsp[0].nodelist)); }
#line 1602 "engines/director/lingo/lingo-gr.cpp"
#line 1604 "engines/director/lingo/lingo-gr.cpp"
break;
case 12: /* method: tMETHOD ID idlist '\n' stmtlist */
#line 242 "engines/director/lingo/lingo-gr.y"
#line 244 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new HandlerNode((yyvsp[-3].s), (yyvsp[-2].idlist), (yyvsp[0].nodelist)); }
#line 1608 "engines/director/lingo/lingo-gr.cpp"
#line 1610 "engines/director/lingo/lingo-gr.cpp"
break;
case 13: /* methodlist: %empty */
#line 244 "engines/director/lingo/lingo-gr.y"
#line 246 "engines/director/lingo/lingo-gr.y"
{ (yyval.nodelist) = new NodeList; }
#line 1614 "engines/director/lingo/lingo-gr.cpp"
#line 1616 "engines/director/lingo/lingo-gr.cpp"
break;
case 15: /* nonemptymethodlist: methodlistline */
#line 248 "engines/director/lingo/lingo-gr.y"
#line 250 "engines/director/lingo/lingo-gr.y"
{
NodeList *list = new NodeList;
if ((yyvsp[0].node)) {
list->push_back((yyvsp[0].node));
}
(yyval.nodelist) = list; }
#line 1625 "engines/director/lingo/lingo-gr.cpp"
#line 1627 "engines/director/lingo/lingo-gr.cpp"
break;
case 16: /* nonemptymethodlist: methodlist '\n' methodlistline */
#line 254 "engines/director/lingo/lingo-gr.y"
#line 256 "engines/director/lingo/lingo-gr.y"
{
if ((yyvsp[0].node)) {
(yyvsp[-2].nodelist)->push_back((yyvsp[0].node));
}
(yyval.nodelist) = (yyvsp[-2].nodelist); }
#line 1635 "engines/director/lingo/lingo-gr.cpp"
#line 1637 "engines/director/lingo/lingo-gr.cpp"
break;
case 17: /* methodlistline: '\n' */
#line 261 "engines/director/lingo/lingo-gr.y"
#line 263 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = nullptr; }
#line 1641 "engines/director/lingo/lingo-gr.cpp"
#line 1643 "engines/director/lingo/lingo-gr.cpp"
break;
case 19: /* handler: tON ID idlist '\n' stmtlist tENDCLAUSE endargdef '\n' */
#line 267 "engines/director/lingo/lingo-gr.y"
#line 269 "engines/director/lingo/lingo-gr.y"
{ // D3
(yyval.node) = new HandlerNode((yyvsp[-6].s), (yyvsp[-5].idlist), (yyvsp[-3].nodelist));
checkEnd((yyvsp[-2].s), (yyvsp[-6].s), false);
delete (yyvsp[-2].s); }
#line 1650 "engines/director/lingo/lingo-gr.cpp"
#line 1652 "engines/director/lingo/lingo-gr.cpp"
break;
case 20: /* handler: tON ID idlist '\n' stmtlist */
#line 271 "engines/director/lingo/lingo-gr.y"
#line 273 "engines/director/lingo/lingo-gr.y"
{ // D4. No 'end' clause
(yyval.node) = new HandlerNode((yyvsp[-3].s), (yyvsp[-2].idlist), (yyvsp[0].nodelist)); }
#line 1657 "engines/director/lingo/lingo-gr.cpp"
#line 1659 "engines/director/lingo/lingo-gr.cpp"
break;
case 22: /* endargdef: ID */
#line 276 "engines/director/lingo/lingo-gr.y"
#line 278 "engines/director/lingo/lingo-gr.y"
{ delete (yyvsp[0].s); }
#line 1663 "engines/director/lingo/lingo-gr.cpp"
#line 1665 "engines/director/lingo/lingo-gr.cpp"
break;
case 23: /* endargdef: endargdef ',' ID */
#line 277 "engines/director/lingo/lingo-gr.y"
#line 279 "engines/director/lingo/lingo-gr.y"
{ delete (yyvsp[0].s); }
#line 1669 "engines/director/lingo/lingo-gr.cpp"
#line 1671 "engines/director/lingo/lingo-gr.cpp"
break;
case 25: /* ID: tAFTER */
#line 283 "engines/director/lingo/lingo-gr.y"
#line 285 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("after"); }
#line 1675 "engines/director/lingo/lingo-gr.cpp"
#line 1677 "engines/director/lingo/lingo-gr.cpp"
break;
case 26: /* ID: tAND */
#line 284 "engines/director/lingo/lingo-gr.y"
#line 286 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("and"); }
#line 1681 "engines/director/lingo/lingo-gr.cpp"
#line 1683 "engines/director/lingo/lingo-gr.cpp"
break;
case 27: /* ID: tBEFORE */
#line 285 "engines/director/lingo/lingo-gr.y"
#line 287 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("before"); }
#line 1687 "engines/director/lingo/lingo-gr.cpp"
#line 1689 "engines/director/lingo/lingo-gr.cpp"
break;
case 28: /* ID: tCAST */
#line 286 "engines/director/lingo/lingo-gr.y"
#line 288 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("cast"); }
#line 1693 "engines/director/lingo/lingo-gr.cpp"
#line 1695 "engines/director/lingo/lingo-gr.cpp"
break;
case 29: /* ID: tCHAR */
#line 287 "engines/director/lingo/lingo-gr.y"
#line 289 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("char"); }
#line 1699 "engines/director/lingo/lingo-gr.cpp"
#line 1701 "engines/director/lingo/lingo-gr.cpp"
break;
case 30: /* ID: tDOWN */
#line 288 "engines/director/lingo/lingo-gr.y"
#line 290 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("down"); }
#line 1705 "engines/director/lingo/lingo-gr.cpp"
#line 1707 "engines/director/lingo/lingo-gr.cpp"
break;
case 31: /* ID: tEXIT */
#line 291 "engines/director/lingo/lingo-gr.y"
#line 293 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("exit"); }
#line 1711 "engines/director/lingo/lingo-gr.cpp"
#line 1713 "engines/director/lingo/lingo-gr.cpp"
break;
case 32: /* ID: tFIELD */
#line 293 "engines/director/lingo/lingo-gr.y"
#line 295 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("field"); }
#line 1717 "engines/director/lingo/lingo-gr.cpp"
#line 1719 "engines/director/lingo/lingo-gr.cpp"
break;
case 33: /* ID: tIN */
#line 296 "engines/director/lingo/lingo-gr.y"
#line 298 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("in"); }
#line 1723 "engines/director/lingo/lingo-gr.cpp"
#line 1725 "engines/director/lingo/lingo-gr.cpp"
break;
case 34: /* ID: tINTERSECTS */
#line 298 "engines/director/lingo/lingo-gr.y"
#line 300 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("intersects"); }
#line 1729 "engines/director/lingo/lingo-gr.cpp"
#line 1731 "engines/director/lingo/lingo-gr.cpp"
break;
case 35: /* ID: tINTO */
#line 299 "engines/director/lingo/lingo-gr.y"
#line 301 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("into"); }
#line 1735 "engines/director/lingo/lingo-gr.cpp"
#line 1737 "engines/director/lingo/lingo-gr.cpp"
break;
case 36: /* ID: tITEM */
#line 300 "engines/director/lingo/lingo-gr.y"
#line 302 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("item"); }
#line 1741 "engines/director/lingo/lingo-gr.cpp"
#line 1743 "engines/director/lingo/lingo-gr.cpp"
break;
case 37: /* ID: tLINE */
#line 301 "engines/director/lingo/lingo-gr.y"
#line 303 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("line"); }
#line 1747 "engines/director/lingo/lingo-gr.cpp"
#line 1749 "engines/director/lingo/lingo-gr.cpp"
break;
case 38: /* ID: tMOD */
#line 304 "engines/director/lingo/lingo-gr.y"
#line 306 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("mod"); }
#line 1753 "engines/director/lingo/lingo-gr.cpp"
#line 1755 "engines/director/lingo/lingo-gr.cpp"
break;
case 39: /* ID: tMOVIE */
#line 305 "engines/director/lingo/lingo-gr.y"
#line 307 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("movie"); }
#line 1759 "engines/director/lingo/lingo-gr.cpp"
#line 1761 "engines/director/lingo/lingo-gr.cpp"
break;
case 40: /* ID: tNEXT */
#line 306 "engines/director/lingo/lingo-gr.y"
#line 308 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("next"); }
#line 1765 "engines/director/lingo/lingo-gr.cpp"
#line 1767 "engines/director/lingo/lingo-gr.cpp"
break;
case 41: /* ID: tNOT */
#line 307 "engines/director/lingo/lingo-gr.y"
#line 309 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("not"); }
#line 1771 "engines/director/lingo/lingo-gr.cpp"
#line 1773 "engines/director/lingo/lingo-gr.cpp"
break;
case 42: /* ID: tOF */
#line 308 "engines/director/lingo/lingo-gr.y"
#line 310 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("of"); }
#line 1777 "engines/director/lingo/lingo-gr.cpp"
#line 1779 "engines/director/lingo/lingo-gr.cpp"
break;
case 43: /* ID: tOPEN */
#line 310 "engines/director/lingo/lingo-gr.y"
#line 312 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("open"); }
#line 1783 "engines/director/lingo/lingo-gr.cpp"
#line 1785 "engines/director/lingo/lingo-gr.cpp"
break;
case 44: /* ID: tOR */
#line 311 "engines/director/lingo/lingo-gr.y"
#line 313 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("or"); }
#line 1789 "engines/director/lingo/lingo-gr.cpp"
#line 1791 "engines/director/lingo/lingo-gr.cpp"
break;
case 45: /* ID: tPLAY */
#line 312 "engines/director/lingo/lingo-gr.y"
#line 314 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("play"); }
#line 1795 "engines/director/lingo/lingo-gr.cpp"
#line 1797 "engines/director/lingo/lingo-gr.cpp"
break;
case 46: /* ID: tPLAYACCEL */
#line 313 "engines/director/lingo/lingo-gr.y"
#line 315 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("playAccel"); }
#line 1801 "engines/director/lingo/lingo-gr.cpp"
#line 1803 "engines/director/lingo/lingo-gr.cpp"
break;
case 47: /* ID: tPREVIOUS */
#line 314 "engines/director/lingo/lingo-gr.y"
#line 316 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("previous"); }
#line 1807 "engines/director/lingo/lingo-gr.cpp"
#line 1809 "engines/director/lingo/lingo-gr.cpp"
break;
case 48: /* ID: tPUT */
#line 316 "engines/director/lingo/lingo-gr.y"
#line 318 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("put"); }
#line 1813 "engines/director/lingo/lingo-gr.cpp"
#line 1815 "engines/director/lingo/lingo-gr.cpp"
break;
case 49: /* ID: tREPEAT */
#line 317 "engines/director/lingo/lingo-gr.y"
#line 319 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("repeat"); }
#line 1819 "engines/director/lingo/lingo-gr.cpp"
#line 1821 "engines/director/lingo/lingo-gr.cpp"
break;
case 50: /* ID: tSCRIPT */
#line 318 "engines/director/lingo/lingo-gr.y"
#line 320 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("script"); }
#line 1825 "engines/director/lingo/lingo-gr.cpp"
#line 1827 "engines/director/lingo/lingo-gr.cpp"
break;
case 51: /* ID: tSET */
#line 319 "engines/director/lingo/lingo-gr.y"
#line 321 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("set"); }
#line 1831 "engines/director/lingo/lingo-gr.cpp"
#line 1833 "engines/director/lingo/lingo-gr.cpp"
break;
case 52: /* ID: tSTARTS */
#line 320 "engines/director/lingo/lingo-gr.y"
#line 322 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("starts"); }
#line 1837 "engines/director/lingo/lingo-gr.cpp"
#line 1839 "engines/director/lingo/lingo-gr.cpp"
break;
case 53: /* ID: tTELL */
#line 321 "engines/director/lingo/lingo-gr.y"
#line 323 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("tell"); }
#line 1843 "engines/director/lingo/lingo-gr.cpp"
#line 1845 "engines/director/lingo/lingo-gr.cpp"
break;
case 54: /* ID: tTO */
#line 323 "engines/director/lingo/lingo-gr.y"
#line 325 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("to"); }
#line 1849 "engines/director/lingo/lingo-gr.cpp"
#line 1851 "engines/director/lingo/lingo-gr.cpp"
break;
case 55: /* ID: tASSERTERROR */
#line 324 "engines/director/lingo/lingo-gr.y"
#line 326 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("scummvmAssertError"); }
#line 1855 "engines/director/lingo/lingo-gr.cpp"
#line 1857 "engines/director/lingo/lingo-gr.cpp"
break;
case 56: /* ID: tSPRITE */
#line 325 "engines/director/lingo/lingo-gr.y"
#line 327 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("sprite"); }
#line 1861 "engines/director/lingo/lingo-gr.cpp"
#line 1863 "engines/director/lingo/lingo-gr.cpp"
break;
case 57: /* ID: tWHEN */
#line 326 "engines/director/lingo/lingo-gr.y"
#line 328 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("when"); }
#line 1867 "engines/director/lingo/lingo-gr.cpp"
#line 1869 "engines/director/lingo/lingo-gr.cpp"
break;
case 58: /* ID: tWHILE */
#line 327 "engines/director/lingo/lingo-gr.y"
#line 329 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("while"); }
#line 1873 "engines/director/lingo/lingo-gr.cpp"
#line 1875 "engines/director/lingo/lingo-gr.cpp"
break;
case 59: /* ID: tWINDOW */
#line 328 "engines/director/lingo/lingo-gr.y"
#line 330 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("window"); }
#line 1879 "engines/director/lingo/lingo-gr.cpp"
#line 1881 "engines/director/lingo/lingo-gr.cpp"
break;
case 60: /* ID: tWITH */
#line 329 "engines/director/lingo/lingo-gr.y"
#line 331 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("with"); }
#line 1885 "engines/director/lingo/lingo-gr.cpp"
#line 1887 "engines/director/lingo/lingo-gr.cpp"
break;
case 61: /* ID: tWITHIN */
#line 330 "engines/director/lingo/lingo-gr.y"
#line 332 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("within"); }
#line 1891 "engines/director/lingo/lingo-gr.cpp"
#line 1893 "engines/director/lingo/lingo-gr.cpp"
break;
case 62: /* ID: tWORD */
#line 331 "engines/director/lingo/lingo-gr.y"
#line 333 "engines/director/lingo/lingo-gr.y"
{ (yyval.s) = new Common::String("word"); }
#line 1897 "engines/director/lingo/lingo-gr.cpp"
#line 1899 "engines/director/lingo/lingo-gr.cpp"
break;
case 63: /* idlist: %empty */
#line 334 "engines/director/lingo/lingo-gr.y"
#line 336 "engines/director/lingo/lingo-gr.y"
{ (yyval.idlist) = new IDList; }
#line 1903 "engines/director/lingo/lingo-gr.cpp"
#line 1905 "engines/director/lingo/lingo-gr.cpp"
break;
case 65: /* nonemptyidlist: ID */
#line 338 "engines/director/lingo/lingo-gr.y"
#line 340 "engines/director/lingo/lingo-gr.y"
{
Common::Array<Common::String *> *list = new IDList;
list->push_back((yyvsp[0].s));
(yyval.idlist) = list; }
#line 1912 "engines/director/lingo/lingo-gr.cpp"
#line 1914 "engines/director/lingo/lingo-gr.cpp"
break;
case 66: /* nonemptyidlist: nonemptyidlist ',' ID */
#line 342 "engines/director/lingo/lingo-gr.y"
#line 344 "engines/director/lingo/lingo-gr.y"
{
(yyvsp[-2].idlist)->push_back((yyvsp[0].s));
(yyval.idlist) = (yyvsp[-2].idlist); }
#line 1920 "engines/director/lingo/lingo-gr.cpp"
#line 1922 "engines/director/lingo/lingo-gr.cpp"
break;
case 70: /* proc: ID '(' exprlist ')' */
#line 355 "engines/director/lingo/lingo-gr.y"
#line 357 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new CmdNode((yyvsp[-3].s), (yyvsp[-1].nodelist)); }
#line 1926 "engines/director/lingo/lingo-gr.cpp"
#line 1928 "engines/director/lingo/lingo-gr.cpp"
break;
case 71: /* proc: ID exprlist */
#line 356 "engines/director/lingo/lingo-gr.y"
#line 358 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new CmdNode((yyvsp[-1].s), (yyvsp[0].nodelist)); }
#line 1932 "engines/director/lingo/lingo-gr.cpp"
#line 1934 "engines/director/lingo/lingo-gr.cpp"
break;
case 72: /* definevars: tGLOBAL idlist */
#line 359 "engines/director/lingo/lingo-gr.y"
#line 361 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new GlobalNode((yyvsp[0].idlist)); }
#line 1938 "engines/director/lingo/lingo-gr.cpp"
#line 1940 "engines/director/lingo/lingo-gr.cpp"
break;
case 73: /* definevars: tPROPERTY idlist */
#line 360 "engines/director/lingo/lingo-gr.y"
#line 362 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new PropertyNode((yyvsp[0].idlist)); }
#line 1944 "engines/director/lingo/lingo-gr.cpp"
#line 1946 "engines/director/lingo/lingo-gr.cpp"
break;
case 74: /* definevars: tINSTANCE idlist */
#line 361 "engines/director/lingo/lingo-gr.y"
#line 363 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new InstanceNode((yyvsp[0].idlist)); }
#line 1950 "engines/director/lingo/lingo-gr.cpp"
#line 1952 "engines/director/lingo/lingo-gr.cpp"
break;
case 75: /* stmtlist: %empty */
#line 364 "engines/director/lingo/lingo-gr.y"
#line 366 "engines/director/lingo/lingo-gr.y"
{ (yyval.nodelist) = new NodeList; }
#line 1956 "engines/director/lingo/lingo-gr.cpp"
#line 1958 "engines/director/lingo/lingo-gr.cpp"
break;
case 77: /* nonemptystmtlist: stmtlistline */
#line 369 "engines/director/lingo/lingo-gr.y"
#line 371 "engines/director/lingo/lingo-gr.y"
{
NodeList *list = new NodeList;
if ((yyvsp[0].node)) {
list->push_back((yyvsp[0].node));
}
(yyval.nodelist) = list; }
#line 1967 "engines/director/lingo/lingo-gr.cpp"
#line 1969 "engines/director/lingo/lingo-gr.cpp"
break;
case 78: /* nonemptystmtlist: stmtlist stmtlistline */
#line 375 "engines/director/lingo/lingo-gr.y"
#line 377 "engines/director/lingo/lingo-gr.y"
{
if ((yyvsp[0].node)) {
(yyvsp[-1].nodelist)->push_back((yyvsp[0].node));
}
(yyval.nodelist) = (yyvsp[-1].nodelist); }
#line 1977 "engines/director/lingo/lingo-gr.cpp"
#line 1979 "engines/director/lingo/lingo-gr.cpp"
break;
case 79: /* stmtlistline: '\n' */
#line 382 "engines/director/lingo/lingo-gr.y"
#line 384 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = nullptr; }
#line 1983 "engines/director/lingo/lingo-gr.cpp"
#line 1985 "engines/director/lingo/lingo-gr.cpp"
break;
case 81: /* simpleexprnoparens: tINT */
#line 388 "engines/director/lingo/lingo-gr.y"
#line 390 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new IntNode((yyvsp[0].i)); }
#line 1989 "engines/director/lingo/lingo-gr.cpp"
#line 1991 "engines/director/lingo/lingo-gr.cpp"
break;
case 82: /* simpleexprnoparens: tFLOAT */
#line 389 "engines/director/lingo/lingo-gr.y"
#line 391 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new FloatNode((yyvsp[0].f)); }
#line 1995 "engines/director/lingo/lingo-gr.cpp"
#line 1997 "engines/director/lingo/lingo-gr.cpp"
break;
case 83: /* simpleexprnoparens: tSYMBOL */
#line 390 "engines/director/lingo/lingo-gr.y"
#line 392 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new SymbolNode((yyvsp[0].s)); }
#line 2001 "engines/director/lingo/lingo-gr.cpp"
#line 2003 "engines/director/lingo/lingo-gr.cpp"
break;
case 84: /* simpleexprnoparens: tSTRING */
#line 391 "engines/director/lingo/lingo-gr.y"
#line 393 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new StringNode((yyvsp[0].s)); }
#line 2007 "engines/director/lingo/lingo-gr.cpp"
#line 2009 "engines/director/lingo/lingo-gr.cpp"
break;
case 85: /* simpleexprnoparens: '+' simpleexpr */
#line 392 "engines/director/lingo/lingo-gr.y"
#line 394 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = (yyvsp[0].node); }
#line 2013 "engines/director/lingo/lingo-gr.cpp"
#line 2015 "engines/director/lingo/lingo-gr.cpp"
break;
case 86: /* simpleexprnoparens: '-' simpleexpr */
#line 393 "engines/director/lingo/lingo-gr.y"
#line 395 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new UnaryOpNode(LC::c_negate, (yyvsp[0].node)); }
#line 2019 "engines/director/lingo/lingo-gr.cpp"
#line 2021 "engines/director/lingo/lingo-gr.cpp"
break;
case 87: /* simpleexprnoparens: tNOT simpleexpr */
#line 394 "engines/director/lingo/lingo-gr.y"
#line 396 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new UnaryOpNode(LC::c_not, (yyvsp[0].node)); }
#line 2025 "engines/director/lingo/lingo-gr.cpp"
#line 2027 "engines/director/lingo/lingo-gr.cpp"
break;
case 88: /* simpleexprnoparens: ID '(' exprlist ')' */
#line 395 "engines/director/lingo/lingo-gr.y"
#line 397 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new FuncNode((yyvsp[-3].s), (yyvsp[-1].nodelist)); }
#line 2031 "engines/director/lingo/lingo-gr.cpp"
#line 2033 "engines/director/lingo/lingo-gr.cpp"
break;
case 89: /* simpleexprnoparens: ID */
#line 396 "engines/director/lingo/lingo-gr.y"
#line 398 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new VarNode((yyvsp[0].s)); }
#line 2037 "engines/director/lingo/lingo-gr.cpp"
#line 2039 "engines/director/lingo/lingo-gr.cpp"
break;
case 91: /* simpleexpr: '(' expr ')' */
#line 400 "engines/director/lingo/lingo-gr.y"
#line 402 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = (yyvsp[-1].node); }
#line 2043 "engines/director/lingo/lingo-gr.cpp"
#line 2045 "engines/director/lingo/lingo-gr.cpp"
break;
case 92: /* expr: simpleexpr */
#line 403 "engines/director/lingo/lingo-gr.y"
#line 405 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = (yyvsp[0].node); }
#line 2049 "engines/director/lingo/lingo-gr.cpp"
#line 2051 "engines/director/lingo/lingo-gr.cpp"
break;
case 93: /* expr: expr '+' expr */
#line 404 "engines/director/lingo/lingo-gr.y"
#line 406 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_add, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2055 "engines/director/lingo/lingo-gr.cpp"
#line 2057 "engines/director/lingo/lingo-gr.cpp"
break;
case 94: /* expr: expr '-' expr */
#line 405 "engines/director/lingo/lingo-gr.y"
#line 407 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_sub, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2061 "engines/director/lingo/lingo-gr.cpp"
#line 2063 "engines/director/lingo/lingo-gr.cpp"
break;
case 95: /* expr: expr '*' expr */
#line 406 "engines/director/lingo/lingo-gr.y"
#line 408 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_mul, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2067 "engines/director/lingo/lingo-gr.cpp"
#line 2069 "engines/director/lingo/lingo-gr.cpp"
break;
case 96: /* expr: expr '/' expr */
#line 407 "engines/director/lingo/lingo-gr.y"
#line 409 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_div, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2073 "engines/director/lingo/lingo-gr.cpp"
#line 2075 "engines/director/lingo/lingo-gr.cpp"
break;
case 97: /* expr: expr tMOD expr */
#line 408 "engines/director/lingo/lingo-gr.y"
#line 410 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_mod, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2079 "engines/director/lingo/lingo-gr.cpp"
#line 2081 "engines/director/lingo/lingo-gr.cpp"
break;
case 98: /* expr: expr '>' expr */
#line 409 "engines/director/lingo/lingo-gr.y"
#line 411 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_gt, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2085 "engines/director/lingo/lingo-gr.cpp"
#line 2087 "engines/director/lingo/lingo-gr.cpp"
break;
case 99: /* expr: expr '<' expr */
#line 410 "engines/director/lingo/lingo-gr.y"
#line 412 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_lt, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2091 "engines/director/lingo/lingo-gr.cpp"
#line 2093 "engines/director/lingo/lingo-gr.cpp"
break;
case 100: /* expr: expr tEQ expr */
#line 411 "engines/director/lingo/lingo-gr.y"
#line 413 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_eq, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2097 "engines/director/lingo/lingo-gr.cpp"
#line 2099 "engines/director/lingo/lingo-gr.cpp"
break;
case 101: /* expr: expr tNEQ expr */
#line 412 "engines/director/lingo/lingo-gr.y"
#line 414 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_neq, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2103 "engines/director/lingo/lingo-gr.cpp"
#line 2105 "engines/director/lingo/lingo-gr.cpp"
break;
case 102: /* expr: expr tGE expr */
#line 413 "engines/director/lingo/lingo-gr.y"
#line 415 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_ge, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2109 "engines/director/lingo/lingo-gr.cpp"
#line 2111 "engines/director/lingo/lingo-gr.cpp"
break;
case 103: /* expr: expr tLE expr */
#line 414 "engines/director/lingo/lingo-gr.y"
#line 416 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_le, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2115 "engines/director/lingo/lingo-gr.cpp"
#line 2117 "engines/director/lingo/lingo-gr.cpp"
break;
case 104: /* expr: expr tAND expr */
#line 415 "engines/director/lingo/lingo-gr.y"
#line 417 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_and, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2121 "engines/director/lingo/lingo-gr.cpp"
#line 2123 "engines/director/lingo/lingo-gr.cpp"
break;
case 105: /* expr: expr tOR expr */
#line 416 "engines/director/lingo/lingo-gr.y"
#line 418 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_or, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2127 "engines/director/lingo/lingo-gr.cpp"
#line 2129 "engines/director/lingo/lingo-gr.cpp"
break;
case 106: /* expr: expr '&' expr */
#line 417 "engines/director/lingo/lingo-gr.y"
#line 419 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_ampersand, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2133 "engines/director/lingo/lingo-gr.cpp"
#line 2135 "engines/director/lingo/lingo-gr.cpp"
break;
case 107: /* expr: expr tCONCAT expr */
#line 418 "engines/director/lingo/lingo-gr.y"
#line 420 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_concat, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2139 "engines/director/lingo/lingo-gr.cpp"
#line 2141 "engines/director/lingo/lingo-gr.cpp"
break;
case 108: /* expr: expr tCONTAINS expr */
#line 419 "engines/director/lingo/lingo-gr.y"
#line 421 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_contains, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2145 "engines/director/lingo/lingo-gr.cpp"
#line 2147 "engines/director/lingo/lingo-gr.cpp"
break;
case 109: /* expr: expr tSTARTS expr */
#line 420 "engines/director/lingo/lingo-gr.y"
#line 422 "engines/director/lingo/lingo-gr.y"
{ (yyval.node) = new BinaryOpNode(LC::c_starts, (yyvsp[-2].node), (yyvsp[0].node)); }
#line 2151 "engines/director/lingo/lingo-gr.cpp"
#line 2153 "engines/director/lingo/lingo-gr.cpp"
break;
case 110: /* exprlist: %empty */
#line 423 "engines/director/lingo/lingo-gr.y"
#line 425 "engines/director/lingo/lingo-gr.y"
{ (yyval.nodelist) = new NodeList; }
#line 2157 "engines/director/lingo/lingo-gr.cpp"
#line 2159 "engines/director/lingo/lingo-gr.cpp"
break;
case 112: /* nonemptyexprlist: expr */
#line 427 "engines/director/lingo/lingo-gr.y"
#line 429 "engines/director/lingo/lingo-gr.y"
{
NodeList *list = new NodeList;
list->push_back((yyvsp[0].node));
(yyval.nodelist) = list; }
#line 2166 "engines/director/lingo/lingo-gr.cpp"
#line 2168 "engines/director/lingo/lingo-gr.cpp"
break;
case 113: /* nonemptyexprlist: nonemptyexprlist ',' expr */
#line 431 "engines/director/lingo/lingo-gr.y"
#line 433 "engines/director/lingo/lingo-gr.y"
{
(yyvsp[-2].nodelist)->push_back((yyvsp[0].node));
(yyval.nodelist) = (yyvsp[-2].nodelist); }
#line 2174 "engines/director/lingo/lingo-gr.cpp"
#line 2176 "engines/director/lingo/lingo-gr.cpp"
break;
#line 2178 "engines/director/lingo/lingo-gr.cpp"
#line 2180 "engines/director/lingo/lingo-gr.cpp"
default: break;
}
@ -2373,7 +2375,7 @@ yyreturn:
return yyresult;
}
#line 436 "engines/director/lingo/lingo-gr.y"
#line 438 "engines/director/lingo/lingo-gr.y"
int yyreport_syntax_error(const yypcontext_t *ctx) {

View File

@ -137,7 +137,7 @@ extern int yydebug;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 109 "engines/director/lingo/lingo-gr.y"
#line 111 "engines/director/lingo/lingo-gr.y"
Common::String *s;
int i;

View File

@ -62,6 +62,7 @@
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-gr.h"
#include "director/lingo/lingo-object.h"
@ -71,25 +72,26 @@ extern int yyparse();
using namespace Director;
static void yyerror(const char *s) {
g_lingo->_hadError = true;
LingoCompiler *compiler = g_lingo->_compiler;
compiler->_hadError = true;
warning("###################### LINGO: %s at line %d col %d in %s id: %d",
s, g_lingo->_linenumber, g_lingo->_colnumber, scriptType2str(g_lingo->_assemblyContext->_scriptType),
g_lingo->_assemblyContext->_id);
if (g_lingo->_lines[2] != g_lingo->_lines[1])
warning("# %3d: %s", g_lingo->_linenumber - 2, Common::String(g_lingo->_lines[2], g_lingo->_lines[1] - 1).c_str());
s, compiler->_linenumber, compiler->_colnumber, scriptType2str(compiler->_assemblyContext->_scriptType),
compiler->_assemblyContext->_id);
if (compiler->_lines[2] != compiler->_lines[1])
warning("# %3d: %s", compiler->_linenumber - 2, Common::String(compiler->_lines[2], compiler->_lines[1] - 1).c_str());
if (g_lingo->_lines[1] != g_lingo->_lines[0])
warning("# %3d: %s", g_lingo->_linenumber - 1, Common::String(g_lingo->_lines[1], g_lingo->_lines[0] - 1).c_str());
if (compiler->_lines[1] != compiler->_lines[0])
warning("# %3d: %s", compiler->_linenumber - 1, Common::String(compiler->_lines[1], compiler->_lines[0] - 1).c_str());
const char *ptr = g_lingo->_lines[0];
const char *ptr = compiler->_lines[0];
while (*ptr && *ptr != '\n')
ptr++;
warning("# %3d: %s", g_lingo->_linenumber, Common::String(g_lingo->_lines[0], ptr).c_str());
warning("# %3d: %s", compiler->_linenumber, Common::String(compiler->_lines[0], ptr).c_str());
Common::String arrow;
for (uint i = 0; i < g_lingo->_colnumber; i++)
for (uint i = 0; i < compiler->_colnumber; i++)
arrow += ' ';
warning("# %s^ about here", arrow.c_str());
@ -185,7 +187,7 @@ static void checkEnd(Common::String *token, Common::String *expect, bool require
// TOP-LEVEL STUFF
script: scriptpartlist { g_lingo->_assemblyAST = new ScriptNode($scriptpartlist); } ;
script: scriptpartlist { g_lingo->_compiler->_assemblyAST = new ScriptNode($scriptpartlist); } ;
scriptpartlist: scriptpart[item] {
NodeList *list = new NodeList;

View File

@ -757,6 +757,7 @@ char *yytext;
#include "director/director.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-gr.h"
#include "director/lingo/lingo-the.h"
@ -768,32 +769,36 @@ static uint inputlen;
// Push lines in stack
static void pushLine(uint num) {
LingoCompiler *compiler = g_lingo->_compiler;
if (num > inputlen)
return;
g_lingo->_lines[2] = g_lingo->_lines[1];
g_lingo->_lines[1] = g_lingo->_lines[0];
g_lingo->_lines[0] = &inputbuffer[num];
compiler->_lines[2] = compiler->_lines[1];
compiler->_lines[1] = compiler->_lines[0];
compiler->_lines[0] = &inputbuffer[num];
}
static void count() {
LingoCompiler *compiler = g_lingo->_compiler;
if (debugChannelSet(-1, kDebugParse))
debug("LEXER: Read '%s' at %d:%d", yytext, g_lingo->_linenumber, g_lingo->_colnumber);
debug("LEXER: Read '%s' at %d:%d", yytext, compiler->_linenumber, compiler->_colnumber);
char *p = yytext;
while (*p) {
if (*p == '\n' || *p == '\xC2') {
g_lingo->_linenumber++;
g_lingo->_colnumber = 0;
compiler->_linenumber++;
compiler->_colnumber = 0;
if (*p == '\n')
pushLine(g_lingo->_bytenumber + 1);
pushLine(compiler->_bytenumber + 1);
} else {
g_lingo->_colnumber++;
compiler->_colnumber++;
}
p++;
g_lingo->_bytenumber++;
compiler->_bytenumber++;
}
}
@ -813,8 +818,8 @@ static Common::String *cleanupString(const char *s) {
return res;
}
#line 816 "engines/director/lingo/lingo-lex.cpp"
#line 817 "engines/director/lingo/lingo-lex.cpp"
#line 821 "engines/director/lingo/lingo-lex.cpp"
#line 822 "engines/director/lingo/lingo-lex.cpp"
#define INITIAL 0
@ -1034,10 +1039,10 @@ YY_DECL
}
{
#line 106 "engines/director/lingo/lingo-lex.l"
#line 111 "engines/director/lingo/lingo-lex.l"
#line 1040 "engines/director/lingo/lingo-lex.cpp"
#line 1045 "engines/director/lingo/lingo-lex.cpp"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@ -1093,67 +1098,67 @@ do_action: /* This label is used only to access EOF actions. */
case 1:
YY_RULE_SETUP
#line 108 "engines/director/lingo/lingo-lex.l"
#line 113 "engines/director/lingo/lingo-lex.l"
{ count(); }
YY_BREAK
case 2:
YY_RULE_SETUP
#line 110 "engines/director/lingo/lingo-lex.l"
#line 115 "engines/director/lingo/lingo-lex.l"
{ count(); yylval.s = new Common::String(yytext + 1); return SYMBOL; } // D3, skip '#'
YY_BREAK
case 3:
YY_RULE_SETUP
#line 112 "engines/director/lingo/lingo-lex.l"
#line 117 "engines/director/lingo/lingo-lex.l"
{ count(); return tAFTER; } // D3
YY_BREAK
case 4:
YY_RULE_SETUP
#line 113 "engines/director/lingo/lingo-lex.l"
#line 118 "engines/director/lingo/lingo-lex.l"
{ count(); return tAND; }
YY_BREAK
case 5:
YY_RULE_SETUP
#line 114 "engines/director/lingo/lingo-lex.l"
#line 119 "engines/director/lingo/lingo-lex.l"
{ count(); return tBEFORE; } // D3
YY_BREAK
case 6:
YY_RULE_SETUP
#line 115 "engines/director/lingo/lingo-lex.l"
#line 120 "engines/director/lingo/lingo-lex.l"
{ count(); return tCAST; }
YY_BREAK
case 7:
YY_RULE_SETUP
#line 116 "engines/director/lingo/lingo-lex.l"
#line 121 "engines/director/lingo/lingo-lex.l"
{ count(); return tCHAR; } // D3
YY_BREAK
case 8:
YY_RULE_SETUP
#line 117 "engines/director/lingo/lingo-lex.l"
#line 122 "engines/director/lingo/lingo-lex.l"
{ count(); return tCONTAINS; }
YY_BREAK
case 9:
YY_RULE_SETUP
#line 118 "engines/director/lingo/lingo-lex.l"
#line 123 "engines/director/lingo/lingo-lex.l"
{ count(); return tDOWN; }
YY_BREAK
case 10:
YY_RULE_SETUP
#line 119 "engines/director/lingo/lingo-lex.l"
#line 124 "engines/director/lingo/lingo-lex.l"
{ count(); return tIF; }
YY_BREAK
case 11:
YY_RULE_SETUP
#line 120 "engines/director/lingo/lingo-lex.l"
#line 125 "engines/director/lingo/lingo-lex.l"
{ count(); return tELSIF; }
YY_BREAK
case 12:
YY_RULE_SETUP
#line 121 "engines/director/lingo/lingo-lex.l"
#line 126 "engines/director/lingo/lingo-lex.l"
{ count(); return tELSE; }
YY_BREAK
case 13:
YY_RULE_SETUP
#line 122 "engines/director/lingo/lingo-lex.l"
#line 127 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1175,177 +1180,177 @@ YY_RULE_SETUP
YY_BREAK
case 14:
YY_RULE_SETUP
#line 140 "engines/director/lingo/lingo-lex.l"
#line 145 "engines/director/lingo/lingo-lex.l"
{ count(); return tFACTORY; }
YY_BREAK
case 15:
YY_RULE_SETUP
#line 141 "engines/director/lingo/lingo-lex.l"
#line 146 "engines/director/lingo/lingo-lex.l"
{ count(); return tEXIT; }
YY_BREAK
case 16:
YY_RULE_SETUP
#line 142 "engines/director/lingo/lingo-lex.l"
#line 147 "engines/director/lingo/lingo-lex.l"
{ count(); return tFIELD; }
YY_BREAK
case 17:
YY_RULE_SETUP
#line 143 "engines/director/lingo/lingo-lex.l"
#line 148 "engines/director/lingo/lingo-lex.l"
{ count(); return tGLOBAL; }
YY_BREAK
case 18:
YY_RULE_SETUP
#line 144 "engines/director/lingo/lingo-lex.l"
#line 149 "engines/director/lingo/lingo-lex.l"
{ count(); return tGO; }
YY_BREAK
case 19:
YY_RULE_SETUP
#line 145 "engines/director/lingo/lingo-lex.l"
#line 150 "engines/director/lingo/lingo-lex.l"
{ count(); return tGO; }
YY_BREAK
case 20:
YY_RULE_SETUP
#line 146 "engines/director/lingo/lingo-lex.l"
#line 151 "engines/director/lingo/lingo-lex.l"
{ count(); return tGOLOOP; }
YY_BREAK
case 21:
YY_RULE_SETUP
#line 147 "engines/director/lingo/lingo-lex.l"
#line 152 "engines/director/lingo/lingo-lex.l"
{ count(); return tINSTANCE; }
YY_BREAK
case 22:
YY_RULE_SETUP
#line 148 "engines/director/lingo/lingo-lex.l"
#line 153 "engines/director/lingo/lingo-lex.l"
{ count(); return tINTERSECTS;}
YY_BREAK
case 23:
YY_RULE_SETUP
#line 149 "engines/director/lingo/lingo-lex.l"
#line 154 "engines/director/lingo/lingo-lex.l"
{ count(); return tINTO; }
YY_BREAK
case 24:
YY_RULE_SETUP
#line 150 "engines/director/lingo/lingo-lex.l"
#line 155 "engines/director/lingo/lingo-lex.l"
{ count(); return tIN; }
YY_BREAK
case 25:
YY_RULE_SETUP
#line 151 "engines/director/lingo/lingo-lex.l"
#line 156 "engines/director/lingo/lingo-lex.l"
{ count(); return tITEM; }
YY_BREAK
case 26:
YY_RULE_SETUP
#line 152 "engines/director/lingo/lingo-lex.l"
#line 157 "engines/director/lingo/lingo-lex.l"
{ count(); return tLINE; }
YY_BREAK
case 27:
YY_RULE_SETUP
#line 153 "engines/director/lingo/lingo-lex.l"
#line 158 "engines/director/lingo/lingo-lex.l"
{ count(); return tMACRO;; }
YY_BREAK
case 28:
YY_RULE_SETUP
#line 154 "engines/director/lingo/lingo-lex.l"
#line 159 "engines/director/lingo/lingo-lex.l"
{ count(); return tMETHOD; }
YY_BREAK
case 29:
YY_RULE_SETUP
#line 155 "engines/director/lingo/lingo-lex.l"
#line 160 "engines/director/lingo/lingo-lex.l"
{ count(); return tMOD;}
YY_BREAK
case 30:
YY_RULE_SETUP
#line 156 "engines/director/lingo/lingo-lex.l"
#line 161 "engines/director/lingo/lingo-lex.l"
{ count(); return tMOVIE; }
YY_BREAK
case 31:
YY_RULE_SETUP
#line 157 "engines/director/lingo/lingo-lex.l"
#line 162 "engines/director/lingo/lingo-lex.l"
{ count(); return tNEXT; }
YY_BREAK
case 32:
YY_RULE_SETUP
#line 158 "engines/director/lingo/lingo-lex.l"
#line 163 "engines/director/lingo/lingo-lex.l"
{ count(); return tNOT; }
YY_BREAK
case 33:
YY_RULE_SETUP
#line 159 "engines/director/lingo/lingo-lex.l"
#line 164 "engines/director/lingo/lingo-lex.l"
{ count(); return tOF; }
YY_BREAK
case 34:
YY_RULE_SETUP
#line 160 "engines/director/lingo/lingo-lex.l"
#line 165 "engines/director/lingo/lingo-lex.l"
{ count(); return tON; } // D3
YY_BREAK
case 35:
YY_RULE_SETUP
#line 161 "engines/director/lingo/lingo-lex.l"
#line 166 "engines/director/lingo/lingo-lex.l"
{ count(); return tOPEN; }
YY_BREAK
case 36:
YY_RULE_SETUP
#line 162 "engines/director/lingo/lingo-lex.l"
#line 167 "engines/director/lingo/lingo-lex.l"
{ count(); return tOR; }
YY_BREAK
case 37:
YY_RULE_SETUP
#line 163 "engines/director/lingo/lingo-lex.l"
#line 168 "engines/director/lingo/lingo-lex.l"
{ count(); return tPLAY; }
YY_BREAK
case 38:
YY_RULE_SETUP
#line 164 "engines/director/lingo/lingo-lex.l"
#line 169 "engines/director/lingo/lingo-lex.l"
{ count(); return tPLAY; }
YY_BREAK
case 39:
YY_RULE_SETUP
#line 165 "engines/director/lingo/lingo-lex.l"
#line 170 "engines/director/lingo/lingo-lex.l"
{ count(); return tPLAYACCEL; }
YY_BREAK
case 40:
YY_RULE_SETUP
#line 166 "engines/director/lingo/lingo-lex.l"
#line 171 "engines/director/lingo/lingo-lex.l"
{ count(); return tPREVIOUS; }
YY_BREAK
case 41:
YY_RULE_SETUP
#line 167 "engines/director/lingo/lingo-lex.l"
#line 172 "engines/director/lingo/lingo-lex.l"
{ count(); return tPROPERTY; } // D4
YY_BREAK
case 42:
YY_RULE_SETUP
#line 168 "engines/director/lingo/lingo-lex.l"
#line 173 "engines/director/lingo/lingo-lex.l"
{ count(); return tPUT; }
YY_BREAK
case 43:
YY_RULE_SETUP
#line 169 "engines/director/lingo/lingo-lex.l"
#line 174 "engines/director/lingo/lingo-lex.l"
{ count(); return tREPEAT; }
YY_BREAK
case 44:
YY_RULE_SETUP
#line 170 "engines/director/lingo/lingo-lex.l"
#line 175 "engines/director/lingo/lingo-lex.l"
{ count(); return tSCRIPT; }
YY_BREAK
case 45:
YY_RULE_SETUP
#line 171 "engines/director/lingo/lingo-lex.l"
#line 176 "engines/director/lingo/lingo-lex.l"
{ count(); return tSET; }
YY_BREAK
case 46:
YY_RULE_SETUP
#line 172 "engines/director/lingo/lingo-lex.l"
#line 177 "engines/director/lingo/lingo-lex.l"
{ count(); return tSTARTS; }
YY_BREAK
case 47:
YY_RULE_SETUP
#line 173 "engines/director/lingo/lingo-lex.l"
#line 178 "engines/director/lingo/lingo-lex.l"
{ count(); return tTELL; }
YY_BREAK
case 48:
YY_RULE_SETUP
#line 174 "engines/director/lingo/lingo-lex.l"
#line 179 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1384,7 +1389,7 @@ YY_RULE_SETUP
YY_BREAK
case 49:
YY_RULE_SETUP
#line 209 "engines/director/lingo/lingo-lex.l"
#line 214 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1410,7 +1415,7 @@ YY_RULE_SETUP
YY_BREAK
case 50:
YY_RULE_SETUP
#line 231 "engines/director/lingo/lingo-lex.l"
#line 236 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1487,7 +1492,7 @@ YY_RULE_SETUP
YY_BREAK
case 51:
YY_RULE_SETUP
#line 304 "engines/director/lingo/lingo-lex.l"
#line 309 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1525,7 +1530,7 @@ YY_RULE_SETUP
YY_BREAK
case 52:
YY_RULE_SETUP
#line 338 "engines/director/lingo/lingo-lex.l"
#line 343 "engines/director/lingo/lingo-lex.l"
{
count();
@ -1555,82 +1560,82 @@ YY_RULE_SETUP
YY_BREAK
case 53:
YY_RULE_SETUP
#line 364 "engines/director/lingo/lingo-lex.l"
#line 369 "engines/director/lingo/lingo-lex.l"
{ count(); return tTHEN; }
YY_BREAK
case 54:
YY_RULE_SETUP
#line 365 "engines/director/lingo/lingo-lex.l"
#line 370 "engines/director/lingo/lingo-lex.l"
{ count(); return tTO; }
YY_BREAK
case 55:
YY_RULE_SETUP
#line 366 "engines/director/lingo/lingo-lex.l"
#line 371 "engines/director/lingo/lingo-lex.l"
{ count(); return tASSERTERROR; }
YY_BREAK
case 56:
YY_RULE_SETUP
#line 367 "engines/director/lingo/lingo-lex.l"
#line 372 "engines/director/lingo/lingo-lex.l"
{ count(); return tSPRITE; }
YY_BREAK
case 57:
YY_RULE_SETUP
#line 368 "engines/director/lingo/lingo-lex.l"
#line 373 "engines/director/lingo/lingo-lex.l"
{ count(); return tWITH; }
YY_BREAK
case 58:
YY_RULE_SETUP
#line 369 "engines/director/lingo/lingo-lex.l"
#line 374 "engines/director/lingo/lingo-lex.l"
{ count(); return tWITHIN; }
YY_BREAK
case 59:
YY_RULE_SETUP
#line 370 "engines/director/lingo/lingo-lex.l"
#line 375 "engines/director/lingo/lingo-lex.l"
{ count(); return tWHEN; }
YY_BREAK
case 60:
YY_RULE_SETUP
#line 371 "engines/director/lingo/lingo-lex.l"
#line 376 "engines/director/lingo/lingo-lex.l"
{ count(); return tWHILE; }
YY_BREAK
case 61:
YY_RULE_SETUP
#line 372 "engines/director/lingo/lingo-lex.l"
#line 377 "engines/director/lingo/lingo-lex.l"
{ count(); return tWINDOW; }
YY_BREAK
case 62:
YY_RULE_SETUP
#line 373 "engines/director/lingo/lingo-lex.l"
#line 378 "engines/director/lingo/lingo-lex.l"
{ count(); return tWORD; }
YY_BREAK
case 63:
YY_RULE_SETUP
#line 375 "engines/director/lingo/lingo-lex.l"
#line 380 "engines/director/lingo/lingo-lex.l"
{ count(); return tNEQ; }
YY_BREAK
case 64:
YY_RULE_SETUP
#line 376 "engines/director/lingo/lingo-lex.l"
#line 381 "engines/director/lingo/lingo-lex.l"
{ count(); return tGE; }
YY_BREAK
case 65:
YY_RULE_SETUP
#line 377 "engines/director/lingo/lingo-lex.l"
#line 382 "engines/director/lingo/lingo-lex.l"
{ count(); return tLE; }
YY_BREAK
case 66:
YY_RULE_SETUP
#line 378 "engines/director/lingo/lingo-lex.l"
#line 383 "engines/director/lingo/lingo-lex.l"
{ count(); return tCONCAT; }
YY_BREAK
case 67:
YY_RULE_SETUP
#line 379 "engines/director/lingo/lingo-lex.l"
#line 384 "engines/director/lingo/lingo-lex.l"
{ count(); return tEQ; }
YY_BREAK
case 68:
YY_RULE_SETUP
#line 381 "engines/director/lingo/lingo-lex.l"
#line 386 "engines/director/lingo/lingo-lex.l"
{
count();
yylval.s = new Common::String(yytext);
@ -1640,41 +1645,41 @@ YY_RULE_SETUP
YY_BREAK
case 69:
YY_RULE_SETUP
#line 387 "engines/director/lingo/lingo-lex.l"
#line 392 "engines/director/lingo/lingo-lex.l"
{ count(); yylval.f = atof(yytext); return tFLOAT; }
YY_BREAK
case 70:
YY_RULE_SETUP
#line 388 "engines/director/lingo/lingo-lex.l"
#line 393 "engines/director/lingo/lingo-lex.l"
{ count(); yylval.i = strtol(yytext, NULL, 10); return tINT; }
YY_BREAK
case 71:
YY_RULE_SETUP
#line 389 "engines/director/lingo/lingo-lex.l"
#line 394 "engines/director/lingo/lingo-lex.l"
{ count(); return *yytext; }
YY_BREAK
case 72:
/* rule 72 can match eol */
YY_RULE_SETUP
#line 390 "engines/director/lingo/lingo-lex.l"
#line 395 "engines/director/lingo/lingo-lex.l"
{ count(); return '\n'; }
YY_BREAK
case 73:
YY_RULE_SETUP
#line 391 "engines/director/lingo/lingo-lex.l"
#line 396 "engines/director/lingo/lingo-lex.l"
{ count(); yylval.s = cleanupString(&yytext[1]); yylval.s->deleteLastChar(); return tSTRING; }
YY_BREAK
case 74:
YY_RULE_SETUP
#line 392 "engines/director/lingo/lingo-lex.l"
#line 397 "engines/director/lingo/lingo-lex.l"
{ count(); }
YY_BREAK
case 75:
YY_RULE_SETUP
#line 394 "engines/director/lingo/lingo-lex.l"
#line 399 "engines/director/lingo/lingo-lex.l"
ECHO;
YY_BREAK
#line 1677 "engines/director/lingo/lingo-lex.cpp"
#line 1682 "engines/director/lingo/lingo-lex.cpp"
case YY_STATE_EOF(INITIAL):
yyterminate();
@ -2683,16 +2688,16 @@ void yyfree (void * ptr )
#define YYTABLES_NAME "yytables"
#line 394 "engines/director/lingo/lingo-lex.l"
#line 399 "engines/director/lingo/lingo-lex.l"
extern int yydebug;
namespace Director {
int Lingo::parse(const char *code) {
int LingoCompiler::parse(const char *code) {
inputbuffer = code;
g_lingo->_bytenumber = 0;
_bytenumber = 0;
inputlen = strlen(code);
_lines[0] = _lines[1] = _lines[2] = code;

View File

@ -37,6 +37,7 @@
#include "director/director.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-gr.h"
#include "director/lingo/lingo-the.h"
@ -48,32 +49,36 @@ static uint inputlen;
// Push lines in stack
static void pushLine(uint num) {
LingoCompiler *compiler = g_lingo->_compiler;
if (num > inputlen)
return;
g_lingo->_lines[2] = g_lingo->_lines[1];
g_lingo->_lines[1] = g_lingo->_lines[0];
g_lingo->_lines[0] = &inputbuffer[num];
compiler->_lines[2] = compiler->_lines[1];
compiler->_lines[1] = compiler->_lines[0];
compiler->_lines[0] = &inputbuffer[num];
}
static void count() {
LingoCompiler *compiler = g_lingo->_compiler;
if (debugChannelSet(-1, kDebugParse))
debug("LEXER: Read '%s' at %d:%d", yytext, g_lingo->_linenumber, g_lingo->_colnumber);
debug("LEXER: Read '%s' at %d:%d", yytext, compiler->_linenumber, compiler->_colnumber);
char *p = yytext;
while (*p) {
if (*p == '\n' || *p == '\xC2') {
g_lingo->_linenumber++;
g_lingo->_colnumber = 0;
compiler->_linenumber++;
compiler->_colnumber = 0;
if (*p == '\n')
pushLine(g_lingo->_bytenumber + 1);
pushLine(compiler->_bytenumber + 1);
} else {
g_lingo->_colnumber++;
compiler->_colnumber++;
}
p++;
g_lingo->_bytenumber++;
compiler->_bytenumber++;
}
}
@ -397,9 +402,9 @@ extern int yydebug;
namespace Director {
int Lingo::parse(const char *code) {
int LingoCompiler::parse(const char *code) {
inputbuffer = code;
g_lingo->_bytenumber = 0;
_bytenumber = 0;
inputlen = strlen(code);
_lines[0] = _lines[1] = _lines[2] = code;

View File

@ -201,6 +201,40 @@ Common::String ScriptContext::asString() {
return Common::String::format("script: #%s %d %p", _name.c_str(), _inheritanceLevel, (void *)this);
}
Symbol ScriptContext::define(Common::String &name, int nargs, ScriptData *code, Common::Array<Common::String> *argNames, Common::Array<Common::String> *varNames) {
Symbol sym;
sym.name = new Common::String(name);
sym.type = HANDLER;
sym.u.defn = code;
sym.nargs = nargs;
sym.maxArgs = nargs;
sym.argNames = argNames;
sym.varNames = varNames;
sym.ctx = this;
sym.archive = _archive;
if (debugChannelSet(1, kDebugCompile)) {
uint pc = 0;
while (pc < sym.u.defn->size()) {
uint spc = pc;
Common::String instr = g_lingo->decodeInstruction(_archive, sym.u.defn, pc, &pc);
debugC(1, kDebugCompile, "[%5d] %s", spc, instr.c_str());
}
debugC(1, kDebugCompile, "<end define code>");
}
if (!g_lingo->_eventHandlerTypeIds.contains(name)) {
_functionHandlers[name] = sym;
if (_scriptType == kMovieScript && _archive && !_archive->functionHandlers.contains(name)) {
_archive->functionHandlers[name] = sym;
}
} else {
_eventHandlers[g_lingo->_eventHandlerTypeIds[name]] = sym;
}
return sym;
}
Symbol ScriptContext::getMethod(const Common::String &methodName) {
Symbol sym;

View File

@ -23,7 +23,7 @@
#include "director/director.h"
#include "director/cast.h"
#include "director/movie.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-codegen.h"
namespace Director {
@ -165,25 +165,25 @@ struct ScriptPatch {
{nullptr, nullptr, kPlatformUnknown, nullptr, kNoneScript, 0, 0, nullptr, nullptr}
};
Common::String Lingo::patchLingoCode(Common::String &line, LingoArchive *archive, ScriptType type, uint16 id, int linenum) {
Common::String LingoCompiler::patchLingoCode(Common::String &line, LingoArchive *archive, ScriptType type, uint16 id, int linenum) {
if (!archive)
return line;
const ScriptPatch *patch = scriptPatches;
Common::String movie = _vm->getCurrentPath() + archive->cast->getMacName();
Common::String movie = g_director->getCurrentPath() + archive->cast->getMacName();
// So far, we have not many patches, so do linear lookup
while (patch->gameId) {
// First, we do cheap comparisons
if (patch->type != type || patch->id != id || patch->linenum != linenum ||
(patch->platform != kPlatformUnknown && patch->platform != _vm->getPlatform())) {
(patch->platform != kPlatformUnknown && patch->platform != g_director->getPlatform())) {
patch++;
continue;
}
// Now expensive ones
if (movie.compareToIgnoreCase(patch->movie) || strcmp(patch->gameId, _vm->getGameId())
|| (patch->extra && strcmp(patch->extra, _vm->getExtra()))) {
if (movie.compareToIgnoreCase(patch->movie) || strcmp(patch->gameId, g_director->getGameId())
|| (patch->extra && strcmp(patch->extra, g_director->getExtra()))) {
patch++;
continue;
}

View File

@ -22,7 +22,7 @@
#include "director/director.h"
#include "director/movie.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-codegen.h"
namespace Director {
@ -126,7 +126,7 @@ static const char *findtokstart(const char *start, const char *token) {
return ptr;
}
Common::String Lingo::codePreprocessor(const char *s, LingoArchive *archive, ScriptType type, uint16 id, bool simple) {
Common::String LingoCompiler::codePreprocessor(const char *s, LingoArchive *archive, ScriptType type, uint16 id, bool simple) {
Common::String res;
// We start from processing the continuation synbols
@ -228,7 +228,7 @@ Common::String Lingo::codePreprocessor(const char *s, LingoArchive *archive, Scr
}
debugC(2, kDebugParse | kDebugPreprocess, "line: %d '%s'", iflevel, line.c_str());
if (!defFound && (type == kMovieScript || type == kCastScript) && (_vm->getVersion() < 400 || _vm->getCurrentMovie()->_allowOutdatedLingo)) {
if (!defFound && (type == kMovieScript || type == kCastScript) && (g_director->getVersion() < 400 || g_director->getCurrentMovie()->_allowOutdatedLingo)) {
tok = nexttok(line.c_str());
if (tok.equals("macro") || tok.equals("factory") || tok.equals("on")) {
defFound = true;

View File

@ -38,6 +38,7 @@
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-gr.h"
#include "director/lingo/lingo-object.h"
@ -45,6 +46,15 @@ namespace Director {
Lingo *g_lingo;
int calcStringAlignment(const char *s) {
return calcCodeAlignment(strlen(s) + 1);
}
int calcCodeAlignment(int l) {
int instLen = sizeof(inst);
return (l + instLen - 1) / instLen;
}
Symbol::Symbol() {
name = nullptr;
type = VOIDSYM;
@ -146,26 +156,13 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
_currentScript = 0;
_currentScriptContext = nullptr;
_assemblyAST = nullptr;
_assemblyArchive = nullptr;
_currentAssembly = nullptr;
_assemblyContext = nullptr;
_currentChannelId = -1;
_globalCounter = 0;
_pc = 0;
_abort = false;
_indef = false;
_expectError = false;
_caughtError = false;
_linenumber = _colnumber = _bytenumber = 0;
_lines[0] = _lines[1] = _lines[2] = nullptr;
_hadError = false;
_inFactory = false;
_floatPrecision = 4;
_floatPrecisionFormat = "%.4f";
@ -181,6 +178,8 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
_windowList.type = ARRAY;
_windowList.u.farr = new DatumArray;
_compiler = new LingoCompiler;
initEventHandlerTypes();
initBuiltIns();
@ -266,122 +265,13 @@ void LingoArchive::addCode(const char *code, ScriptType type, uint16 id, const c
else
contextName = Common::String::format("%d", id);
ScriptContext *sc = g_lingo->compileLingo(code, this, type, id, contextName);
ScriptContext *sc = g_lingo->_compiler->compileLingo(code, this, type, id, contextName);
if (sc) {
scriptContexts[type][id] = sc;
*sc->_refCount += 1;
}
}
ScriptContext *Lingo::compileAnonymous(const char *code) {
debugC(1, kDebugCompile, "Compiling anonymous lingo\n"
"***********\n%s\n\n***********", code);
return compileLingo(code, nullptr, kNoneScript, 0, "[anonymous]", true);
}
ScriptContext *Lingo::compileLingo(const char *code, LingoArchive *archive, ScriptType type, uint16 id, const Common::String &scriptName, bool anonymous) {
_assemblyArchive = archive;
_assemblyAST = nullptr;
ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, archive, type, id);
_currentAssembly = new ScriptData;
_methodVars = new VarTypeHash;
_linenumber = _colnumber = 1;
_hadError = false;
if (!strncmp(code, "menu:", 5) || scumm_strcasestr(code, "\nmenu:")) {
debugC(1, kDebugCompile, "Parsing menu");
parseMenu(code);
return nullptr;
}
// Preprocess the code for ease of the parser
Common::String codeNorm = codePreprocessor(code, archive, type, id);
code = codeNorm.c_str();
// Parse the Lingo and build an AST
parse(code);
// Generate bytecode
if (_assemblyAST) {
_assemblyAST->compile();
}
// for D4 and above, there usually won't be any code left.
// all scoped methods will be defined and stored by the code parser
// however D3 and below allow scopeless functions!
// and these can show up in D4 when imported from other movies
if (!_currentAssembly->empty()) {
// end of script, add a c_procret so stack frames work as expected
code1(LC::c_procret);
code1(STOP);
if (debugChannelSet(3, kDebugCompile)) {
if (_currentAssembly->size() && !_hadError)
Common::hexdump((byte *)&_currentAssembly->front(), _currentAssembly->size() * sizeof(inst));
debugC(2, kDebugCompile, "<resulting code>");
uint pc = 0;
while (pc < _currentAssembly->size()) {
uint spc = pc;
Common::String instr = decodeInstruction(_assemblyArchive, _currentAssembly, pc, &pc);
debugC(2, kDebugCompile, "[%5d] %s", spc, instr.c_str());
}
debugC(2, kDebugCompile, "<end code>");
}
Symbol currentFunc;
currentFunc.type = HANDLER;
currentFunc.u.defn = _currentAssembly;
Common::String typeStr = Common::String(scriptType2str(type));
currentFunc.name = new Common::String("[" + typeStr + " " + _assemblyContext->getName() + "]");
currentFunc.ctx = _assemblyContext;
currentFunc.archive = archive;
currentFunc.anonymous = anonymous;
// arg names should be empty, but just in case
Common::Array<Common::String> *argNames = new Common::Array<Common::String>;
for (uint i = 0; i < _argstack.size(); i++) {
argNames->push_back(Common::String(_argstack[i]->c_str()));
}
Common::Array<Common::String> *varNames = new Common::Array<Common::String>;
for (Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>::iterator it = _methodVars->begin(); it != _methodVars->end(); ++it) {
if (it->_value == kVarLocal)
varNames->push_back(Common::String(it->_key));
}
if (debugChannelSet(1, kDebugCompile)) {
debug("Function vars");
debugN(" Args: ");
for (uint i = 0; i < argNames->size(); i++) {
debugN("%s, ", (*argNames)[i].c_str());
}
debugN("\n");
debugN(" Local vars: ");
for (uint i = 0; i < varNames->size(); i++) {
debugN("%s, ", (*varNames)[i].c_str());
}
debugN("\n");
}
currentFunc.argNames = argNames;
currentFunc.varNames = varNames;
_assemblyContext->_eventHandlers[kEventGeneric] = currentFunc;
}
delete _methodVars;
_methodVars = nullptr;
_currentAssembly = nullptr;
delete _assemblyAST;
_assemblyAST = nullptr;
_assemblyContext = nullptr;
_assemblyArchive = nullptr;
return mainContext;
}
void Lingo::printStack(const char *s, uint pc) {
Common::String stack(s);
@ -1101,10 +991,6 @@ int Datum::compareTo(Datum &d, bool ignoreCase) const {
}
}
void Lingo::parseMenu(const char *code) {
warning("STUB: parseMenu");
}
void Lingo::runTests() {
Common::File inFile;
Common::ArchiveMemberList fsList;
@ -1136,11 +1022,10 @@ void Lingo::runTests() {
debug(">> Compiling file %s of size %d, id: %d", fileList[i].c_str(), size, counter);
_hadError = false;
mainArchive->addCode(script, kTestScript, counter);
if (!debugChannelSet(-1, kDebugCompileOnly)) {
if (!_hadError)
if (!_compiler->_hadError)
executeScript(kTestScript, counter);
else
debug(">> Skipping execution");
@ -1182,6 +1067,16 @@ void Lingo::executePerFrameHook(int frame, int subframe) {
}
}
void Lingo::cleanLocalVars() {
// Clean up current scope local variables and clean up memory
debugC(3, kDebugLingoExec, "cleanLocalVars: have %d vars", _localvars->size());
g_lingo->_localvars->clear();
delete g_lingo->_localvars;
g_lingo->_localvars = nullptr;
}
void Lingo::printAllVars() {
debugN(" Local vars: ");
if (_localvars) {

View File

@ -50,11 +50,15 @@ class Cast;
class ScriptContext;
class DirectorEngine;
class Frame;
class LingoCompiler;
typedef void (*inst)(void);
#define STOP (inst)0
#define ENTITY_INDEX(t,id) ((t) * 100000 + (id))
int calcStringAlignment(const char *s);
int calcCodeAlignment(int l);
typedef Common::Array<inst> ScriptData;
struct FuncDesc {
@ -233,9 +237,6 @@ public:
void resetLingo();
ScriptContext *compileAnonymous(const char *code);
ScriptContext *compileLingo(const char *code, LingoArchive *archive, ScriptType type, uint16 id, const Common::String &scriptName, bool anonyomous = false);
ScriptContext *compileLingoV4(Common::SeekableReadStreamEndian &stream, LingoArchive *archive, const Common::String &archName, uint16 version);
void executeHandler(const Common::String &name);
void executeScript(ScriptType type, uint16 id);
void printStack(const char *s, uint pc);
@ -256,13 +257,6 @@ public:
void runTests();
// lingo-preprocessor.cpp
public:
Common::String codePreprocessor(const char *s, LingoArchive *archive, ScriptType type, uint16 id, bool simple = false);
// lingo-patcher.cpp
Common::String patchLingoCode(Common::String &line, LingoArchive *archive, ScriptType type, uint16 id, int linenumber);
// lingo-events.cpp
private:
void initEventHandlerTypes();
@ -287,14 +281,6 @@ public:
void printAllVars();
int calcStringAlignment(const char *s) {
return calcCodeAlignment(strlen(s) + 1);
}
int calcCodeAlignment(int l) {
int instLen = sizeof(inst);
return (l + instLen - 1) / instLen;
}
inst readInst() { return getInst(_pc++); }
inst getInst(uint pc) { return (*_currentScript)[pc]; }
int readInt() { return getInt(_pc++); }
@ -355,43 +341,9 @@ private:
Common::StringArray _entityNames;
Common::StringArray _fieldNames;
// compiler resources
public:
bool isInArgStack(Common::String *s);
void clearArgStack();
LingoCompiler *_compiler;
int code1(inst code) { _currentAssembly->push_back(code); return _currentAssembly->size() - 1; }
int code2(inst code_1, inst code_2) { int o = code1(code_1); code1(code_2); return o; }
int code3(inst code_1, inst code_2, inst code_3) { int o = code1(code_1); code1(code_2); code1(code_3); return o; }
int code4(inst code_1, inst code_2, inst code_3, inst code_4) { int o = code1(code_1); code1(code_2); code1(code_3); code1(code_4); return o; }
void codeArg(Common::String *s);
int codeCmd(Common::String *s, int numpar);
Symbol codeDefine(Common::String &s, int start, int nargs, int end = -1, bool removeCode = true);
void codeFactory(Common::String &s);
int codeFloat(double f);
int codeFunc(Common::String *s, int numpar);
int codeInt(int val);
void codeLabel(int label);
int codeString(const char *s);
void processIf(int toplabel, int endlabel);
void registerMethodVar(const Common::String &name, VarType type);
LingoArchive *_assemblyArchive;
ScriptContext *_assemblyContext;
Node *_assemblyAST;
ScriptData *_currentAssembly;
bool _indef;
uint _linenumber;
uint _colnumber;
uint _bytenumber;
const char *_lines[3];
bool _inFactory;
Common::Array<Common::String *> _argstack;
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVars;
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVarsStash;
public:
int _currentChannelId;
LingoArchive *_currentArchive;
ScriptContext *_currentScriptContext;
@ -408,8 +360,6 @@ public:
int _objectEntityId;
Common::Array<int> _labelstack;
SymbolHash _builtinCmds;
SymbolHash _builtinFuncs;
SymbolHash _builtinConsts;
@ -418,12 +368,6 @@ public:
Common::String _floatPrecisionFormat;
bool _hadError;
private:
int parse(const char *code);
void parseMenu(const char *code);
public:
void push(Datum d);
Datum pop(bool eval = true);