Rez: Labels, $$CountOf, $$ArrayIndex

This commit is contained in:
Wolfgang Thaller 2014-10-08 00:41:40 +02:00
parent 523a68d3de
commit a02d56ba1c
9 changed files with 326 additions and 36 deletions

View File

@ -1,8 +1,9 @@
#include "Expression.h"
#include "ResourceCompiler.h"
#include <cassert>
#include <iostream>
int Expression::evaluateInt(Context *ctx)
int Expression::evaluateInt(ResourceCompiler *ctx)
{
throw TypeError();
}
@ -21,7 +22,7 @@ IntExpr::~IntExpr()
{
}
int IntExpr::evaluateInt(Context *ctx)
int IntExpr::evaluateInt(ResourceCompiler *ctx)
{
return val;
}
@ -41,7 +42,7 @@ BinaryExpr::~BinaryExpr()
{
}
int BinaryExpr::evaluateInt(Context *ctx)
int BinaryExpr::evaluateInt(ResourceCompiler *ctx)
{
switch(op)
{
@ -75,7 +76,7 @@ UnaryExpr::~UnaryExpr()
{
}
int UnaryExpr::evaluateInt(Context *ctx)
int UnaryExpr::evaluateInt(ResourceCompiler *ctx)
{
switch(op)
{
@ -85,3 +86,42 @@ int UnaryExpr::evaluateInt(Context *ctx)
return ~a->evaluateInt(ctx);
}
}
IdentifierExpr::IdentifierExpr(std::string id, bool isFunction)
: id(id), isFunction(isFunction)
{
}
void IdentifierExpr::addArgument(ExprPtr e)
{
arguments.push_back(e);
}
int IdentifierExpr::evaluateInt(ResourceCompiler *ctx)
{
if(isFunction)
{
if(id == "$$countof" || id == "$$arrayindex")
{
assert(arguments.size() == 1);
IdentifierExprPtr arr = std::dynamic_pointer_cast<IdentifierExpr>(arguments[0]);
assert(arr);
if(id == "$$countof")
return ctx->getArrayCount(arr->id);
else
return ctx->getArrayIndex(arr->id);
}
else
{
std::cout << id << std::endl;
assert(false);
}
}
else
{
ExprPtr val = ctx->lookupIdentifier(id);
assert(val);
return val->evaluateInt(ctx);
}
}

View File

@ -4,17 +4,14 @@
#include <memory>
#include <vector>
class Context
{
};
class ResourceCompiler;
class Expression;
class CompoundExpr;
class IdentifierExpr;
typedef std::shared_ptr<Expression> ExprPtr;
typedef std::shared_ptr<CompoundExpr> CompoundExprPtr;
typedef std::shared_ptr<IdentifierExpr> IdentifierExprPtr;
enum class BinaryOp
@ -34,7 +31,7 @@ class TypeError
class Expression
{
public:
virtual int evaluateInt(Context *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
virtual ~Expression();
};
@ -53,7 +50,7 @@ public:
IntExpr(int val) : val(val) {}
~IntExpr();
virtual int evaluateInt(Context *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
};
class CompoundExpr : public Expression
@ -76,7 +73,7 @@ public:
: op(op), a(a), b(b) {}
~BinaryExpr();
virtual int evaluateInt(Context *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
};
class UnaryExpr : public Expression
@ -88,9 +85,19 @@ public:
: op(op), a(a) {}
~UnaryExpr();
virtual int evaluateInt(Context *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
};
class IdentifierExpr : public Expression
{
std::string id;
std::vector<ExprPtr> arguments;
bool isFunction;
public:
IdentifierExpr(std::string id, bool isFunction = false);
void addArgument(ExprPtr e);
virtual int evaluateInt(ResourceCompiler *ctx);
};
#endif // EXPRESSION_H

View File

@ -1,11 +1,116 @@
#include "ResourceCompiler.h"
#include <iostream>
#include "ResourceDefinitions.h"
ResourceCompiler::ResourceCompiler()
ResourceCompiler::ResourceCompiler(TypeDefinitionPtr type, CompoundExprPtr body)
: typeDefinition(type), body(body), currentOffset(0), currentField(nullptr)
{
}
void ResourceCompiler::write(int nBits, int value)
{
std::cout << "[" << nBits << " bits] = " << std::hex << value << std::dec << std::endl;
currentOffset += nBits;
}
ExprPtr ResourceCompiler::lookupIdentifier(std::string name, const Subscripts &sub)
{
if(currentField)
{
if(ExprPtr val = currentField->lookupNamedValue(name))
return val;
}
auto p = labelValues.find(std::make_pair(name, sub));
if(p != labelValues.end())
return p->second;
return nullptr;
}
void ResourceCompiler::defineLabel(const std::string &name)
{
labelValues[std::make_pair(name,currentSubscripts)] = std::make_shared<IntExpr>(currentOffset);
}
void ResourceCompiler::compile()
{
std::cout << "(first pass)\n";
currentOffset = 0;
typeDefinition->compile(body, this, true);
std::cout << "(second pass)\n";
currentOffset = 0;
typeDefinition->compile(body, this, false);
std::cout << "(done)\n";
}
int ResourceCompiler::getArrayCount(const std::string &name)
{
Subscripts sub = currentSubscripts;
for(;;)
{
auto p = arrayCounts.find(std::make_pair(name, sub));
if(p != arrayCounts.end())
return p->second;
if(sub.empty())
return 0; /* ### */
sub.popSubscript();
}
}
int ResourceCompiler::getArrayIndex(const std::string &arrayName)
{
return curArrayIndices[arrayName];
}
void ResourceCompiler::beginArrayScope(std::string &arrayName, int index)
{
if(arrayName != "")
{
curArrayIndices[arrayName] = index;
int& count = arrayCounts[std::make_pair(arrayName, currentSubscripts)];
if(count < index)
count = index;
arrayCounts[std::make_pair(arrayName, Subscripts())] = count;
//std::cout << "count for " << arrayName << " is " << count << std::endl;
}
currentSubscripts.addSubscript(index);
}
Subscripts::Subscripts()
{
}
Subscripts::~Subscripts()
{
}
void Subscripts::addSubscript(int x)
{
subscripts.push_back(x);
}
void Subscripts::popSubscript()
{
subscripts.pop_back();
}
bool Subscripts::operator<(const Subscripts &other) const
{
if(subscripts.size() < other.subscripts.size())
return true;
if(other.subscripts.size() < subscripts.size())
return false;
for(int i = 0, n = subscripts.size(); i < n; i++)
{
if(subscripts[i] < other.subscripts[i])
return true;
else if(subscripts[i] > other.subscripts[i])
return false;
}
return false;
}

View File

@ -2,14 +2,69 @@
#define RESOURCECOMPILER_H
#include "Expression.h"
#include "ResourceDefinitions.h"
class ResourceCompiler : public Context
class Field;
class Subscripts
{
std::vector<int> subscripts;
public:
ResourceCompiler();
Subscripts();
~Subscripts();
void addSubscript(int x);
void popSubscript();
bool operator<(const Subscripts& other) const;
bool empty() const { return subscripts.empty(); }
};
class ResourceCompiler
{
TypeDefinitionPtr typeDefinition;
CompoundExprPtr body;
std::map<std::pair<std::string, Subscripts>, ExprPtr> labelValues;
std::map<std::pair<std::string, Subscripts>, int> arrayCounts;
std::map<std::string, int> curArrayIndices;
int currentOffset;
Field* currentField;
Subscripts currentSubscripts;
void beginArrayScope(std::string& arrayName, int index);
public:
ResourceCompiler(TypeDefinitionPtr type, CompoundExprPtr body);
void reserve(int nBits) { write(nBits, 0); }
void write(int nBits, int value);
ExprPtr lookupIdentifier(std::string name, const Subscripts& sub = Subscripts());
void defineLabel(const std::string& name);
void compile();
int getArrayCount(const std::string& arrayName);
int getArrayIndex(const std::string& arrayName);
class FieldScope
{
ResourceCompiler *compiler;
public:
FieldScope(ResourceCompiler* compiler, Field *field)
: compiler(compiler) { compiler->currentField = field; }
~FieldScope() { compiler->currentField = nullptr; }
};
class ArrayScope
{
ResourceCompiler *compiler;
public:
ArrayScope(ResourceCompiler* compiler, std::string& arrayName, int index)
: compiler(compiler) { compiler->beginArrayScope(arrayName, index); }
~ArrayScope() { compiler->currentSubscripts.popSubscript(); }
};
};
#endif // RESOURCECOMPILER_H

View File

@ -36,7 +36,7 @@ void FieldList::addField(FieldPtr field)
void FieldList::addLabel(std::string name)
{
// ### TODO
addField(std::make_shared<LabelField>(name));
}
void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
@ -57,6 +57,30 @@ void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
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;
@ -88,6 +112,7 @@ void SimpleField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass
int actualValue = 0;
if(!prePass)
{
ResourceCompiler::FieldScope scope(compiler, this);
if(value)
{
actualValue = value->evaluateInt(compiler);
@ -121,6 +146,7 @@ void ArrayField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
while(i < n)
{
++iterations;
ResourceCompiler::ArrayScope scope(compiler, name, iterations);
for(FieldPtr f : fields)
{
if(f->needsValue())
@ -133,9 +159,25 @@ void ArrayField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
}
}
if(arrayCount)
if(!prePass && arrayCount)
{
int expected = arrayCount->evaluateInt(compiler);
assert(expected == iterations);
}
}
LabelField::LabelField(std::string name)
: name(name)
{
}
bool LabelField::needsValue()
{
return false;
}
void LabelField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
compiler->defineLabel(name);
}

View File

@ -57,6 +57,8 @@ public:
virtual bool needsValue() { return true; }
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass) = 0;
virtual ExprPtr lookupNamedValue(std::string) { return nullptr; }
};
typedef std::shared_ptr<Field> FieldPtr;
@ -80,9 +82,11 @@ public:
ExprPtr value;
std::map<std::string, ExprPtr> namedValues;
ExprPtr lastNamedValue;
void addNamedValue(std::string n) {}
void addNamedValue(std::string n, ExprPtr val) {}
void addNamedValue(std::string n);
void addNamedValue(std::string n, ExprPtr val);
ExprPtr lookupNamedValue(std::string);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
@ -95,6 +99,19 @@ inline SimpleField::Attrs operator|(SimpleField::Attrs a, SimpleField::Attrs b)
return SimpleField::Attrs( int(a) | int(b) );
}
class LabelField : public Field
{
std::string name;
public:
LabelField(std::string name);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<LabelField> LabelFieldPtr;
class FieldList : public Field
{
protected:

View File

@ -293,27 +293,33 @@ expression7 : expression8 { $$ = $1; }
expression8 : INTLIT { $$ = std::make_shared<IntExpr>($1); }
| CHARLIT { $$ = std::make_shared<IntExpr>($1); }
| IDENTIFIER /* ### */
| IDENTIFIER "(" function_argument_list ")"
| IDENTIFIER "[" function_argument_list1 "]"
| IDENTIFIER { $$ = std::make_shared<IdentifierExpr>($1); }
| IDENTIFIER
{ world.functionCalls.push(std::make_shared<IdentifierExpr>($1,true)); }
"(" function_argument_list ")"
{ $$ = world.functionCalls.top(); world.functionCalls.pop(); }
| IDENTIFIER
{ world.functionCalls.push(std::make_shared<IdentifierExpr>($1,false)); }
"[" function_argument_list1 "]"
{ $$ = world.functionCalls.top(); world.functionCalls.pop(); }
| "(" expression ")" { $$ = $2; }
;
function_argument_list : %empty | function_argument_list1 ;
function_argument_list1 : expression | function_argument_list "," expression ;
function_argument_list1 : expression
{ world.functionCalls.top()->addArgument($expression); }
| function_argument_list "," expression
{ world.functionCalls.top()->addArgument($expression); }
;
resource : "resource" res_type "(" expression resource_attributes ")" "{" resource_body "}"
{
int id = $expression->evaluateInt(nullptr);
std::cout << "RESOURCE " << $2 << "(" << id << ")" << std::endl;
TypeDefinitionPtr type = world.getTypeDefinition($res_type, id);
ResourceCompiler compiler;
std::cout << "(first pass)\n";
type->compile($resource_body, &compiler, true);
std::cout << "(second pass)\n";
type->compile($resource_body, &compiler, false);
std::cout << "(done)\n";
ResourceCompiler compiler(type, $resource_body);
compiler.compile();
}
;

View File

@ -12,6 +12,7 @@ class RezWorld
std::map<TypeSpec, TypeDefinitionPtr> types;
std::stack<FieldListPtr> fieldLists;
std::stack<IdentifierExprPtr> functionCalls;
public:
RezWorld();
void addTypeDefinition(TypeSpec spec, TypeDefinitionPtr type);

View File

@ -3,9 +3,26 @@
*/
#include "/home/wolfgang/Projects/Retro68/CExamples/Sample.r"
//#include "/home/wolfgang/Projects/Retro68/CExamples/Sample.r"
type 'TEST' {
boolean itemUnlocked = false, // defined attributes bits...
itemLocked = true;
integer zero, one, two, answer = 42, missed;
longint;
//integer = (after - before) / 32;
integer = $$CountOf(foo);
before:
array foo {
integer = $$ArrayIndex(foo);
integer;
integer;
};
after:
;
};
resource 'TEST' (128) {
answer,
0x1234,
{ 1, 2; 3, 4; }
};