Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
18 kB · 742 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743#include "generator.hpp"
#include <algorithm>#include <cassert>#include <iterator>#include <stdexcept>
#include "literals.hpp"
namespace{ void opPushInt(Compiler::Generator::CodeContainer& code, int value) { code.push_back(Compiler::Generator::segment0(0, value)); }
void opFetchIntLiteral(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(4)); }
void opFetchFloatLiteral(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(5)); }
void opIntToFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(3)); }
void opFloatToInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(6)); }
void opStoreLocalShort(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(0)); }
void opStoreLocalLong(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(1)); }
void opStoreLocalFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(2)); }
void opNegateInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(7)); }
void opNegateFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(8)); }
void opAddInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(9)); }
void opAddFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(10)); }
void opSubInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(11)); }
void opSubFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(12)); }
void opMulInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(13)); }
void opMulFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(14)); }
void opDivInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(15)); }
void opDivFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(16)); }
void opIntToFloat1(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(17)); }
void opReturn(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(20)); }
void opMessageBox(Compiler::Generator::CodeContainer& code, int buttons) { code.push_back(Compiler::Generator::segment3(0, buttons)); }
void opReport(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(58)); }
void opFetchLocalShort(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(21)); }
void opFetchLocalLong(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(22)); }
void opFetchLocalFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(23)); }
void opJumpForward(Compiler::Generator::CodeContainer& code, int offset) { code.push_back(Compiler::Generator::segment0(1, offset)); }
void opJumpBackward(Compiler::Generator::CodeContainer& code, int offset) { code.push_back(Compiler::Generator::segment0(2, offset)); }
/* Currently unused void opSkipOnZero (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (24)); } */
void opSkipOnNonZero(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(25)); }
void opEqualInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(26)); }
void opNonEqualInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(27)); }
void opLessThanInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(28)); }
void opLessOrEqualInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(29)); }
void opGreaterThanInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(30)); }
void opGreaterOrEqualInt(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(31)); }
void opEqualFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(32)); }
void opNonEqualFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(33)); }
void opLessThanFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(34)); }
void opLessOrEqualFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(35)); }
void opGreaterThanFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(36)); }
void opGreaterOrEqualFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(37)); }
void opStoreGlobalShort(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(39)); }
void opStoreGlobalLong(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(40)); }
void opStoreGlobalFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(41)); }
void opFetchGlobalShort(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(42)); }
void opFetchGlobalLong(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(43)); }
void opFetchGlobalFloat(Compiler::Generator::CodeContainer& code) { code.push_back(Compiler::Generator::segment5(44)); }
void opStoreMemberShort(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 65 : 59)); }
void opStoreMemberLong(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 66 : 60)); }
void opStoreMemberFloat(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 67 : 61)); }
void opFetchMemberShort(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 68 : 62)); }
void opFetchMemberLong(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 69 : 63)); }
void opFetchMemberFloat(Compiler::Generator::CodeContainer& code, bool global) { code.push_back(Compiler::Generator::segment5(global ? 70 : 64)); }}
namespace Compiler::Generator{ void pushInt(CodeContainer& code, Literals& literals, int value) { int index = literals.addInteger(value); opPushInt(code, index); opFetchIntLiteral(code); }
void pushFloat(CodeContainer& code, Literals& literals, float value) { int index = literals.addFloat(value); opPushInt(code, index); opFetchFloatLiteral(code); }
void pushString(CodeContainer& code, Literals& literals, const std::string& value) { int index = literals.addString(value); opPushInt(code, index); }
void assignToLocal(CodeContainer& code, char localType, int localIndex, const CodeContainer& value, char valueType) { opPushInt(code, localIndex);
std::copy(value.begin(), value.end(), std::back_inserter(code));
if (localType != valueType) { if (localType == 'f' && valueType == 'l') { opIntToFloat(code); } else if ((localType == 'l' || localType == 's') && valueType == 'f') { opFloatToInt(code); } }
switch (localType) { case 'f':
opStoreLocalFloat(code); break;
case 's':
opStoreLocalShort(code); break;
case 'l':
opStoreLocalLong(code); break;
default:
assert(0); } }
void negate(CodeContainer& code, char valueType) { switch (valueType) { case 'l':
opNegateInt(code); break;
case 'f':
opNegateFloat(code); break;
default:
assert(0); } }
void add(CodeContainer& code, char valueType1, char valueType2) { if (valueType1 == 'l' && valueType2 == 'l') { opAddInt(code); } else { if (valueType1 == 'l') opIntToFloat1(code);
if (valueType2 == 'l') opIntToFloat(code);
opAddFloat(code); } }
void sub(CodeContainer& code, char valueType1, char valueType2) { if (valueType1 == 'l' && valueType2 == 'l') { opSubInt(code); } else { if (valueType1 == 'l') opIntToFloat1(code);
if (valueType2 == 'l') opIntToFloat(code);
opSubFloat(code); } }
void mul(CodeContainer& code, char valueType1, char valueType2) { if (valueType1 == 'l' && valueType2 == 'l') { opMulInt(code); } else { if (valueType1 == 'l') opIntToFloat1(code);
if (valueType2 == 'l') opIntToFloat(code);
opMulFloat(code); } }
void div(CodeContainer& code, char valueType1, char valueType2) { if (valueType1 == 'l' && valueType2 == 'l') { opDivInt(code); } else { if (valueType1 == 'l') opIntToFloat1(code);
if (valueType2 == 'l') opIntToFloat(code);
opDivFloat(code); } }
void convert(CodeContainer& code, char fromType, char toType) { if (fromType != toType) { if (fromType == 'f' && toType == 'l') opFloatToInt(code); else if (fromType == 'l' && toType == 'f') opIntToFloat(code); else throw std::logic_error("illegal type conversion"); } }
void exit(CodeContainer& code) { opReturn(code); }
void message(CodeContainer& code, Literals& literals, const std::string& message, int buttons) { assert(buttons >= 0);
if (buttons >= 256) throw std::runtime_error("A message box can't have more than 255 buttons");
int index = literals.addString(message);
opPushInt(code, index); opMessageBox(code, buttons); }
void report(CodeContainer& code, Literals& literals, const std::string& message) { int index = literals.addString(message);
opPushInt(code, index); opReport(code); }
void fetchLocal(CodeContainer& code, char localType, int localIndex) { opPushInt(code, localIndex);
switch (localType) { case 'f':
opFetchLocalFloat(code); break;
case 's':
opFetchLocalShort(code); break;
case 'l':
opFetchLocalLong(code); break;
default:
assert(0); } }
void jump(CodeContainer& code, int offset) { if (offset > 0) opJumpForward(code, offset); else if (offset < 0) opJumpBackward(code, -offset); else throw std::logic_error("infinite loop"); }
void jumpOnZero(CodeContainer& code, int offset) { opSkipOnNonZero(code);
if (offset < 0) --offset; // compensate for skip instruction
jump(code, offset); }
void compare(CodeContainer& code, char op, char valueType1, char valueType2) { if (valueType1 == 'l' && valueType2 == 'l') { switch (op) { case 'e': opEqualInt(code); break; case 'n': opNonEqualInt(code); break; case 'l': opLessThanInt(code); break; case 'L': opLessOrEqualInt(code); break; case 'g': opGreaterThanInt(code); break; case 'G': opGreaterOrEqualInt(code); break;
default:
assert(0); } } else { if (valueType1 == 'l') opIntToFloat1(code);
if (valueType2 == 'l') opIntToFloat(code);
switch (op) { case 'e': opEqualFloat(code); break; case 'n': opNonEqualFloat(code); break; case 'l': opLessThanFloat(code); break; case 'L': opLessOrEqualFloat(code); break; case 'g': opGreaterThanFloat(code); break; case 'G': opGreaterOrEqualFloat(code); break;
default:
assert(0); } } }
void assignToGlobal(CodeContainer& code, Literals& literals, char localType, const std::string& name, const CodeContainer& value, char valueType) { int index = literals.addString(name);
opPushInt(code, index);
std::copy(value.begin(), value.end(), std::back_inserter(code));
if (localType != valueType) { if (localType == 'f' && (valueType == 'l' || valueType == 's')) { opIntToFloat(code); } else if ((localType == 'l' || localType == 's') && valueType == 'f') { opFloatToInt(code); } }
switch (localType) { case 'f':
opStoreGlobalFloat(code); break;
case 's':
opStoreGlobalShort(code); break;
case 'l':
opStoreGlobalLong(code); break;
default:
assert(0); } }
void fetchGlobal(CodeContainer& code, Literals& literals, char localType, const std::string& name) { int index = literals.addString(name);
opPushInt(code, index);
switch (localType) { case 'f':
opFetchGlobalFloat(code); break;
case 's':
opFetchGlobalShort(code); break;
case 'l':
opFetchGlobalLong(code); break;
default:
assert(0); } }
void assignToMember(CodeContainer& code, Literals& literals, char localType, const std::string& name, const std::string& id, const CodeContainer& value, char valueType, bool global) { int index = literals.addString(name);
opPushInt(code, index);
index = literals.addString(id);
opPushInt(code, index);
std::copy(value.begin(), value.end(), std::back_inserter(code));
if (localType != valueType) { if (localType == 'f' && (valueType == 'l' || valueType == 's')) { opIntToFloat(code); } else if ((localType == 'l' || localType == 's') && valueType == 'f') { opFloatToInt(code); } }
switch (localType) { case 'f':
opStoreMemberFloat(code, global); break;
case 's':
opStoreMemberShort(code, global); break;
case 'l':
opStoreMemberLong(code, global); break;
default:
assert(0); } }
void fetchMember(CodeContainer& code, Literals& literals, char localType, const std::string& name, const std::string& id, bool global) { int index = literals.addString(name);
opPushInt(code, index);
index = literals.addString(id);
opPushInt(code, index);
switch (localType) { case 'f':
opFetchMemberFloat(code, global); break;
case 's':
opFetchMemberShort(code, global); break;
case 'l':
opFetchMemberLong(code, global); break;
default:
assert(0); } }}