You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/compiler/generator.cpp

743 lines
18 KiB
C++

#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);
}
}
}