Retro68/Rez/ResourceDefinitions.cc

255 lines
4.9 KiB
C++
Raw Normal View History

2014-10-06 15:03:25 +00:00
#include "ResourceDefinitions.h"
#include <ostream>
#include <cassert>
2014-10-06 15:03:25 +00:00
#include "ResourceCompiler.h"
2014-10-06 15:03:25 +00:00
std::ostream &operator<<(std::ostream &out, ResType t)
{
char c1 = static_cast<char>((int)t >> 24);
char c2 = static_cast<char>((int)t >> 16);
char c3 = static_cast<char>((int)t >> 8);
char c4 = static_cast<char>((int)t);
out << "'" << c1 << c2 << c3 << c4 << "'";
return out;
}
std::ostream &operator<<(std::ostream &out, TypeSpec ts)
{
out << ts.getType();
if(ts.hasID())
out << " (" << ts.getID() << ")";
return out;
}
FieldList::~FieldList()
{
}
void FieldList::addField(FieldPtr field)
{
fields.push_back(field);
}
void FieldList::addLabel(std::string name)
{
2014-10-07 22:41:40 +00:00
addField(std::make_shared<LabelField>(name));
}
void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
int i = 0;
for(FieldPtr f : fields)
{
if(f->needsValue())
f->compile(compound->getItem(i++), compiler, prePass);
else
f->compile(nullptr, compiler, prePass);
}
}
2014-10-07 22:41:40 +00:00
void SimpleField::addNamedValue(std::string n)
{
if(lastNamedValue)
addNamedValue(n, std::make_shared<BinaryExpr>(
BinaryOp::PLUS, lastNamedValue, std::make_shared<IntExpr>(1)));
else
addNamedValue(n, std::make_shared<IntExpr>(0));
}
void SimpleField::addNamedValue(std::string n, ExprPtr val)
{
namedValues[n] = val;
lastNamedValue = val;
}
ExprPtr SimpleField::lookupNamedValue(std::string n)
{
auto p = namedValues.find(n);
if(p != namedValues.end())
return p->second;
else
return nullptr;
}
bool SimpleField::needsValue()
{
return !value;
}
void SimpleField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
2014-10-07 23:17:39 +00:00
switch(type)
{
case Type::bitstring:
case Type::boolean:
case Type::byte:
case Type::integer:
case Type::longint:
compileInt(expr, compiler, prePass);
break;
case Type::string:
case Type::wstring:
case Type::pstring:
case Type::char_:
compileString(expr, compiler, prePass);
break;
}
}
void SimpleField::compileString(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
std::string str;
{
ResourceCompiler::FieldScope scope(compiler, this);
str = (value ? value : expr)->evaluateString(compiler);
}
if(arrayCount || type == Type::char_)
{
int requestedSize = type == Type::char_ ? 1 : arrayCount->evaluateInt(compiler);
if(requestedSize < str.size())
str.erase(str.begin() + requestedSize, str.end());
else if(requestedSize > str.size())
str.insert(str.end(),requestedSize - str.size(), '\0');
}
int count = str.size();
if(type == Type::pstring)
{
if(count > 255)
{
str.erase(str.begin() + 255, str.end());
count = 255;
}
compiler->write(8, count);
}
else if(type == Type::wstring)
{
if(count > 65535)
{
str.erase(str.begin() + 65535, str.end());
count = 65535;
}
compiler->write(16, count);
}
for(char c : str)
compiler->write(8, c);
}
void SimpleField::compileInt(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
int bitSize = 0;
switch(type)
{
case Type::bitstring:
bitSize = arrayCount->evaluateInt(compiler);
break;
case Type::boolean:
bitSize = 1;
break;
case Type::byte:
bitSize = 8;
break;
case Type::integer:
bitSize = 16;
break;
case Type::longint:
bitSize = 32;
break;
}
int actualValue = 0;
if(!prePass)
{
2014-10-07 22:41:40 +00:00
ResourceCompiler::FieldScope scope(compiler, this);
2014-10-07 23:17:39 +00:00
actualValue = (value ? value : expr)->evaluateInt(compiler);
}
compiler->write(bitSize, actualValue);
}
2014-10-07 18:44:40 +00:00
ArrayField::ArrayField(std::string name, ExprPtr count)
: name(name), arrayCount(count)
{
}
void ArrayField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
int i = 0;
int n = compound->size();
int iterations = 0;
while(i < n)
{
++iterations;
2014-10-07 22:41:40 +00:00
ResourceCompiler::ArrayScope scope(compiler, name, iterations);
2014-10-07 18:44:40 +00:00
for(FieldPtr f : fields)
{
if(f->needsValue())
{
assert(i < n);
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
}
2014-10-07 22:41:40 +00:00
if(!prePass && arrayCount)
2014-10-07 18:44:40 +00:00
{
int expected = arrayCount->evaluateInt(compiler);
assert(expected == iterations);
}
}
2014-10-07 22:41:40 +00:00
LabelField::LabelField(std::string name)
: name(name)
{
}
bool LabelField::needsValue()
{
return false;
}
void LabelField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
compiler->defineLabel(name);
}
2014-10-07 23:17:17 +00:00
void SwitchField::addCase(const std::string name, FieldListPtr alternative)
{
cases[name] = alternative;
}
void SwitchField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CaseExprPtr caseExpr = std::dynamic_pointer_cast<CaseExpr>(expr);
assert(caseExpr);
FieldListPtr caseDefinition = cases[caseExpr->tag];
assert(caseDefinition);
caseDefinition->compile(caseExpr->expr, compiler, prePass);
}