aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorScott Percival2019-10-27 17:25:50 +0800
committerEugene Sandulenko2019-11-17 22:31:54 +0100
commitcd619768edc22f1a374cf1857a5eef7e6c384696 (patch)
treec9933e21ab9f46081201eed56d4681cfc63cf5a8 /engines
parent186ff9cbce3bb9ffa5dcf7dbee1f30e4437e1080 (diff)
downloadscummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.tar.gz
scummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.tar.bz2
scummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.zip
DIRECTOR: Flesh out bytecode interpreter
Diffstat (limited to 'engines')
-rw-r--r--engines/director/lingo/lingo-bytecode.cpp236
-rw-r--r--engines/director/lingo/lingo-code.cpp56
-rw-r--r--engines/director/lingo/lingo.cpp1
-rw-r--r--engines/director/lingo/lingo.h20
4 files changed, 280 insertions, 33 deletions
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index f19ebb7768..c04515ac07 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -25,45 +25,62 @@
namespace Director {
static struct LingoV4Bytecode {
- const char opcode;
+ const uint8 opcode;
const inst func;
+ const char *args;
} lingoV4[] = {
- { 0x03, Lingo::c_voidpush },
- { 0x04, Lingo::c_mul },
- { 0x05, Lingo::c_add },
- { 0x06, Lingo::c_sub },
- { 0x07, Lingo::c_div },
- { 0x08, Lingo::c_mod },
- { 0x09, Lingo::c_negate },
- { 0x0a, Lingo::c_ampersand },
- { 0x0b, Lingo::c_concat },
- { 0x0c, Lingo::c_lt },
- { 0x0d, Lingo::c_le },
- { 0x0e, Lingo::c_neq },
- { 0x0f, Lingo::c_eq },
- { 0x10, Lingo::c_gt },
- { 0x11, Lingo::c_ge },
- { 0x12, Lingo::c_and },
- { 0x13, Lingo::c_or },
- { 0x14, Lingo::c_not },
- { 0x15, Lingo::c_contains },
- { 0x16, Lingo::c_starts },
- { 0x17, Lingo::c_of },
- { 0x18, Lingo::c_hilite },
- { 0x19, Lingo::c_intersects },
- { 0x1a, Lingo::c_within },
- { 0x1b, Lingo::c_field },
- { 0x1c, Lingo::c_tell },
- { 0x1d, Lingo::c_telldone },
+ { 0x03, Lingo::c_voidpush, "" },
+ { 0x04, Lingo::c_mul, "" },
+ { 0x05, Lingo::c_add, "" },
+ { 0x06, Lingo::c_sub, "" },
+ { 0x07, Lingo::c_div, "" },
+ { 0x08, Lingo::c_mod, "" },
+ { 0x09, Lingo::c_negate, "" },
+ { 0x0a, Lingo::c_ampersand, "" },
+ { 0x0b, Lingo::c_concat, "" },
+ { 0x0c, Lingo::c_lt, "" },
+ { 0x0d, Lingo::c_le, "" },
+ { 0x0e, Lingo::c_neq, "" },
+ { 0x0f, Lingo::c_eq, "" },
+ { 0x10, Lingo::c_gt, "" },
+ { 0x11, Lingo::c_ge, "" },
+ { 0x12, Lingo::c_and, "" },
+ { 0x13, Lingo::c_or, "" },
+ { 0x14, Lingo::c_not, "" },
+ { 0x15, Lingo::c_contains, "" },
+ { 0x16, Lingo::c_starts, "" },
+ { 0x17, Lingo::c_of, "" },
+ { 0x18, Lingo::c_hilite, "" },
+ { 0x19, Lingo::c_intersects, "" },
+ { 0x1a, Lingo::c_within, "" },
+ { 0x1b, Lingo::c_field, "" },
+ { 0x1c, Lingo::c_tell, "" },
+ { 0x1d, Lingo::c_telldone, "" },
- { 0x41, Lingo::c_intpush },
- { 0, 0 }
+ { 0x41, Lingo::c_intpush, "b" },
+ { 0, 0, 0 }
};
+void Lingo::initBytecode() {
+ for (LingoV4Bytecode *op = lingoV4; op->opcode; op++) {
+ _lingoV4[op->opcode] = new Opcode( op->func, op->args );
+ }
+}
+
void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id) {
debugC(1, kDebugLingoCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id);
+ if (_scripts[type].contains(id)) {
+ delete _scripts[type][id];
+ }
+
+ _currentScript = new ScriptData;
+ _currentScriptType = type;
+ _scripts[type][id] = _currentScript;
+ _currentEntityId = id;
+
+ // read the Lscr header!
// unk1
for (uint32 i = 0; i < 0x10; i++) {
stream.readByte();
@@ -88,9 +105,164 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
uint16 unk6 = stream.readUint16();
stream.readUint16();
uint16 consts_base = stream.readUint16();
-
- // preload all the constants
+
+ // preload all the constants!
+ // these are stored as a reference table of 6 byte entries, followed by a storage area.
+
+ // copy the storage area first.
+ uint32 consts_store_offset = consts_offset+6*consts_count;
+ uint32 consts_store_size = stream.size()-consts_store_offset;
+ stream.seek(consts_store_offset);
+ byte *const_store = (byte *)malloc(consts_store_size);
+ stream.read(const_store, consts_store_size);
+
+ Common::Array<Datum> const_data;
+
+ // read each entry in the reference table.
stream.seek(consts_offset);
+ for (uint16 i=0; i<consts_count; i++) {
+ Datum constant;
+ uint16 const_type = stream.readUint16();
+ uint32 value = stream.readUint32();
+ switch (const_type) {
+ case 1: { // String type
+ constant.type = STRING;
+ constant.u.s = new Common::String();
+ if (value < consts_store_offset) {
+ warning("Constant string start offset is out of bounds!");
+ break;
+ }
+ uint32 pointer = value - consts_store_offset;
+ while (pointer < consts_store_size) {
+ if (const_store[pointer] == '\r') {
+ constant.u.s += '\n';
+ } else if (const_store[pointer] == '\0') {
+ break;
+ } else {
+ constant.u.s += const_store[pointer];
+ }
+ pointer += 1;
+ }
+ if (pointer == consts_store_size) {
+ warning("Constant string has no null terminator!");
+ break;
+ }
+ }
+ break;
+ case 4: // Integer type
+ constant.type = INT;
+ constant.u.i = (int)value;
+ break;
+ case 9: { // Float type
+ constant.type = FLOAT;
+ if (value < consts_store_offset) {
+ warning("Constant float start offset is out of bounds!");
+ break;
+ } else if (value+4 > consts_store_offset + consts_store_size) {
+ warning("Constant float end offset is out of bounds!");
+ break;
+ }
+ constant.u.f = *(float *)(const_store+value-consts_store_offset);
+ }
+ break;
+ default:
+ warning("Unknown constant type %d", type);
+ break;
+ }
+
+ const_data.push_back(constant);
+ }
+ free(const_store);
+
+ // parse each function!
+ // these are stored as a code storage area, followed by a reference table of 42 byte entries.
+
+ // copy the storage area first.
+ uint32 code_store_size = functions_offset - code_store_offset;
+ stream.seek(code_store_offset);
+ byte *code_store = (byte *)malloc(code_store_size);
+ stream.read(code_store, code_store_size);
+
+ // read each entry in the function table.
+ stream.seek(functions_offset);
+ for (uint16 i=0; i<functions_count; i++) {
+ stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ uint16 arg_count = stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ uint16 var_count = stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ uint16 name_index = stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ uint16 length = stream.readUint16();
+ stream.readUint16();
+ uint16 start_offset = stream.readUint16();
+ stream.readUint16();
+ stream.readUint16();
+ uint16 end_offset = stream.readUint16();
+
+ if (start_offset < code_store_offset) {
+ warning("Function %d start offset is out of bounds!", i);
+ continue;
+ } else if (end_offset >= code_store_offset+code_store_size) {
+ warning("Function %d end offset is out of bounds!", i);
+ continue;
+ }
+
+ uint32 pointer = start_offset-code_store_offset;
+ Common::Array<uint32> offset_list;
+ while (pointer < end_offset-code_store_offset) {
+ uint8 opcode = code_store[pointer];
+
+ pointer += 1;
+ if (_lingoV4.contains(opcode)) {
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(_lingoV4[opcode]->func);
+
+ } else {
+ // unimplemented instruction
+ inst op_value = 0;
+ WRITE_UINT32(&op_value, opcode);
+
+ if (opcode < 0x40) {
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(Lingo::c_nop);
+ _currentScript->push_back(op_value);
+ } else if (opcode < 0x80) {
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(Lingo::c_nop1);
+ _currentScript->push_back(op_value);
+ inst arg1 = 0;
+ WRITE_UINT32(&arg1, code_store[pointer]);
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(arg1);
+ pointer += 1;
+ } else {
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(Lingo::c_nop2);
+ _currentScript->push_back(op_value);
+ inst arg1 = 0;
+ WRITE_UINT32(&arg1, code_store[pointer]);
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(arg1);
+ inst arg2 = 0;
+ WRITE_UINT32(&arg2, code_store[pointer+1]);
+ offset_list.push_back(_currentScript->size());
+ _currentScript->push_back(arg2);
+ pointer += 2;
+ }
+ }
+ }
+
+ }
+
}
}
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 85b50cd8ea..14f08719a9 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -57,7 +57,8 @@ static struct FuncDescr {
} funcDescr[] = {
{ 0, "STOP", "" },
{ Lingo::c_xpop, "c_xpop", "" },
- { Lingo::c_arraypush, "c_arraypush", "i" },
+ { Lingo::c_argspush, "c_argspush", "i" },
+ { Lingo::c_arraypush, "c_arraypush", "i" },
{ Lingo::c_printtop, "c_printtop", "" },
{ Lingo::c_intpush, "c_intpush", "i" },
{ Lingo::c_voidpush, "c_voidpush", "" },
@@ -125,6 +126,11 @@ static struct FuncDescr {
{ Lingo::c_instance, "c_instance", "s" },
{ Lingo::c_open, "c_open", "" },
{ Lingo::c_hilite, "c_hilite", "" },
+ { Lingo::c_jump, "c_jump", "" },
+ { Lingo::c_jumpif, "c_jumpif", "" },
+ { Lingo::c_nop, "c_nop", "i" },
+ { Lingo::c_nop1, "c_nop1", "ii" },
+ { Lingo::c_nop2, "c_nop2", "iii" },
{ 0, 0, 0 }
};
@@ -244,6 +250,21 @@ void Lingo::c_symbolpush() {
g_lingo->push(Datum(new Common::String(s)));
}
+void Lingo::c_argspush() {
+ Datum d;
+ inst v = (*g_lingo->_currentScript)[g_lingo->_pc++];
+ int argsSize = READ_UINT32(&v);
+
+ warning("STUB: c_argspush()");
+
+ for (int i = 0; i < argsSize; i++)
+ g_lingo->pop();
+
+ d.u.i = argsSize;
+ d.type = INT;
+ g_lingo->push(d);
+}
+
void Lingo::c_arraypush() {
Datum d;
inst v = (*g_lingo->_currentScript)[g_lingo->_pc++];
@@ -1246,4 +1267,37 @@ void Lingo::c_hilite() {
cast_id.u.i);
}
+void Lingo::c_jump() {
+
+}
+
+void Lingo::c_jumpif() {
+
+}
+
+void Lingo::c_nop() {
+ int savepc = g_lingo->_pc;
+ uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]);
+ warning("STUB: c_nop: %d", opcode);
+ g_lingo->_pc += 1;
+}
+
+void Lingo::c_nop1() {
+ int savepc = g_lingo->_pc;
+ uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]);
+ uint arg1 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+1]);
+ warning("STUB: c_nop1: %d %d", opcode, arg1);
+ g_lingo->_pc += 2;
+}
+
+void Lingo::c_nop2() {
+ int savepc = g_lingo->_pc;
+ uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]);
+ uint arg1 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+1]);
+ uint arg2 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+2]);
+ warning("STUB: c_nop2: %d %d %d", opcode, arg1, arg2);
+ g_lingo->_pc += 3;
+}
+
+
}
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 77c0bbcb9d..8be3408ad1 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -73,6 +73,7 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
initBuiltIns();
initFuncs();
+ initBytecode();
initTheEntities();
warning("Lingo Inited");
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index e1a165796e..3227786666 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -89,6 +89,14 @@ struct FuncDesc {
typedef Common::HashMap<void *, FuncDesc *> FuncHash;
+struct Opcode {
+ inst func;
+ const char *proto;
+
+ Opcode(inst f, const char *p) { func = f; proto = p; }
+};
+typedef Common::HashMap<int, Opcode *> OpcodeHash;
+
struct Symbol { /* symbol table entry */
Common::String name;
int type;
@@ -170,6 +178,7 @@ public:
void initBuiltIns();
void initFuncs();
+ void initBytecode();
void initTheEntities();
void runTests();
@@ -207,6 +216,7 @@ public:
int code1(inst code) { _currentScript->push_back(code); return _currentScript->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; }
int codeString(const char *s);
void codeLabel(int label);
int codeInt(int val);
@@ -270,6 +280,7 @@ public:
static void c_stringpush();
static void c_symbolpush();
static void c_varpush();
+ static void c_argspush();
static void c_arraypush();
static void c_assign();
bool verify(Symbol *s);
@@ -317,6 +328,13 @@ public:
static void c_open();
static void c_hilite();
+ static void c_jump();
+ static void c_jumpif();
+
+ static void c_nop();
+ static void c_nop1();
+ static void c_nop2();
+
void printSTUBWithArglist(const char *funcname, int nargs, const char *prefix = "STUB:");
void convertVOIDtoString(int arg, int nargs);
void dropStack(int nargs);
@@ -563,6 +581,8 @@ private:
FuncHash _functions;
+ OpcodeHash _lingoV4;
+
uint _pc;
StackData _stack;