aboutsummaryrefslogtreecommitdiff
path: root/engines/director/lingo/lingo-bytecode.cpp
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/director/lingo/lingo-bytecode.cpp
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/director/lingo/lingo-bytecode.cpp')
-rw-r--r--engines/director/lingo/lingo-bytecode.cpp236
1 files changed, 204 insertions, 32 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;
+ }
+ }
+ }
+
+ }
+
}
}