diff --git a/src/libreallive/bytecode.cc b/src/libreallive/bytecode.cc index d8a8373e..937a957b 100644 --- a/src/libreallive/bytecode.cc +++ b/src/libreallive/bytecode.cc @@ -144,8 +144,8 @@ void PrintParameterString(std::ostream& oss, // Take the binary stuff and try to get usefull, printable values. const char* start = param.c_str(); try { - std::unique_ptr piece(GetData(start)); - oss << piece->GetDebugString(); + ExpressionPiece piece(GetData(start)); + oss << piece.GetDebugString(); } catch (libreallive::Error& e) { // Any error throw here is a parse error. @@ -364,7 +364,8 @@ void TextoutElement::RunOnMachine(RLMachine& machine) const { // ExpressionElement // ----------------------------------------------------------------------- -ExpressionElement::ExpressionElement(const char* src) { +ExpressionElement::ExpressionElement(const char* src) + : parsed_expression_(invalid_expression_piece_t()) { // Don't parse the expression, just isolate it. const char* end = src; end += NextToken(end); @@ -375,31 +376,32 @@ ExpressionElement::ExpressionElement(const char* src) { repr.assign(src, end); } -ExpressionElement::ExpressionElement(const long val) { +ExpressionElement::ExpressionElement(const long val) + : parsed_expression_(invalid_expression_piece_t()) { repr.resize(6, '$'); repr[1] = 0xff; insert_i32(repr, 2, val); } ExpressionElement::ExpressionElement(const ExpressionElement& rhs) - : parsed_expression_(nullptr) { + : parsed_expression_(rhs.parsed_expression_) { } ExpressionElement::~ExpressionElement() {} int ExpressionElement::GetValueOnly(RLMachine& machine) const { const char* location = repr.c_str(); - std::unique_ptr e(GetExpression(location)); - return e->GetIntegerValue(machine); + ExpressionPiece e(GetExpression(location)); + return e.GetIntegerValue(machine); } const ExpressionPiece& ExpressionElement::ParsedExpression() const { - if (parsed_expression_.get() == 0) { + if (!parsed_expression_.is_valid()) { const char* location = repr.c_str(); parsed_expression_ = GetAssignment(location); } - return *parsed_expression_; + return parsed_expression_; } void ExpressionElement::PrintSourceRepresentation(std::ostream& oss) const { @@ -435,8 +437,7 @@ bool CommandElement::AreParametersParsed() const { } void CommandElement::SetParsedParameters( - ExpressionPiecesVector& parsedParameters) const { - parsed_parameters_.clear(); + ExpressionPiecesVector parsedParameters) const { parsed_parameters_ = std::move(parsedParameters); } @@ -619,8 +620,8 @@ std::string FunctionElement::GetSerializedCommand(RLMachine& machine) const { rv.push_back('('); for (string const& param : params) { const char* data = param.c_str(); - std::unique_ptr expression(GetData(data)); - rv.append(expression->GetSerializedExpression(machine)); + ExpressionPiece expression(GetData(data)); + rv.append(expression.GetSerializedExpression(machine)); } rv.push_back(')'); } @@ -679,8 +680,8 @@ std::string SingleArgFunctionElement::GetSerializedCommand(RLMachine& machine) rv.push_back(command[i]); rv.push_back('('); const char* data = arg_.c_str(); - std::unique_ptr expression(GetData(data)); - rv.append(expression->GetSerializedExpression(machine)); + ExpressionPiece expression(GetData(data)); + rv.append(expression.GetSerializedExpression(machine)); rv.push_back(')'); return rv; } diff --git a/src/libreallive/bytecode.h b/src/libreallive/bytecode.h index 71fcd0ac..ea116784 100644 --- a/src/libreallive/bytecode.h +++ b/src/libreallive/bytecode.h @@ -212,7 +212,7 @@ class ExpressionElement : public BytecodeElement { // Storage for the parsed expression so we only have to calculate // it once (and so we can return it by const reference) - mutable std::unique_ptr parsed_expression_; + mutable ExpressionPiece parsed_expression_; }; // Command elements. @@ -236,7 +236,7 @@ class CommandElement : public BytecodeElement { bool AreParametersParsed() const; // Gets/Sets the cached parameters. - void SetParsedParameters(ExpressionPiecesVector& p) const; + void SetParsedParameters(ExpressionPiecesVector p) const; const ExpressionPiecesVector& GetParsedParameters() const; // Returns the number of parameters. @@ -259,7 +259,7 @@ class CommandElement : public BytecodeElement { static const int COMMAND_SIZE = 8; unsigned char command[COMMAND_SIZE]; - mutable std::vector > parsed_parameters_; + mutable std::vector parsed_parameters_; }; class SelectElement : public CommandElement { diff --git a/src/libreallive/expression.cc b/src/libreallive/expression.cc index 844e6bdb..5430c614 100644 --- a/src/libreallive/expression.cc +++ b/src/libreallive/expression.cc @@ -42,7 +42,6 @@ #include #include "libreallive/defs.h" -#include "libreallive/expression_pieces.h" #include "libreallive/intmemref.h" #include "machine/reference.h" #include "machine/rlmachine.h" @@ -193,19 +192,19 @@ size_t NextData(const char* src) { // dissassembler.ml in RLDev, so really, while I coded this, Haeleth // really gets all the credit. -std::unique_ptr GetExpressionToken(const char*& src) { +ExpressionPiece GetExpressionToken(const char*& src) { if (src[0] == 0xff) { src++; int value = read_i32(src); src += 4; - return std::unique_ptr(new IntegerConstant(value)); + return ExpressionPiece::IntConstant(value); } else if (src[0] == 0xc8) { src++; - return std::unique_ptr(new StoreRegisterExpressionPiece()); + return ExpressionPiece::StoreRegister(); } else if ((src[0] != 0xc8 && src[0] != 0xff) && src[1] == '[') { int type = src[0]; src += 2; - std::unique_ptr location = GetExpression(src); + ExpressionPiece location = GetExpression(src); if (src[0] != ']') { std::ostringstream ss; @@ -215,8 +214,7 @@ std::unique_ptr GetExpressionToken(const char*& src) { } src++; - return std::unique_ptr( - new MemoryReference(type, std::move(location))); + return ExpressionPiece::MemoryReference(type, std::move(location)); } else if (src[0] == 0) { throw Error("Unexpected end of buffer in GetExpressionToken"); } else { @@ -227,7 +225,7 @@ std::unique_ptr GetExpressionToken(const char*& src) { } } -std::unique_ptr GetExpressionTerm(const char*& src) { +ExpressionPiece GetExpressionTerm(const char*& src) { if (src[0] == '$') { src++; return GetExpressionToken(src); @@ -237,11 +235,10 @@ std::unique_ptr GetExpressionTerm(const char*& src) { } else if (src[0] == '\\' && src[1] == 0x01) { // Uniary - src += 2; - return std::unique_ptr( - new UniaryExpressionOperator(0x01, GetExpressionTerm(src))); + return ExpressionPiece::UniaryExpression(0x01, GetExpressionTerm(src)); } else if (src[0] == '(') { src++; - std::unique_ptr p = GetExpressionBoolean(src); + ExpressionPiece p = GetExpressionBoolean(src); if (src[0] != ')') { std::ostringstream ss; ss << "Unexpected character '" << src[0] << "' in GetExpressionTerm" @@ -260,121 +257,121 @@ std::unique_ptr GetExpressionTerm(const char*& src) { } } -static std::unique_ptr GetExpressionArithmaticLoopHiPrec( +static ExpressionPiece GetExpressionArithmaticLoopHiPrec( const char*& src, - std::unique_ptr tok) { + ExpressionPiece tok) { if (src[0] == '\\' && src[1] >= 0x02 && src[1] <= 0x09) { char op = src[1]; // Advance past this operator src += 2; - std::unique_ptr newPiece( - new BinaryExpressionOperator(op, std::move(tok), GetExpressionTerm(src))); - return GetExpressionArithmaticLoopHiPrec(src, std::move(newPiece)); + ExpressionPiece new_piece = ExpressionPiece::BinaryExpression( + op, std::move(tok), GetExpressionTerm(src)); + return GetExpressionArithmaticLoopHiPrec(src, std::move(new_piece)); } else { // We don't consume anything and just return our input token. return tok; } } -static std::unique_ptr GetExpressionArithmaticLoop( +static ExpressionPiece GetExpressionArithmaticLoop( const char*& src, - std::unique_ptr tok) { + ExpressionPiece tok) { if (src[0] == '\\' && (src[1] == 0x00 || src[1] == 0x01)) { char op = src[1]; src += 2; - std::unique_ptr other = GetExpressionTerm(src); - std::unique_ptr rhs = + ExpressionPiece other = GetExpressionTerm(src); + ExpressionPiece rhs = GetExpressionArithmaticLoopHiPrec(src, std::move(other)); - std::unique_ptr newPiece( - new BinaryExpressionOperator(op, std::move(tok), std::move(rhs))); - return GetExpressionArithmaticLoop(src, std::move(newPiece)); + ExpressionPiece new_piece = + ExpressionPiece::BinaryExpression(op, std::move(tok), std::move(rhs)); + return GetExpressionArithmaticLoop(src, std::move(new_piece)); } else { return tok; } } -std::unique_ptr GetExpressionArithmatic(const char*& src) { +ExpressionPiece GetExpressionArithmatic(const char*& src) { return GetExpressionArithmaticLoop( src, GetExpressionArithmaticLoopHiPrec(src, GetExpressionTerm(src))); } -static std::unique_ptr GetExpressionConditionLoop( +static ExpressionPiece GetExpressionConditionLoop( const char*& src, - std::unique_ptr tok) { + ExpressionPiece tok) { if (src[0] == '\\' && (src[1] >= 0x28 && src[1] <= 0x2d)) { char op = src[1]; src += 2; - std::unique_ptr rhs = GetExpressionArithmatic(src); - std::unique_ptr newPiece( - new BinaryExpressionOperator(op, std::move(tok), std::move(rhs))); - return GetExpressionConditionLoop(src, std::move(newPiece)); + ExpressionPiece rhs = GetExpressionArithmatic(src); + ExpressionPiece new_piece = + ExpressionPiece::BinaryExpression(op, std::move(tok), std::move(rhs)); + return GetExpressionConditionLoop(src, std::move(new_piece)); } else { return tok; } } -std::unique_ptr GetExpressionCondition(const char*& src) { +ExpressionPiece GetExpressionCondition(const char*& src) { return GetExpressionConditionLoop(src, GetExpressionArithmatic(src)); } -static std::unique_ptr GetExpressionBooleanLoopAnd( +static ExpressionPiece GetExpressionBooleanLoopAnd( const char*& src, - std::unique_ptr tok) { + ExpressionPiece tok) { if (src[0] == '\\' && src[1] == '<') { src += 2; - std::unique_ptr rhs = GetExpressionCondition(src); + ExpressionPiece rhs = GetExpressionCondition(src); return GetExpressionBooleanLoopAnd( src, - std::unique_ptr(new BinaryExpressionOperator( - 0x3c, std::move(tok), std::move(rhs)))); + ExpressionPiece::BinaryExpression( + 0x3c, std::move(tok), std::move(rhs))); } else { return tok; } } -static std::unique_ptr GetExpressionBooleanLoopOr( +static ExpressionPiece GetExpressionBooleanLoopOr( const char*& src, - std::unique_ptr tok) { + ExpressionPiece tok) { if (src[0] == '\\' && src[1] == '=') { src += 2; - std::unique_ptr innerTerm = GetExpressionCondition(src); - std::unique_ptr rhs = + ExpressionPiece innerTerm = GetExpressionCondition(src); + ExpressionPiece rhs = GetExpressionBooleanLoopAnd(src, std::move(innerTerm)); return GetExpressionBooleanLoopOr( src, - std::unique_ptr(new BinaryExpressionOperator( - 0x3d, std::move(tok), std::move(rhs)))); + ExpressionPiece::BinaryExpression( + 0x3d, std::move(tok), std::move(rhs))); } else { return tok; } } -std::unique_ptr GetExpressionBoolean(const char*& src) { +ExpressionPiece GetExpressionBoolean(const char*& src) { return GetExpressionBooleanLoopOr( src, GetExpressionBooleanLoopAnd(src, GetExpressionCondition(src))); } -std::unique_ptr GetExpression(const char*& src) { +ExpressionPiece GetExpression(const char*& src) { return GetExpressionBoolean(src); } // Parses an expression of the form [dest] = [source expression]; -std::unique_ptr GetAssignment(const char*& src) { - std::unique_ptr itok(GetExpressionTerm(src)); +ExpressionPiece GetAssignment(const char*& src) { + ExpressionPiece itok(GetExpressionTerm(src)); int op = src[1]; src += 2; - std::unique_ptr etok(GetExpression(src)); + ExpressionPiece etok(GetExpression(src)); if (op >= 0x14 && op <= 0x24) { - return std::unique_ptr( - new AssignmentExpressionOperator(op, std::move(itok), std::move(etok))); + return ExpressionPiece::BinaryExpression( + op, std::move(itok), std::move(etok)); } else { throw Error("Undefined assignment in GetAssignment"); } } // Parses a string in the parameter list. -static std::unique_ptr GetString(const char*& src) { +static ExpressionPiece GetString(const char*& src) { // Get the length of this string in the bytecode: size_t length = NextString(src); @@ -388,14 +385,14 @@ static std::unique_ptr GetString(const char*& src) { // Increment the source by that many characters src += length; - return std::unique_ptr(new StringConstant(s)); + return ExpressionPiece::StrConstant(s); } // Parses a parameter in the parameter list. This is the only method // of all the get_*(const char*& src) functions that can parse // strings. It also deals with things like special and complex // parameters. -std::unique_ptr GetData(const char*& src) { +ExpressionPiece GetData(const char*& src) { if (*src == ',') { ++src; return GetData(src); @@ -410,7 +407,8 @@ std::unique_ptr GetData(const char*& src) { } else if (*src == 'a') { // TODO(erg): Cleanup below. const char* end = src; - std::unique_ptr cep; + + ExpressionPiece cep = ExpressionPiece::ComplexExpression(); if (*end++ == 'a') { int tag = *end++; @@ -422,42 +420,41 @@ std::unique_ptr GetData(const char*& src) { tag = (second << 16) | tag; } - cep.reset(new SpecialExpressionPiece(tag)); + cep = ExpressionPiece::SpecialExpression(tag); if (*end != '(') { // We have a single parameter in this special expression; - cep->AddContainedPiece(GetData(end)); - return std::unique_ptr(cep.release()); + cep.AddContainedPiece(GetData(end)); + return cep; } else { end++; } } else { - cep.reset(new ComplexExpressionPiece()); + cep = ExpressionPiece::ComplexExpression(); } while (*end != ')') { - cep->AddContainedPiece(GetData(end)); + cep.AddContainedPiece(GetData(end)); } - return std::unique_ptr(cep.release()); + return cep; } else { return GetExpression(src); } } -std::unique_ptr GetComplexParam(const char*& src) { +ExpressionPiece GetComplexParam(const char*& src) { if (*src == ',') { ++src; return GetData(src); } else if (*src == '(') { ++src; - std::unique_ptr cep(new ComplexExpressionPiece()); + ExpressionPiece cep = ExpressionPiece::ComplexExpression(); - while (*src != ')') { - cep->AddContainedPiece(GetData(src)); - } + while (*src != ')') + cep.AddContainedPiece(GetData(src)); - return std::unique_ptr(cep.release()); + return cep; } else { return GetExpression(src); } @@ -468,7 +465,7 @@ std::string EvaluatePRINT(RLMachine& machine, const std::string& in) { // rldev manual. if (boost::starts_with(in, "###PRINT(")) { const char* expression_start = in.c_str() + 9; - std::unique_ptr piece(GetExpression(expression_start)); + ExpressionPiece piece(GetExpression(expression_start)); if (*expression_start != ')') { std::ostringstream ss; @@ -477,7 +474,7 @@ std::string EvaluatePRINT(RLMachine& machine, const std::string& in) { throw Error(ss.str()); } - return piece->GetStringValue(machine); + return piece.GetStringValue(machine); } else { // Just a normal string we can ignore return in; @@ -536,357 +533,584 @@ std::string PrintableToParsableString(const std::string& src) { // ---------------------------------------------------------------------- -ExpressionPiece::~ExpressionPiece() {} -bool ExpressionPiece::IsMemoryReference() const { return false; } -bool ExpressionPiece::IsOperator() const { return false; } -bool ExpressionPiece::IsAssignment() const { return false; } -bool ExpressionPiece::IsComplexParameter() const { return false; } -bool ExpressionPiece::IsSpecialParameter() const { return false; } - -ExpressionValueType ExpressionPiece::GetExpressionValueType() const { - return ValueTypeInteger; +// OK: Here's the current things I need to do more: +// +// - I've written a move operator= (I've written the move ctor). +// - I need to write both the copy ctor and the copy operator=. +// - Lots of integration work still. + + +// static +ExpressionPiece ExpressionPiece::StoreRegister() { + ExpressionPiece piece; + piece.piece_type = TYPE_STORE_REGISTER; + return piece; +} + +// static +ExpressionPiece ExpressionPiece::IntConstant(const int constant) { + ExpressionPiece piece; + piece.piece_type = TYPE_INT_CONSTANT; + piece.int_constant = constant; + return piece; +} + +// static +ExpressionPiece ExpressionPiece::StrConstant(const std::string constant) { + ExpressionPiece piece; + piece.piece_type = TYPE_STRING_CONSTANT; + new (&piece.str_constant) std::string(constant); + return piece; +} + +// static +ExpressionPiece ExpressionPiece::MemoryReference(const int type, + ExpressionPiece location) { + ExpressionPiece piece; + piece.piece_type = TYPE_MEMORY_REFERENCE; + piece.mem_reference.type = type; + piece.mem_reference.location = new ExpressionPiece(std::move(location)); + return piece; +} + +// static +ExpressionPiece ExpressionPiece::UniaryExpression(const char operation, + ExpressionPiece operand) { + ExpressionPiece piece; + piece.piece_type = TYPE_UNIARY_EXPRESSION; + piece.uniary_expression.operation = operation; + piece.uniary_expression.operand = new ExpressionPiece(std::move(operand)); + return piece; +} + +// static +ExpressionPiece ExpressionPiece::BinaryExpression(const char operation, + ExpressionPiece lhs, + ExpressionPiece rhs) { + ExpressionPiece piece; + piece.piece_type = TYPE_BINARY_EXPRESSION; + piece.binary_expression.operation = operation; + piece.binary_expression.left_operand = new ExpressionPiece(std::move(lhs)); + piece.binary_expression.right_operand = new ExpressionPiece(std::move(rhs)); + return piece; +} + +// static +ExpressionPiece ExpressionPiece::ComplexExpression() { + ExpressionPiece piece; + piece.piece_type = TYPE_COMPLEX_EXPRESSION; + new (&piece.complex_expression) std::vector(); + return piece; +} + +// static +ExpressionPiece ExpressionPiece::SpecialExpression(const int tag) { + ExpressionPiece piece; + piece.piece_type = TYPE_SPECIAL_EXPRESSION; + piece.special_expression.overload_tag = tag; + new (&piece.special_expression.pieces) std::vector(); + return piece; +} + +ExpressionPiece::ExpressionPiece(invalid_expression_piece_t) + : piece_type(TYPE_INVALID) { +} + +ExpressionPiece::ExpressionPiece(const ExpressionPiece& rhs) + : piece_type(rhs.piece_type) { + switch (piece_type) { + case TYPE_STORE_REGISTER: + break; + case TYPE_INT_CONSTANT: + int_constant = rhs.int_constant; + break; + case TYPE_STRING_CONSTANT: + new (&str_constant) std::string(rhs.str_constant); + break; + case TYPE_MEMORY_REFERENCE: + mem_reference.type = rhs.mem_reference.type; + mem_reference.location = + new ExpressionPiece(*rhs.mem_reference.location); + break; + case TYPE_UNIARY_EXPRESSION: + uniary_expression.operation = rhs.uniary_expression.operation; + uniary_expression.operand = + new ExpressionPiece(*rhs.uniary_expression.operand); + break; + case TYPE_BINARY_EXPRESSION: + binary_expression.operation = rhs.binary_expression.operation; + binary_expression.left_operand = + new ExpressionPiece(*rhs.binary_expression.left_operand); + binary_expression.right_operand = + new ExpressionPiece(*rhs.binary_expression.right_operand); + break; + case TYPE_COMPLEX_EXPRESSION: + new (&complex_expression) std::vector( + rhs.complex_expression); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.overload_tag = rhs.special_expression.overload_tag; + new (&special_expression.pieces) std::vector( + rhs.special_expression.pieces); + break; + case TYPE_INVALID: + break; + } } -// A default implementation is provided since not everything will have assign -// semantics. -void ExpressionPiece::SetIntegerValue(RLMachine& machine, int rvalue) {} +ExpressionPiece::ExpressionPiece(ExpressionPiece&& rhs) + : piece_type(rhs.piece_type) { + switch (piece_type) { + case TYPE_STORE_REGISTER: + break; + case TYPE_INT_CONSTANT: + int_constant = rhs.int_constant; + break; + case TYPE_STRING_CONSTANT: + new (&str_constant) std::string(std::move(rhs.str_constant)); + break; + case TYPE_MEMORY_REFERENCE: + mem_reference.type = rhs.mem_reference.type; + mem_reference.location = rhs.mem_reference.location; + rhs.mem_reference.location = nullptr; + break; + case TYPE_UNIARY_EXPRESSION: + uniary_expression.operation = rhs.uniary_expression.operation; + uniary_expression.operand = rhs.uniary_expression.operand; + rhs.uniary_expression.operand = nullptr; + break; + case TYPE_BINARY_EXPRESSION: + binary_expression.operation = rhs.binary_expression.operation; + binary_expression.left_operand = rhs.binary_expression.left_operand; + binary_expression.right_operand = rhs.binary_expression.right_operand; + rhs.binary_expression.left_operand = nullptr; + rhs.binary_expression.right_operand = nullptr; + break; + case TYPE_COMPLEX_EXPRESSION: + new (&complex_expression) std::vector(std::move( + rhs.complex_expression)); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.overload_tag = rhs.special_expression.overload_tag; + new (&special_expression.pieces) std::vector(std::move( + rhs.special_expression.pieces)); + break; + case TYPE_INVALID: + break; + } -int ExpressionPiece::GetIntegerValue(RLMachine& machine) const { - throw libreallive::Error( - "ExpressionPiece::GetStringValue() invalid on this object"); + rhs.piece_type = TYPE_INVALID; } -void ExpressionPiece::SetStringValue(RLMachine& machine, - const std::string&) {} -const std::string& ExpressionPiece::GetStringValue(RLMachine& machine) const { - throw libreallive::Error( - "ExpressionPiece::GetStringValue() invalid on this object"); +ExpressionPiece::~ExpressionPiece() { + Invalidate(); } -IntReferenceIterator ExpressionPiece::GetIntegerReferenceIterator( - RLMachine& machine) const { - throw libreallive::Error( - "ExpressionPiece::GetIntegerReferenceIterator() invalid on this object"); -} +ExpressionPiece& ExpressionPiece::operator=(const ExpressionPiece& rhs) { + Invalidate(); -StringReferenceIterator ExpressionPiece::GetStringReferenceIterator( - RLMachine& machine) const { - throw libreallive::Error( - "ExpressionPiece::GetStringReferenceIterator() invalid on this object"); -} + piece_type = rhs.piece_type; + switch (piece_type) { + case TYPE_STORE_REGISTER: + break; + case TYPE_INT_CONSTANT: + int_constant = rhs.int_constant; + break; + case TYPE_STRING_CONSTANT: + new (&str_constant) std::string(rhs.str_constant); + break; + case TYPE_MEMORY_REFERENCE: + mem_reference.type = rhs.mem_reference.type; + mem_reference.location = + new ExpressionPiece(*rhs.mem_reference.location); + break; + case TYPE_UNIARY_EXPRESSION: + uniary_expression.operation = rhs.uniary_expression.operation; + uniary_expression.operand = + new ExpressionPiece(*rhs.uniary_expression.operand); + break; + case TYPE_BINARY_EXPRESSION: + binary_expression.operation = rhs.binary_expression.operation; + binary_expression.left_operand = + new ExpressionPiece(*rhs.binary_expression.left_operand); + binary_expression.right_operand = + new ExpressionPiece(*rhs.binary_expression.right_operand); + break; + case TYPE_COMPLEX_EXPRESSION: + new (&complex_expression) std::vector( + rhs.complex_expression); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.overload_tag = rhs.special_expression.overload_tag; + new (&special_expression.pieces) std::vector( + rhs.special_expression.pieces); + break; + case TYPE_INVALID: + break; + } -// ----------------------------------------------------------------------- + return *this; +} -StoreRegisterExpressionPiece::StoreRegisterExpressionPiece() {} +ExpressionPiece& ExpressionPiece::operator=(ExpressionPiece&& rhs) { + Invalidate(); -StoreRegisterExpressionPiece::~StoreRegisterExpressionPiece() {} + piece_type = rhs.piece_type; + switch (piece_type) { + case TYPE_STORE_REGISTER: + break; + case TYPE_INT_CONSTANT: + int_constant = rhs.int_constant; + break; + case TYPE_STRING_CONSTANT: + new (&str_constant) std::string(std::move(rhs.str_constant)); + break; + case TYPE_MEMORY_REFERENCE: + mem_reference.type = rhs.mem_reference.type; + mem_reference.location = rhs.mem_reference.location; + rhs.mem_reference.location = nullptr; + break; + case TYPE_UNIARY_EXPRESSION: + uniary_expression.operation = rhs.uniary_expression.operation; + uniary_expression.operand = rhs.uniary_expression.operand; + rhs.uniary_expression.operand = nullptr; + break; + case TYPE_BINARY_EXPRESSION: + binary_expression.operation = rhs.binary_expression.operation; + binary_expression.left_operand = rhs.binary_expression.left_operand; + binary_expression.right_operand = rhs.binary_expression.right_operand; + rhs.binary_expression.left_operand = nullptr; + rhs.binary_expression.right_operand = nullptr; + break; + case TYPE_COMPLEX_EXPRESSION: + new (&complex_expression) std::vector(std::move( + rhs.complex_expression)); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.overload_tag = rhs.special_expression.overload_tag; + new (&special_expression.pieces) std::vector(std::move( + rhs.special_expression.pieces)); + break; + case TYPE_INVALID: + break; + } -bool StoreRegisterExpressionPiece::IsMemoryReference() const { return true; } + rhs.piece_type = TYPE_INVALID; -void StoreRegisterExpressionPiece::SetIntegerValue(RLMachine& machine, - int rvalue) { - machine.set_store_register(rvalue); + return *this; } -int StoreRegisterExpressionPiece::GetIntegerValue(RLMachine& machine) const { - return machine.store_register(); +bool ExpressionPiece::IsMemoryReference() const { + return piece_type == TYPE_STORE_REGISTER || + piece_type == TYPE_MEMORY_REFERENCE; } -std::string StoreRegisterExpressionPiece::GetSerializedExpression(RLMachine& machine) - const { - return IntToBytecode(machine.store_register()); +bool ExpressionPiece::IsComplexParameter() const { + return piece_type == TYPE_COMPLEX_EXPRESSION; } -std::string StoreRegisterExpressionPiece::GetDebugString() const { - return ""; +bool ExpressionPiece::IsSpecialParameter() const { + return piece_type == TYPE_SPECIAL_EXPRESSION; } -IntReferenceIterator StoreRegisterExpressionPiece::GetIntegerReferenceIterator( - RLMachine& machine) const { - return IntReferenceIterator(machine.store_register_address()); +ExpressionValueType ExpressionPiece::GetExpressionValueType() const { + switch (piece_type) { + case TYPE_STRING_CONSTANT: + return ValueTypeString; + case TYPE_MEMORY_REFERENCE: + return is_string_location(mem_reference.type) ? + ValueTypeString : ValueTypeInteger; + default: + return ValueTypeInteger; + } } -std::unique_ptr StoreRegisterExpressionPiece::Clone() const { - return std::unique_ptr(new StoreRegisterExpressionPiece); +void ExpressionPiece::SetIntegerValue(RLMachine& machine, int rvalue) { + switch (piece_type) { + case TYPE_STORE_REGISTER: + machine.set_store_register(rvalue); + break; + case TYPE_MEMORY_REFERENCE: + machine.SetIntValue( + IntMemRef( + mem_reference.type, + mem_reference.location->GetIntegerValue(machine)), + rvalue); + break; + default: { + std::ostringstream ss; + ss << "ExpressionPiece::SetIntegerValue() invalid on object of type " + << piece_type; + throw Error(ss.str()); + } + } } -// ----------------------------------------------------------------------- - -// IntegerConstant -IntegerConstant::IntegerConstant(const int in) : constant(in) {} - -IntegerConstant::~IntegerConstant() {} - -int IntegerConstant::GetIntegerValue(RLMachine& machine) const { return constant; } - -std::string IntegerConstant::GetSerializedExpression(RLMachine& machine) const { - return IntToBytecode(constant); +int ExpressionPiece::GetIntegerValue(RLMachine& machine) const { + switch (piece_type) { + case TYPE_STORE_REGISTER: + return machine.store_register(); + case TYPE_INT_CONSTANT: + return int_constant; + case TYPE_MEMORY_REFERENCE: + return machine.GetIntValue(IntMemRef( + mem_reference.type, + mem_reference.location->GetIntegerValue(machine))); + case TYPE_UNIARY_EXPRESSION: + return PerformUniaryOperationOn( + uniary_expression.operand->GetIntegerValue(machine)); + case TYPE_BINARY_EXPRESSION: + if (binary_expression.operation >= 20 && + binary_expression.operation < 30) { + int value = PerformBinaryOperationOn( + binary_expression.left_operand->GetIntegerValue(machine), + binary_expression.right_operand->GetIntegerValue(machine)); + binary_expression.left_operand->SetIntegerValue(machine, value); + return value; + } else if (binary_expression.operation == 30) { + int value = binary_expression.right_operand->GetIntegerValue(machine); + binary_expression.left_operand->SetIntegerValue(machine, value); + return value; + } else { + return PerformBinaryOperationOn( + binary_expression.left_operand->GetIntegerValue(machine), + binary_expression.right_operand->GetIntegerValue(machine)); + } + default: { + std::ostringstream ss; + ss << "ExpressionPiece::GetIntegerValue() invalid on object of type " + << piece_type; + throw Error(ss.str()); + } + } } -std::string IntegerConstant::GetDebugString() const { - return std::to_string(constant); +void ExpressionPiece::SetStringValue(RLMachine& machine, + const std::string& rvalue) { + switch (piece_type) { + case TYPE_MEMORY_REFERENCE: + machine.SetStringValue(mem_reference.type, + mem_reference.location->GetIntegerValue(machine), + rvalue); + return; + default: + throw libreallive::Error( + "ExpressionPiece::SetStringValue() invalid on this object"); + } } -std::unique_ptr IntegerConstant::Clone() const { - return std::unique_ptr(new IntegerConstant(constant)); +const std::string& ExpressionPiece::GetStringValue(RLMachine& machine) const { + switch (piece_type) { + case TYPE_STRING_CONSTANT: + return str_constant; + case TYPE_MEMORY_REFERENCE: + return machine.GetStringValue(mem_reference.type, + mem_reference.location->GetIntegerValue( + machine)); + default: + throw libreallive::Error( + "ExpressionPiece::GetStringValue() invalid on this object"); + } } -// ----------------------------------------------------------------------- - -// StringConstant -StringConstant::StringConstant(const std::string& in) : constant(in) {} - -StringConstant::~StringConstant() {} +IntReferenceIterator ExpressionPiece::GetIntegerReferenceIterator( + RLMachine& machine) const { + switch (piece_type) { + case TYPE_STORE_REGISTER: + return IntReferenceIterator(machine.store_register_address()); + case TYPE_MEMORY_REFERENCE: + // Make sure that we are actually referencing an integer + if (is_string_location(mem_reference.type)) { + throw Error( + "Request to GetIntegerReferenceIterator() on a string reference!"); + } -ExpressionValueType StringConstant::GetExpressionValueType() const { - return ValueTypeString; + return IntReferenceIterator( + &machine.memory(), + mem_reference.type, + mem_reference.location->GetIntegerValue(machine)); + default: + throw libreallive::Error( + "ExpressionPiece::GetIntegerReferenceIterator() invalid on this object"); + } } -const std::string& StringConstant::GetStringValue(RLMachine& machine) const { - return constant; -} +StringReferenceIterator ExpressionPiece::GetStringReferenceIterator( + RLMachine& machine) const { + switch (piece_type) { + case TYPE_MEMORY_REFERENCE: + // Make sure that we are actually referencing an integer + if (!is_string_location(mem_reference.type)) { + throw Error( + "Request to GetStringReferenceIterator() on an integer reference!"); + } -std::string StringConstant::GetSerializedExpression(RLMachine& machine) const { - return string("\"") + constant + string("\""); + return StringReferenceIterator( + &machine.memory(), + mem_reference.type, + mem_reference.location->GetIntegerValue(machine)); + default: + throw libreallive::Error("ExpressionPiece::GetStringReferenceIterator()" + " invalid on this object"); + } } -std::string StringConstant::GetDebugString() const { - return string("\"") + constant + string("\""); +std::string ExpressionPiece::GetSerializedExpression(RLMachine& machine) const { + switch (piece_type) { + case TYPE_STORE_REGISTER: + return IntToBytecode(machine.store_register()); + case TYPE_INT_CONSTANT: + return IntToBytecode(int_constant); + case TYPE_STRING_CONSTANT: + return string("\"") + str_constant + string("\""); + case TYPE_MEMORY_REFERENCE: + if (is_string_location(mem_reference.type)) { + return string("\"") + GetStringValue(machine) + string("\""); + } else { + return IntToBytecode(GetIntegerValue(machine)); + } + case TYPE_UNIARY_EXPRESSION: + case TYPE_BINARY_EXPRESSION: + return IntToBytecode(GetIntegerValue(machine)); + case TYPE_COMPLEX_EXPRESSION: + return GetComplexSerializedExpression(machine); + case TYPE_SPECIAL_EXPRESSION: + return GetSpecialSerializedExpression(machine); + case TYPE_INVALID: + throw Error("Called GetSerializedExpression on an invalid piece."); + } } -std::unique_ptr StringConstant::Clone() const { - return std::unique_ptr(new StringConstant(constant)); +std::string ExpressionPiece::GetDebugString() const { + switch (piece_type) { + case TYPE_STORE_REGISTER: + return ""; + case TYPE_INT_CONSTANT: + return std::to_string(int_constant); + case TYPE_STRING_CONSTANT: + return string("\"") + str_constant + string("\""); + case TYPE_MEMORY_REFERENCE: + return GetMemoryDebugString(); + case TYPE_UNIARY_EXPRESSION: + return GetUniaryDebugString(); + case TYPE_BINARY_EXPRESSION: + return GetBinaryDebugString(); + case TYPE_COMPLEX_EXPRESSION: + return GetComplexDebugString(); + case TYPE_SPECIAL_EXPRESSION: + return GetSpecialDebugString(); + case TYPE_INVALID: + return ""; + } } -// ----------------------------------------------------------------------- - -// MemoryReference -MemoryReference::MemoryReference(int inType, - std::unique_ptr target) - : type(inType), location(std::move(target)) {} +// ----------------------------------------------------------------------------- -MemoryReference::~MemoryReference() {} +ExpressionPiece::ExpressionPiece() : piece_type(TYPE_INVALID) {} -bool MemoryReference::IsMemoryReference() const { return true; } +void ExpressionPiece::Invalidate() { + // Needed to get around a quirk of the language + using string_type = std::string; + using vec_type = std::vector; -ExpressionValueType MemoryReference::GetExpressionValueType() const { - if (is_string_location(type)) { - return ValueTypeString; - } else { - return ValueTypeInteger; + switch (piece_type) { + case TYPE_STORE_REGISTER: + case TYPE_INT_CONSTANT: + break; + case TYPE_STRING_CONSTANT: + str_constant.~string_type(); + break; + case TYPE_MEMORY_REFERENCE: + delete mem_reference.location; + break; + case TYPE_UNIARY_EXPRESSION: + delete uniary_expression.operand; + break; + case TYPE_BINARY_EXPRESSION: + delete binary_expression.left_operand; + delete binary_expression.right_operand; + break; + case TYPE_COMPLEX_EXPRESSION: + complex_expression.~vec_type(); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.pieces.~vec_type(); + break; + case TYPE_INVALID: + break; } } -void MemoryReference::SetIntegerValue(RLMachine& machine, int rvalue) { - return machine.SetIntValue(IntMemRef(type, location->GetIntegerValue(machine)), - rvalue); -} - -int MemoryReference::GetIntegerValue(RLMachine& machine) const { - return machine.GetIntValue(IntMemRef(type, location->GetIntegerValue(machine))); -} +// ----------------------------------------------------------------------------- -void MemoryReference::SetStringValue(RLMachine& machine, - const std::string& rvalue) { - return machine.SetStringValue(type, location->GetIntegerValue(machine), rvalue); +std::string ExpressionPiece::GetComplexSerializedExpression( + RLMachine& machine) const { + string s("("); + for (auto const& piece : complex_expression) { + s += "("; + s += piece.GetSerializedExpression(machine); + s += ")"; + } + s += ")"; + return s; } -const std::string& MemoryReference::GetStringValue(RLMachine& machine) const { - return machine.GetStringValue(type, location->GetIntegerValue(machine)); -} +std::string ExpressionPiece::GetSpecialSerializedExpression( + RLMachine& machine) const { + string s("a"); + s += char(special_expression.overload_tag); -std::string MemoryReference::GetSerializedExpression(RLMachine& machine) const { - if (is_string_location(type)) { - return string("\"") + GetStringValue(machine) + string("\""); - } else { - return IntToBytecode(GetIntegerValue(machine)); + if (special_expression.pieces.size() > 1) + s.append("("); + for (auto const& piece : special_expression.pieces) { + s += piece.GetSerializedExpression(machine); } + if (special_expression.pieces.size() > 1) + s.append(")"); + + return s; } -std::string MemoryReference::GetDebugString() const { +std::string ExpressionPiece::GetMemoryDebugString() const { std::ostringstream ret; - if (type == STRS_LOCATION) { + if (mem_reference.type == STRS_LOCATION) { ret << "strS["; - } else if (type == STRK_LOCATION) { + } else if (mem_reference.type == STRK_LOCATION) { ret << "strK["; - } else if (type == STRM_LOCATION) { + } else if (mem_reference.type == STRM_LOCATION) { ret << "strM["; - } else if (type == INTZ_LOCATION_IN_BYTECODE) { + } else if (mem_reference.type == INTZ_LOCATION_IN_BYTECODE) { ret << "intZ["; - } else if (type == INTL_LOCATION_IN_BYTECODE) { + } else if (mem_reference.type == INTL_LOCATION_IN_BYTECODE) { ret << "intL["; } else { - char bank = 'A' + (type % 26); + char bank = 'A' + (mem_reference.type % 26); ret << "int" << bank << "["; } - ret << location->GetDebugString(); + ret << mem_reference.location->GetDebugString(); ret << "]"; return ret.str(); } -IntReferenceIterator MemoryReference::GetIntegerReferenceIterator( - RLMachine& machine) const { - // Make sure that we are actually referencing an integer - if (is_string_location(type)) { - throw Error( - "Request to GetIntegerReferenceIterator() on a string reference!"); - } - - return IntReferenceIterator( - &machine.memory(), type, location->GetIntegerValue(machine)); -} - -StringReferenceIterator MemoryReference::GetStringReferenceIterator( - RLMachine& machine) const { - // Make sure that we are actually referencing an integer - if (!is_string_location(type)) { - throw Error( - "Request to GetStringReferenceIterator() on an integer reference!"); - } - - return StringReferenceIterator( - &machine.memory(), type, location->GetIntegerValue(machine)); -} - -std::unique_ptr MemoryReference::Clone() const { - return std::unique_ptr( - new MemoryReference(type, location->Clone())); -} - -// ---------------------------------------------------------------------- - -UniaryExpressionOperator::UniaryExpressionOperator( - char inOperation, - std::unique_ptr inOperand) - : operand(std::move(inOperand)), operation(inOperation) {} - -UniaryExpressionOperator::~UniaryExpressionOperator() {} - -int UniaryExpressionOperator::PerformOperationOn(int int_operand) const { - int result = int_operand; - switch (operation) { - case 0x01: - result = -int_operand; - break; - default: - break; - } - - return result; -} - -int UniaryExpressionOperator::GetIntegerValue(RLMachine& machine) const { - return PerformOperationOn(operand->GetIntegerValue(machine)); -} - -std::string UniaryExpressionOperator::GetSerializedExpression(RLMachine& machine) - const { - return IntToBytecode(GetIntegerValue(machine)); -} - -std::string UniaryExpressionOperator::GetDebugString() const { +std::string ExpressionPiece::GetUniaryDebugString() const { std::ostringstream str; - if (operation == 0x01) { + if (uniary_expression.operation == 0x01) { str << "-"; } - str << operand->GetDebugString(); + str << uniary_expression.operand->GetDebugString(); return str.str(); } -std::unique_ptr UniaryExpressionOperator::Clone() const { - return std::unique_ptr( - new UniaryExpressionOperator(operation, operand->Clone())); -} - -// ---------------------------------------------------------------------- - -BinaryExpressionOperator::BinaryExpressionOperator( - char inOperation, - std::unique_ptr lhs, - std::unique_ptr rhs) - : operation(inOperation), - leftOperand(std::move(lhs)), - rightOperand(std::move(rhs)) {} - -BinaryExpressionOperator::~BinaryExpressionOperator() {} - -// Stolen from xclannad -int BinaryExpressionOperator::PerformOperationOn(int lhs, int rhs) const { - switch (operation) { - case 0: - case 20: - return lhs + rhs; - case 1: - case 21: - return lhs - rhs; - case 2: - case 22: - return lhs * rhs; - case 3: - case 23: - return rhs != 0 ? lhs / rhs : lhs; - case 4: - case 24: - return rhs != 0 ? lhs % rhs : lhs; - case 5: - case 25: - return lhs & rhs; - case 6: - case 26: - return lhs | rhs; - case 7: - case 27: - return lhs ^ rhs; - case 8: - case 28: - return lhs << rhs; - case 9: - case 29: - return lhs >> rhs; - case 40: - return lhs == rhs; - case 41: - return lhs != rhs; - case 42: - return lhs <= rhs; - case 43: - return lhs < rhs; - case 44: - return lhs >= rhs; - case 45: - return lhs > rhs; - case 60: - return lhs && rhs; - case 61: - return lhs || rhs; - default: { - std::ostringstream ss; - ss << "Invalid operator " << (int)operation << " in expression!"; - throw Error(ss.str()); - } - } -} - -int BinaryExpressionOperator::GetIntegerValue(RLMachine& machine) const { - return PerformOperationOn(leftOperand->GetIntegerValue(machine), - rightOperand->GetIntegerValue(machine)); -} - -std::string BinaryExpressionOperator::GetSerializedExpression(RLMachine& machine) - const { - return IntToBytecode(GetIntegerValue(machine)); -} - -std::string BinaryExpressionOperator::GetDebugString() const { +std::string ExpressionPiece::GetBinaryDebugString() const { std::ostringstream str; - str << leftOperand->GetDebugString(); + str << binary_expression.left_operand->GetDebugString(); str << " "; - switch (operation) { + switch (binary_expression.operation) { case 0: case 20: str << "+"; @@ -956,146 +1180,161 @@ std::string BinaryExpressionOperator::GetDebugString() const { break; default: { std::ostringstream ss; - ss << "Invalid operator " << (int)operation << " in expression!"; + ss << "Invalid operator " + << static_cast(binary_expression.operation) + << " in expression!"; throw Error(ss.str()); } } - if (IsAssignment() && operation != 30) { + if (binary_expression.operation >= 0x14 && + binary_expression.operation != 30) { str << "="; } str << " "; - str << rightOperand->GetDebugString(); + str << binary_expression.right_operand->GetDebugString(); return str.str(); } -std::unique_ptr BinaryExpressionOperator::Clone() const { - return std::unique_ptr(new BinaryExpressionOperator( - operation, leftOperand->Clone(), rightOperand->Clone())); -} - -// ---------------------------------------------------------------------- - -AssignmentExpressionOperator::AssignmentExpressionOperator( - char op, - std::unique_ptr lhs, - std::unique_ptr rhs) - : BinaryExpressionOperator(op, std::move(lhs), std::move(rhs)) {} - -AssignmentExpressionOperator::~AssignmentExpressionOperator() {} - -bool AssignmentExpressionOperator::IsAssignment() const { return true; } - -int AssignmentExpressionOperator::GetIntegerValue(RLMachine& machine) const { - if (operation == 30) { - int value = rightOperand->GetIntegerValue(machine); - leftOperand->SetIntegerValue(machine, value); - return value; - } else { - int value = PerformOperationOn(leftOperand->GetIntegerValue(machine), - rightOperand->GetIntegerValue(machine)); - leftOperand->SetIntegerValue(machine, value); - return value; - } -} - -std::unique_ptr AssignmentExpressionOperator::Clone() const { - return std::unique_ptr(new AssignmentExpressionOperator( - operation, leftOperand->Clone(), rightOperand->Clone())); -} - -// ----------------------------------------------------------------------- - -ComplexExpressionPiece::ComplexExpressionPiece() {} - -ComplexExpressionPiece::~ComplexExpressionPiece() {} - -bool ComplexExpressionPiece::IsComplexParameter() const { return true; } - -void ComplexExpressionPiece::AddContainedPiece( - std::unique_ptr piece) { - contained_pieces_.push_back(std::move(piece)); -} - -std::string ComplexExpressionPiece::GetSerializedExpression(RLMachine& machine) const { - string s("("); - for (auto const& piece : contained_pieces_) { - s += "("; - s += piece->GetSerializedExpression(machine); - s += ")"; - } - s += ")"; - return s; -} - -std::string ComplexExpressionPiece::GetDebugString() const { +std::string ExpressionPiece::GetComplexDebugString() const { string s("("); - for (auto const& piece : contained_pieces_) { + for (auto const& piece : complex_expression) { s += "("; - s += piece->GetDebugString(); + s += piece.GetDebugString(); s += ")"; } s += ")"; return s; } -std::unique_ptr ComplexExpressionPiece::Clone() const { - ComplexExpressionPiece* cep = new ComplexExpressionPiece; - for (auto const& piece : contained_pieces_) - cep->contained_pieces_.push_back(piece->Clone()); - return std::unique_ptr(cep); -} - -// ----------------------------------------------------------------------- - -SpecialExpressionPiece::SpecialExpressionPiece(int tag) : overload_tag_(tag) {} - -SpecialExpressionPiece::~SpecialExpressionPiece() {} - -bool SpecialExpressionPiece::IsSpecialParameter() const { return true; } - -std::string SpecialExpressionPiece::GetSerializedExpression(RLMachine& machine) const { - string s("a"); - s += char(overload_tag_); - - if (contained_pieces_.size() > 1) - s.append("("); - for (auto const& piece : contained_pieces_) { - s += piece->GetSerializedExpression(machine); - } - if (contained_pieces_.size() > 1) - s.append(")"); - - return s; -} - -std::string SpecialExpressionPiece::GetDebugString() const { +std::string ExpressionPiece::GetSpecialDebugString() const { std::ostringstream oss; - oss << int(overload_tag_) << ":{"; + oss << int(special_expression.overload_tag) << ":{"; bool first = true; - for (auto const& piece : contained_pieces_) { + for (auto const& piece : special_expression.pieces) { if (!first) { oss << ", "; } else { first = false; } - oss << piece->GetDebugString(); + oss << piece.GetDebugString(); } oss << "}"; return oss.str(); } -std::unique_ptr SpecialExpressionPiece::Clone() const { - SpecialExpressionPiece* cep = new SpecialExpressionPiece(overload_tag_); - for (auto const& piece : contained_pieces_) - cep->contained_pieces_.push_back(piece->Clone()); - return std::unique_ptr(cep); +int ExpressionPiece::PerformUniaryOperationOn(int int_operand) const { + int result = int_operand; + switch (uniary_expression.operation) { + case 0x01: + result = -int_operand; + break; + default: + break; + } + + return result; +} + +// Stolen from xclannad +int ExpressionPiece::PerformBinaryOperationOn(int lhs, int rhs) const { + switch (binary_expression.operation) { + case 0: + case 20: + return lhs + rhs; + case 1: + case 21: + return lhs - rhs; + case 2: + case 22: + return lhs * rhs; + case 3: + case 23: + return rhs != 0 ? lhs / rhs : lhs; + case 4: + case 24: + return rhs != 0 ? lhs % rhs : lhs; + case 5: + case 25: + return lhs & rhs; + case 6: + case 26: + return lhs | rhs; + case 7: + case 27: + return lhs ^ rhs; + case 8: + case 28: + return lhs << rhs; + case 9: + case 29: + return lhs >> rhs; + case 40: + return lhs == rhs; + case 41: + return lhs != rhs; + case 42: + return lhs <= rhs; + case 43: + return lhs < rhs; + case 44: + return lhs >= rhs; + case 45: + return lhs > rhs; + case 60: + return lhs && rhs; + case 61: + return lhs || rhs; + default: { + std::ostringstream ss; + ss << "Invalid operator " + << static_cast(binary_expression.operation) + << " in expression!"; + throw Error(ss.str()); + } + } +} + +// ----------------------------------------------------------------------- + +void ExpressionPiece::AddContainedPiece(ExpressionPiece piece) { + switch (piece_type) { + case TYPE_COMPLEX_EXPRESSION: + complex_expression.emplace_back(piece); + break; + case TYPE_SPECIAL_EXPRESSION: + special_expression.pieces.emplace_back(piece); + break; + default: + throw Error("Request to AddContainedPiece() invalid!"); + } +} + +const std::vector& +ExpressionPiece::GetContainedPieces() const { + switch (piece_type) { + case TYPE_COMPLEX_EXPRESSION: + return complex_expression; + case TYPE_SPECIAL_EXPRESSION: + return special_expression.pieces; + default: + throw Error("Request to AddContainedPiece() invalid!"); + } +} + +int ExpressionPiece::GetOverloadTag() const { + switch (piece_type) { + case TYPE_SPECIAL_EXPRESSION: + return special_expression.overload_tag; + default: + throw Error("Request to GetOverloadTag() invalid!"); + } } } // namespace libreallive diff --git a/src/libreallive/expression.h b/src/libreallive/expression.h index af3f8b15..0b7eb3aa 100644 --- a/src/libreallive/expression.h +++ b/src/libreallive/expression.h @@ -53,15 +53,15 @@ size_t NextData(const char* src); // Parse expression functions class ExpressionPiece; -std::unique_ptr GetExpressionToken(const char*& src); -std::unique_ptr GetExpressionTerm(const char*& src); -std::unique_ptr GetExpressionArithmatic(const char*& src); -std::unique_ptr GetExpressionCondition(const char*& src); -std::unique_ptr GetExpressionBoolean(const char*& src); -std::unique_ptr GetExpression(const char*& src); -std::unique_ptr GetAssignment(const char*& src); -std::unique_ptr GetData(const char*& src); -std::unique_ptr GetComplexParam(const char*& src); +ExpressionPiece GetExpressionToken(const char*& src); +ExpressionPiece GetExpressionTerm(const char*& src); +ExpressionPiece GetExpressionArithmatic(const char*& src); +ExpressionPiece GetExpressionCondition(const char*& src); +ExpressionPiece GetExpressionBoolean(const char*& src); +ExpressionPiece GetExpression(const char*& src); +ExpressionPiece GetAssignment(const char*& src); +ExpressionPiece GetData(const char*& src); +ExpressionPiece GetComplexParam(const char*& src); std::string EvaluatePRINT(RLMachine& machine, const std::string& in); @@ -78,72 +78,161 @@ enum ExpressionValueType { ValueTypeString }; +enum ExpressionPieceType { + TYPE_STORE_REGISTER, + TYPE_INT_CONSTANT, + TYPE_STRING_CONSTANT, + TYPE_MEMORY_REFERENCE, + TYPE_UNIARY_EXPRESSION, + TYPE_BINARY_EXPRESSION, + TYPE_COMPLEX_EXPRESSION, + TYPE_SPECIAL_EXPRESSION, + TYPE_INVALID +}; + +struct invalid_expression_piece_t {}; + class ExpressionPiece { public: - virtual ~ExpressionPiece(); + static ExpressionPiece StoreRegister(); + static ExpressionPiece IntConstant(const int constant); + static ExpressionPiece StrConstant(const std::string constant); + static ExpressionPiece MemoryReference(const int type, + ExpressionPiece location); + static ExpressionPiece UniaryExpression(const char operation, + ExpressionPiece operand); + static ExpressionPiece BinaryExpression(const char operation, + ExpressionPiece lhs, + ExpressionPiece rhs); + static ExpressionPiece ComplexExpression(); + static ExpressionPiece SpecialExpression(const int tag); + + ExpressionPiece(invalid_expression_piece_t); + ExpressionPiece(const ExpressionPiece& rhs); + ExpressionPiece(ExpressionPiece&& rhs); + ~ExpressionPiece(); + + ExpressionPiece& operator=(const ExpressionPiece& rhs); + ExpressionPiece& operator=(ExpressionPiece&& rhs); + + bool is_valid() const { return piece_type != TYPE_INVALID; } // Capability method; returns false by default. Override when // ExpressionPiece subclass accesses a piece of memory. - virtual bool IsMemoryReference() const; - - // Capability method; returns false by default. Override when - // ExpressionPiece subclass is an operation on one or more other - // ExpressionPieces. - virtual bool IsOperator() const; - - // Used only to add a '=' in debug strings. - virtual bool IsAssignment() const; + bool IsMemoryReference() const; // Capability method; returns false by default. Override only in // classes that represent a complex parameter to the type system. // @see Complex_T - virtual bool IsComplexParameter() const; + bool IsComplexParameter() const; // Capability method; returns false by default. Override only in // classes that represent a special parameter to the type system. // @see Special_T - virtual bool IsSpecialParameter() const; + bool IsSpecialParameter() const; // Returns the value type of this expression (i.e. string or // integer) - virtual ExpressionValueType GetExpressionValueType() const; + ExpressionValueType GetExpressionValueType() const; // Assigns the value into the memory location represented by the // current expression. Not all ExpressionPieces can do this, so // there is a default implementation which does nothing. - virtual void SetIntegerValue(RLMachine& machine, int rvalue); + void SetIntegerValue(RLMachine& machine, int rvalue); // Returns the integer value of this expression; this can either be // a memory access or a calculation based on some subexpressions. - virtual int GetIntegerValue(RLMachine& machine) const; + int GetIntegerValue(RLMachine& machine) const; - virtual void SetStringValue(RLMachine& machine, - const std::string& rvalue); - virtual const std::string& GetStringValue(RLMachine& machine) const; + void SetStringValue(RLMachine& machine, const std::string& rvalue); + const std::string& GetStringValue(RLMachine& machine) const; + + // I used to be able to just static cast any ExpressionPiece to a + // MemoryReference if I wanted/needed a corresponding iterator. Haeleth's + // rlBabel library instead uses the store register as an argument to a + // function that takes a integer reference. So this needs to be here now. + IntReferenceIterator GetIntegerReferenceIterator(RLMachine& machine) const; + StringReferenceIterator GetStringReferenceIterator(RLMachine& machine) const; // A persistable version of this value. This method should return RealLive // bytecode equal to this ExpressionPiece with all references returned. - virtual std::string GetSerializedExpression(RLMachine& machine) const = 0; + std::string GetSerializedExpression(RLMachine& machine) const; // A printable representation of the expression itself. Used to dump our // parsing of the bytecode to the console. - virtual std::string GetDebugString() const = 0; + std::string GetDebugString() const; - // I used to be able to just static cast any ExpressionPiece to a - // MemoryReference if I wanted/needed a corresponding iterator. Haeleth's - // rlBabel library instead uses the store register as an argument to a - // function that takes a integer reference. So this needs to be here now. - virtual IntReferenceIterator GetIntegerReferenceIterator( - RLMachine& machine) const; - virtual StringReferenceIterator GetStringReferenceIterator( - RLMachine& machine) const; + // In the case of Complex and Special types, adds an expression piece to the + // list. + void AddContainedPiece(ExpressionPiece piece); + + const std::vector& GetContainedPieces() const; + + int GetOverloadTag() const; + + private: + ExpressionPiece(); + + // Frees all possible memory and sets |piece_type| to TYPE_INVALID. + void Invalidate(); + + // Implementations of some of the public interface where they aren't one + // liners. + std::string GetComplexSerializedExpression(RLMachine& machine) const; + std::string GetSpecialSerializedExpression(RLMachine& machine) const; + + std::string GetMemoryDebugString() const; + std::string GetUniaryDebugString() const; + std::string GetBinaryDebugString() const; + std::string GetComplexDebugString() const; + std::string GetSpecialDebugString() const; + + int PerformUniaryOperationOn(int int_operand) const; + int PerformBinaryOperationOn(int lhs, int rhs) const; + + ExpressionPieceType piece_type; + + union { + // TYPE_INT_CONSTANT + int int_constant; + + // TYPE_STRING_CONSTANT + std::string str_constant; + + // TODO: Make a TYPE_SIMPLE_MEMORY_REFERENCE which inlines integer + // constants. + + // TYPE_MEMORY_REFERENCE + struct { + int type; + ExpressionPiece* location; + } mem_reference; + + // TYPE_UNIARY_EXPRESSION + struct { + char operation; + ExpressionPiece* operand; + } uniary_expression; + + // TYPE_BINARY_EXPRESSION + struct { + char operation; + ExpressionPiece* left_operand; + ExpressionPiece* right_operand; + } binary_expression; + + // TYPE_COMPLEX_EXPRESSION + std::vector complex_expression; - // Builds a copy of this Expression. - virtual std::unique_ptr Clone() const = 0; + // TYPE_SPECIAL_EXPRESSION + struct { + int overload_tag; + std::vector pieces; + } special_expression; + }; }; -typedef std::vector > - ExpressionPiecesVector; +typedef std::vector ExpressionPiecesVector; } // namespace libreallive diff --git a/src/libreallive/expression_pieces.h b/src/libreallive/expression_pieces.h deleted file mode 100644 index f59e4646..00000000 --- a/src/libreallive/expression_pieces.h +++ /dev/null @@ -1,275 +0,0 @@ -// This file is part of libreallive, a dependency of RLVM. -// -// ----------------------------------------------------------------------- -// -// Copyright (c) 2006, 2007 Peter Jolly -// Copyright (c) 2007 Elliot Glaysher -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, copy, -// modify, merge, publish, distribute, sublicense, and/or sell copies -// of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// ----------------------------------------------------------------------- - -#ifndef SRC_LIBREALLIVE_EXPRESSION_PIECES_H_ -#define SRC_LIBREALLIVE_EXPRESSION_PIECES_H_ - -#include -#include - -#include "libreallive/expression.h" -#include "machine/reference.h" - -namespace libreallive { - -// Represents the store register in an Expression (both as an lvalue -// and rvlaue). -class StoreRegisterExpressionPiece : public ExpressionPiece { - public: - StoreRegisterExpressionPiece(); - virtual ~StoreRegisterExpressionPiece(); - - // Overridden from ExpressionPiece: - virtual bool IsMemoryReference() const final; - virtual void SetIntegerValue(RLMachine& machine, int rvalue) final; - virtual int GetIntegerValue(RLMachine& machine) const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - // Never seen in any commercial games, but needed for rlBabel support. - virtual IntReferenceIterator GetIntegerReferenceIterator( - RLMachine& machine) const final; - virtual std::unique_ptr Clone() const final; -}; - -// Represents a constant integer in an Expression. -class IntegerConstant : public ExpressionPiece { - public: - explicit IntegerConstant(const int in); - virtual ~IntegerConstant(); - - // Overridden from ExpressionPiece: - virtual int GetIntegerValue(RLMachine& machine) const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual std::unique_ptr Clone() const final; - - private: - // The value of this constant - int constant; -}; - -// ----------------------------------------------------------------------- - -class StringConstant : public ExpressionPiece { - public: - explicit StringConstant(const std::string& inStr); - virtual ~StringConstant(); - - // Overridden from ExpressionPiece: - virtual ExpressionValueType GetExpressionValueType() const final; - virtual const std::string& GetStringValue(RLMachine& machine) const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual std::unique_ptr Clone() const final; - - private: - std::string constant; -}; - -// ----------------------------------------------------------------------- - -// Reference to a piece of memory in an RLMachine. Noe that this -class MemoryReference : public ExpressionPiece { - public: - MemoryReference(int type, std::unique_ptr inLoc); - virtual ~MemoryReference(); - - // Overridden from ExpressionPiece: - virtual bool IsMemoryReference() const final; - virtual ExpressionValueType GetExpressionValueType() const final; - - virtual void SetIntegerValue(RLMachine& machine, int rvalue) final; - virtual int GetIntegerValue(RLMachine& machine) const final; - - virtual void SetStringValue(RLMachine& machine, - const std::string& rvalue) final; - virtual const std::string& GetStringValue(RLMachine& machine) const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual IntReferenceIterator GetIntegerReferenceIterator( - RLMachine& machine) const final; - virtual StringReferenceIterator GetStringReferenceIterator( - RLMachine& machine) const final; - virtual std::unique_ptr Clone() const final; - - private: - // The type of an memory reference refers to both the memory - // bank we're accessing, and how we're addressing it. - int type; - - // Arbitrarily complex expression to evaluate at runtime to - // determine the index of the location we want to address. - std::unique_ptr location; -}; - -// ---------------------------------------------------------------------- - -// Represents an operation on one ExpressionPiece, i.e. unary -// negative, et cetera. -class UniaryExpressionOperator : public ExpressionPiece { - public: - UniaryExpressionOperator(char inOperation, - std::unique_ptr inOperand); - virtual ~UniaryExpressionOperator(); - - // Overridden from ExpressionPiece: - virtual int GetIntegerValue(RLMachine& machine) const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual std::unique_ptr Clone() const final; - - private: - // Performs operation on the passed in parameter, and returns the - // value. - int PerformOperationOn(int x) const; - - // The sub-Expression to operate on - std::unique_ptr operand; - - // Which operation we are to perform. - char operation; -}; - -// ---------------------------------------------------------------------- - -class BinaryExpressionOperator : public ExpressionPiece { - public: - BinaryExpressionOperator(char inOperation, - std::unique_ptr lhs, - std::unique_ptr rhs); - virtual ~BinaryExpressionOperator(); - - // Overridden from ExpressionPiece: - virtual int GetIntegerValue(RLMachine& machine) const override; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual std::unique_ptr Clone() const override; - - protected: - // Performs operation on the two passed in operands. - int PerformOperationOn(int lhs, int rhs) const; - - // The operation to perform - char operation; - - // The left operand for this expression - std::unique_ptr leftOperand; - - // The right operand for this expression - std::unique_ptr rightOperand; -}; - -// ---------------------------------------------------------------------- - -// Operation that modies a given memory location, sucha as +=, -=, /=, -// et cetera. -class AssignmentExpressionOperator : public BinaryExpressionOperator { - public: - AssignmentExpressionOperator(char operation, - std::unique_ptr lhs, - std::unique_ptr rhs); - virtual ~AssignmentExpressionOperator(); - - virtual bool IsAssignment() const final; - - // For the entire assignment operator hiearchy, we use GetIntegerValue, - // since it acts as the execute. - virtual int GetIntegerValue(RLMachine& machine) const final; - - // Deliberately has no GetSerializedExpression() implementation; uses - // BinaryExpressionOperator's. - - virtual std::unique_ptr Clone() const final; -}; - - -// ----------------------------------------------------------------------- - -// Represents a Complex parameter to a function. This ExpressionPiece -// contains multiple ExpressionPieces. -class ComplexExpressionPiece : public ExpressionPiece { - public: - ComplexExpressionPiece(); - virtual ~ComplexExpressionPiece(); - - // Adds an ExpressionPiece to this complex expressionPiece. This - // instance of ComplexExpressionPiece takes ownership of any - // ExpressionPiece passed in this way. - void AddContainedPiece(std::unique_ptr piece); - - const std::vector>& contained_pieces() const - { return contained_pieces_; } - - // Overridden from ExpressionPiece: - virtual bool IsComplexParameter() const override; - virtual std::string GetSerializedExpression( - RLMachine& machine) const override; - virtual std::string GetDebugString() const override; - virtual std::unique_ptr Clone() const override; - - protected: - // Poiter owning container of all the ExpressionPieces we compose - std::vector> contained_pieces_; -}; - -// ----------------------------------------------------------------------- - -// Represents a Special parameter; a type that can be multiple types. -// -// In both Haeleth's code and my study of the bytecode, Special -// parameters seem to be types of Complex expressions. Even if they -// weren't, we need to maintain this relationships to make Special_T -// work. -class SpecialExpressionPiece : public ComplexExpressionPiece { - public: - explicit SpecialExpressionPiece(int tag); - virtual ~SpecialExpressionPiece(); - - int overload_tag() const { return overload_tag_; } - - // Overridden from ExpressionPiece: - virtual bool IsSpecialParameter() const final; - virtual std::string GetSerializedExpression( - RLMachine& machine) const final; - virtual std::string GetDebugString() const final; - virtual std::unique_ptr Clone() const final; - - private: - int overload_tag_; -}; - -} // namespace libreallive - -#endif // SRC_LIBREALLIVE_EXPRESSION_PIECES_H_ diff --git a/src/long_operations/select_long_operation.cc b/src/long_operations/select_long_operation.cc index 938b69bf..bf399a8d 100644 --- a/src/long_operations/select_long_operation.cc +++ b/src/long_operations/select_long_operation.cc @@ -80,9 +80,8 @@ SelectLongOperation::SelectLongOperation(RLMachine& machine, bool value = false; if (condition.condition != "") { const char* location = condition.condition.c_str(); - std::unique_ptr condition( - libreallive::GetExpression(location)); - value = !condition->GetIntegerValue(machine); + ExpressionPiece condition(libreallive::GetExpression(location)); + value = !condition.GetIntegerValue(machine); } o.shown = value; @@ -92,18 +91,17 @@ SelectLongOperation::SelectLongOperation(RLMachine& machine, bool enabled = false; if (condition.condition != "") { const char* location = condition.condition.c_str(); - std::unique_ptr condition( - libreallive::GetExpression(location)); - enabled = !condition->GetIntegerValue(machine); + ExpressionPiece condition(libreallive::GetExpression(location)); + enabled = !condition.GetIntegerValue(machine); } bool use_colour = false; int colour_index = 0; if (!enabled && condition.effect_argument != "") { const char* location = condition.effect_argument.c_str(); - std::unique_ptr effect_argument( + ExpressionPiece effect_argument( libreallive::GetExpression(location)); - colour_index = !effect_argument->GetIntegerValue(machine); + colour_index = !effect_argument.GetIntegerValue(machine); use_colour = true; } diff --git a/src/machine/general_operations.cc b/src/machine/general_operations.cc index 7817eaeb..4e1e2183 100644 --- a/src/machine/general_operations.cc +++ b/src/machine/general_operations.cc @@ -101,9 +101,7 @@ void MultiDispatch::operator()(RLMachine& machine, for (unsigned int i = 0; i < parameter_pieces.size(); ++i) { const libreallive::ExpressionPiecesVector& element = - dynamic_cast( - *parameter_pieces[i]).contained_pieces(); - + parameter_pieces[i].GetContainedPieces(); handler_->Dispatch(machine, element); } diff --git a/src/machine/rloperation.cc b/src/machine/rloperation.cc index d71173b9..74afa7a9 100644 --- a/src/machine/rloperation.cc +++ b/src/machine/rloperation.cc @@ -93,13 +93,13 @@ void RLOperation::DispatchFunction(RLMachine& machine, const libreallive::CommandElement& ff) { if (!ff.AreParametersParsed()) { std::vector unparsed = ff.GetUnparsedParameters(); - std::vector> output; + libreallive::ExpressionPiecesVector output; ParseParameters(unparsed, output); - ff.SetParsedParameters(output); + ff.SetParsedParameters(std::move(output)); } - const std::vector>& - parameter_pieces = ff.GetParsedParameters(); + const libreallive::ExpressionPiecesVector& parameter_pieces = + ff.GetParsedParameters(); // Now Dispatch based on these parameters. Dispatch(machine, parameter_pieces); @@ -114,23 +114,23 @@ void RLOperation::DispatchFunction(RLMachine& machine, // Implementation for IntConstant_T IntConstant_T::type IntConstant_T::getData( RLMachine& machine, - const std::vector>& p, + const libreallive::ExpressionPiecesVector& p, unsigned int& position) { - return p[position++]->GetIntegerValue(machine); + return p[position++].GetIntegerValue(machine); } // Was working to change the verify_type to parse_parameters. void IntConstant_T::ParseParameters( unsigned int& position, const std::vector& input, - std::vector>& output) { + libreallive::ExpressionPiecesVector& output) { const char* data = input.at(position).c_str(); - std::unique_ptr ep(libreallive::GetData(data)); + libreallive::ExpressionPiece ep(libreallive::GetData(data)); - if (ep->GetExpressionValueType() != libreallive::ValueTypeInteger) { + if (ep.GetExpressionValueType() != libreallive::ValueTypeInteger) { std::ostringstream oss; oss << "IntConstant_T parse error. Expected type string, but actually " - << "contained \"" << ep->GetDebugString() << "\""; + << "contained \"" << ep.GetDebugString() << "\""; throw rlvm::Exception(oss.str()); } @@ -140,23 +140,22 @@ void IntConstant_T::ParseParameters( IntReference_T::type IntReference_T::getData( RLMachine& machine, - const std::vector>& p, + const libreallive::ExpressionPiecesVector& p, unsigned int& position) { - return static_cast(*p[position++]) - .GetIntegerReferenceIterator(machine); + return p[position++].GetIntegerReferenceIterator(machine); } void IntReference_T::ParseParameters( unsigned int& position, const std::vector& input, - std::vector>& output) { + libreallive::ExpressionPiecesVector& output) { const char* data = input.at(position).c_str(); - std::unique_ptr ep(libreallive::GetData(data)); + libreallive::ExpressionPiece ep(libreallive::GetData(data)); - if (ep->GetExpressionValueType() != libreallive::ValueTypeInteger) { + if (ep.GetExpressionValueType() != libreallive::ValueTypeInteger) { std::ostringstream oss; oss << "IntReference_T parse error. Expected type string, but actually " - << "contained \"" << ep->GetDebugString() << "\""; + << "contained \"" << ep.GetDebugString() << "\""; throw rlvm::Exception(oss.str()); } @@ -166,7 +165,7 @@ void IntReference_T::ParseParameters( StrConstant_T::type StrConstant_T::getData( RLMachine& machine, - const std::vector>& p, + const libreallive::ExpressionPiecesVector& p, unsigned int& position) { // When I was trying to get P_BRIDE running in rlvm, I noticed that when // loading a game, I would often crash with invalid iterators in the LRUCache @@ -203,21 +202,21 @@ StrConstant_T::type StrConstant_T::getData( // So to fix this, we break the COW semantics here by forcing a copy. I'd // prefer to do this in RLMachine or Memory, but I can't because they return // references. - string tmp = p[position++]->GetStringValue(machine); + string tmp = p[position++].GetStringValue(machine); return string(tmp.data(), tmp.size()); } void StrConstant_T::ParseParameters( unsigned int& position, const std::vector& input, - std::vector>& output) { + libreallive::ExpressionPiecesVector& output) { const char* data = input.at(position).c_str(); - std::unique_ptr ep(libreallive::GetData(data)); + libreallive::ExpressionPiece ep(libreallive::GetData(data)); - if (ep->GetExpressionValueType() != libreallive::ValueTypeString) { + if (ep.GetExpressionValueType() != libreallive::ValueTypeString) { std::ostringstream oss; oss << "StrConstant_T parse error. Expected type string, but actually " - << "contained \"" << ep->GetDebugString() << "\""; + << "contained \"" << ep.GetDebugString() << "\""; throw rlvm::Exception(oss.str()); } @@ -227,23 +226,22 @@ void StrConstant_T::ParseParameters( StrReference_T::type StrReference_T::getData( RLMachine& machine, - const std::vector>& p, + const libreallive::ExpressionPiecesVector& p, unsigned int& position) { - return static_cast(*p[position++]) - .GetStringReferenceIterator(machine); + return p[position++].GetStringReferenceIterator(machine); } void StrReference_T::ParseParameters( unsigned int& position, const std::vector& input, - std::vector>& output) { + libreallive::ExpressionPiecesVector& output) { const char* data = input.at(position).c_str(); - std::unique_ptr ep(libreallive::GetData(data)); + libreallive::ExpressionPiece ep(libreallive::GetData(data)); - if (ep->GetExpressionValueType() != libreallive::ValueTypeString) { + if (ep.GetExpressionValueType() != libreallive::ValueTypeString) { std::ostringstream oss; oss << "StrReference_T parse error. Expected type string, but actually " - << "contained \"" << ep->GetDebugString() << "\""; + << "contained \"" << ep.GetDebugString() << "\""; throw rlvm::Exception(oss.str()); } @@ -273,7 +271,7 @@ void RLOp_SpecialCase::DispatchFunction(RLMachine& machine, std::vector unparsed = ff.GetUnparsedParameters(); libreallive::ExpressionPiecesVector output; ParseParameters(unparsed, output); - ff.SetParsedParameters(output); + ff.SetParsedParameters(std::move(output)); } // Pass this on to the implementation of this functor. diff --git a/src/machine/rloperation/complex_t.h b/src/machine/rloperation/complex_t.h index ec5b317f..7e0a1323 100644 --- a/src/machine/rloperation/complex_t.h +++ b/src/machine/rloperation/complex_t.h @@ -29,7 +29,6 @@ #include "libreallive/bytecode_fwd.h" #include "libreallive/expression.h" -#include "libreallive/expression_pieces.h" // Type definition that implements the complex parameter concept. // @@ -45,18 +44,16 @@ struct Complex_T { const libreallive::ExpressionPiecesVector& p, unsigned int& position) { unsigned int pos_in_expression = 0; - const libreallive::ComplexExpressionPiece& sp = - static_cast(*p[position++]); - return type { - Args::getData(machine, sp.contained_pieces(), pos_in_expression)... }; + const libreallive::ExpressionPiecesVector& pieces = + p[position++].GetContainedPieces(); + return type { Args::getData(machine, pieces, pos_in_expression)... }; } static void ParseParameters(unsigned int& position, const std::vector& input, libreallive::ExpressionPiecesVector& output) { const char* data = input.at(position).c_str(); - std::unique_ptr ep( - libreallive::GetComplexParam(data)); + libreallive::ExpressionPiece ep(libreallive::GetComplexParam(data)); output.push_back(std::move(ep)); position++; } diff --git a/src/machine/rloperation/default_value.h b/src/machine/rloperation/default_value.h index ea0bc63d..182ef498 100644 --- a/src/machine/rloperation/default_value.h +++ b/src/machine/rloperation/default_value.h @@ -26,7 +26,7 @@ #include #include -#include "libreallive/expression_pieces.h" +#include "libreallive/expression.h" template struct DefaultIntValue_T { @@ -50,7 +50,8 @@ struct DefaultIntValue_T { if (position < input.size()) { IntConstant_T::ParseParameters(position, input, output); } else { - output.emplace_back(new libreallive::IntegerConstant(DEFAULTVAL)); + output.emplace_back( + libreallive::ExpressionPiece::IntConstant(DEFAULTVAL)); position++; } } @@ -80,7 +81,8 @@ struct DefaultStrValue_T { if (position < input.size()) { StrConstant_T::ParseParameters(position, input, output); } else { - output.emplace_back(new libreallive::StringConstant(std::string())); + output.emplace_back( + libreallive::ExpressionPiece::StrConstant(std::string())); position++; } } diff --git a/src/machine/rloperation/references.h b/src/machine/rloperation/references.h index 652b5173..97bf7ee3 100644 --- a/src/machine/rloperation/references.h +++ b/src/machine/rloperation/references.h @@ -28,7 +28,6 @@ #include "machine/reference.h" #include "libreallive/expression.h" -#include "libreallive/expression_pieces.h" // Type definition for a reference into the RLMachine's memory, // referencing an integer value. diff --git a/src/machine/rloperation/rgb_colour_t.h b/src/machine/rloperation/rgb_colour_t.h index ec9bcad5..c5d542e9 100644 --- a/src/machine/rloperation/rgb_colour_t.h +++ b/src/machine/rloperation/rgb_colour_t.h @@ -87,7 +87,7 @@ struct RGBMaybeAColour_T { if (position < input.size()) { IntConstant_T::ParseParameters(position, input, output); } else { - output.emplace_back(new libreallive::IntegerConstant(255)); + output.emplace_back(libreallive::ExpressionPiece::IntConstant(255)); position++; } } diff --git a/src/machine/rloperation/special_t.h b/src/machine/rloperation/special_t.h index e6078a7d..5a9a4ab9 100644 --- a/src/machine/rloperation/special_t.h +++ b/src/machine/rloperation/special_t.h @@ -29,7 +29,6 @@ #include "libreallive/bytecode_fwd.h" #include "libreallive/expression.h" -#include "libreallive/expression_pieces.h" #include "utilities/exception.h" @@ -41,8 +40,8 @@ // This default mapper is used by most Special_Ts, and returns the tag as the // type. struct DefaultSpecialMapper { - static int GetTypeForTag(const libreallive::SpecialExpressionPiece& sp) { - return sp.overload_tag(); + static int GetTypeForTag(const libreallive::ExpressionPiece& sp) { + return sp.GetOverloadTag(); } }; @@ -84,14 +83,14 @@ struct Special_T { RLMachine& machine, const libreallive::ExpressionPiecesVector& p, unsigned int& position, - const libreallive::SpecialExpressionPiece& sp) { + const libreallive::ExpressionPiece& sp) { if (TYPE::is_complex) { return TYPE::getData(machine, p, position); } else { unsigned int contained_position = 0; position++; return TYPE::getData( - machine, sp.contained_pieces(), contained_position); + machine, sp.GetContainedPieces(), contained_position); } } @@ -106,10 +105,9 @@ struct Special_T { throw std::runtime_error(oss.str()); } - const libreallive::SpecialExpressionPiece& sp = - static_cast(*p[position]); + const libreallive::ExpressionPiece& sp = p[position]; - if (sp.contained_pieces().size() == 0) + if (sp.GetContainedPieces().size() == 0) throw rlvm::Exception("Empty special construct in Special_T"); Parameter par; @@ -145,7 +143,7 @@ struct Special_T { default: { std::ostringstream oss; oss << "Illegal overload in Special_T::getData(). Bytecode tag was " - << sp.overload_tag() << ", Mapped position was " << par.type; + << sp.GetOverloadTag() << ", Mapped position was " << par.type; throw rlvm::Exception(oss.str()); } } diff --git a/src/modules/module_jmp.cc b/src/modules/module_jmp.cc index 35845878..2d362eb4 100644 --- a/src/modules/module_jmp.cc +++ b/src/modules/module_jmp.cc @@ -58,7 +58,7 @@ namespace { // Finds which case should be used in the *_case functions. int EvaluateCase(RLMachine& machine, const CommandElement& goto_element) { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - int value = conditions[0]->GetIntegerValue(machine); + int value = conditions[0].GetIntegerValue(machine); // Walk linearly through the output cases, executing the first // match against value. @@ -82,9 +82,8 @@ int EvaluateCase(RLMachine& machine, const CommandElement& goto_element) { // Parse this expression, and goto the corresponding label if // it's equal to the value we're searching for const char* e = (const char*)caseUnparsed.c_str(); - std::unique_ptr output( - libreallive::GetExpression(e)); - if (output->GetIntegerValue(machine) == value) + libreallive::ExpressionPiece output(libreallive::GetExpression(e)); + if (output.GetIntegerValue(machine) == value) return i; } @@ -170,7 +169,7 @@ struct goto_if : public ParseGotoParametersAsExpressions { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - if (conditions[0]->GetIntegerValue(machine)) { + if (conditions[0].GetIntegerValue(machine)) { machine.GotoLocation(goto_element.GetPointer(0)); } else { machine.AdvanceInstructionPointer(); @@ -184,7 +183,7 @@ struct goto_unless : public ParseGotoParametersAsExpressions { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - if (!conditions[0]->GetIntegerValue(machine)) { + if (!conditions[0].GetIntegerValue(machine)) { machine.GotoLocation(goto_element.GetPointer(0)); } else { machine.AdvanceInstructionPointer(); @@ -202,7 +201,7 @@ struct goto_on : public ParseGotoParametersAsExpressions { void operator()(RLMachine& machine, const CommandElement& goto_element) { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - int value = conditions[0]->GetIntegerValue(machine); + int value = conditions[0].GetIntegerValue(machine); if (value >= 0 && value < int(goto_element.GetPointersCount())) { machine.GotoLocation(goto_element.GetPointer(value)); @@ -245,7 +244,7 @@ struct gosub_if : public ParseGotoParametersAsExpressions { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - if (conditions[0]->GetIntegerValue(machine)) { + if (conditions[0].GetIntegerValue(machine)) { machine.Gosub(goto_element.GetPointer(0)); } else { machine.AdvanceInstructionPointer(); @@ -262,7 +261,7 @@ struct gosub_unless : public ParseGotoParametersAsExpressions { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - if (!conditions[0]->GetIntegerValue(machine)) { + if (!conditions[0].GetIntegerValue(machine)) { machine.Gosub(goto_element.GetPointer(0)); } else { machine.AdvanceInstructionPointer(); @@ -280,7 +279,7 @@ struct gosub_on : public ParseGotoParametersAsExpressions { void operator()(RLMachine& machine, const CommandElement& goto_element) { const ExpressionPiecesVector& conditions = goto_element.GetParsedParameters(); - int value = conditions[0]->GetIntegerValue(machine); + int value = conditions[0].GetIntegerValue(machine); if (value >= 0 && value < int(goto_element.GetPointersCount())) machine.Gosub(goto_element.GetPointer(value)); diff --git a/src/modules/module_obj.cc b/src/modules/module_obj.cc index 5ca19c4a..54d00b35 100644 --- a/src/modules/module_obj.cc +++ b/src/modules/module_obj.cc @@ -35,9 +35,7 @@ #include "systems/base/system.h" #include "utilities/exception.h" #include "libreallive/bytecode.h" -#include "libreallive/expression_pieces.h" -using libreallive::IntegerConstant; using libreallive::ExpressionPiece; void EnsureIsParentObject(GraphicsObject& parent, int size) { @@ -131,24 +129,26 @@ void ObjRangeAdapter::operator()(RLMachine& machine, // what RLOperation.DispatchFunction() does; we manually call the // subclass's Dispatch() so that we can get around the automated // incrementing of the instruction pointer. - int lowerRange = allParameters[0]->GetIntegerValue(machine); - int upperRange = allParameters[1]->GetIntegerValue(machine); - for (int i = lowerRange; i <= upperRange; ++i) { - // Create a new list of expression pieces that contain the - // current object we're dealing with and - libreallive::ExpressionPiecesVector currentInstantiation; - currentInstantiation.emplace_back(new IntegerConstant(i)); - - // Copy everything after the first two items - libreallive::ExpressionPiecesVector::const_iterator it = - allParameters.begin(); - std::advance(it, 2); - for (; it != allParameters.end(); ++it) { - currentInstantiation.emplace_back((*it)->Clone()); - } + int lowerRange = allParameters[0].GetIntegerValue(machine); + int upperRange = allParameters[1].GetIntegerValue(machine); - // Now Dispatch based on these parameters. - handler->Dispatch(machine, currentInstantiation); + // Create a new list of expression pieces that contain a single integer at + // the front. We will update this integer each time through the loop below. + libreallive::ExpressionPiecesVector parameters; + parameters.reserve(allParameters.size() - 1); + parameters.emplace_back( + libreallive::ExpressionPiece::IntConstant(lowerRange)); + + // Copy everything after the first two items + libreallive::ExpressionPiecesVector::const_iterator it = + allParameters.begin(); + std::advance(it, 2); + for (; it != allParameters.end(); ++it) + parameters.emplace_back(*it); + + for (int i = lowerRange; i <= upperRange; ++i) { + parameters[0] = libreallive::ExpressionPiece::IntConstant(i); + handler->Dispatch(machine, parameters); } machine.AdvanceInstructionPointer(); @@ -175,16 +175,14 @@ void ChildObjAdapter::operator()(RLMachine& machine, if (allParameters.size() < 1) throw rlvm::Exception("Less than one argument to an objLayered function!"); - int objset = allParameters[0]->GetIntegerValue(machine); + int objset = allParameters[0].GetIntegerValue(machine); // Copy everything after the first item - libreallive::ExpressionPiecesVector currentInstantiation; libreallive::ExpressionPiecesVector::const_iterator it = allParameters.begin(); ++it; - for (; it != allParameters.end(); ++it) { - currentInstantiation.emplace_back((*it)->Clone()); - } + libreallive::ExpressionPiecesVector currentInstantiation( + it, allParameters.end()); handler->SetProperty(P_PARENTOBJ, objset); handler->Dispatch(machine, currentInstantiation); @@ -217,29 +215,33 @@ void ChildObjRangeAdapter::operator()(RLMachine& machine, // This part is like ChildObjAdapter; the first parameter is an integer // that represents the parent object. - int objset = allParameters[0]->GetIntegerValue(machine); + int objset = allParameters[0].GetIntegerValue(machine); // This part is like ObjRangeAdapter; the second and third parameters are // integers that represent a range of child objects. - int lowerRange = allParameters[1]->GetIntegerValue(machine); - int upperRange = allParameters[2]->GetIntegerValue(machine); + int lowerRange = allParameters[1].GetIntegerValue(machine); + int upperRange = allParameters[2].GetIntegerValue(machine); + + // Create a new list of expression pieces that contain a single integer at + // the front. We will update this integer each time through the loop below. + libreallive::ExpressionPiecesVector parameters; + parameters.reserve(allParameters.size() - 2); + parameters.emplace_back( + libreallive::ExpressionPiece::IntConstant(lowerRange)); + + // Copy everything after the first three items + libreallive::ExpressionPiecesVector::const_iterator it = + allParameters.begin(); + std::advance(it, 3); + for (; it != allParameters.end(); ++it) + parameters.emplace_back(*it); + for (int i = lowerRange; i <= upperRange; ++i) { - // Create a new list of expression pieces that contain the - // current object we're dealing with and - libreallive::ExpressionPiecesVector currentInstantiation; - currentInstantiation.emplace_back(new IntegerConstant(i)); - - // Copy everything after the first three items - libreallive::ExpressionPiecesVector::const_iterator it = - allParameters.begin(); - std::advance(it, 3); - for (; it != allParameters.end(); ++it) { - currentInstantiation.emplace_back((*it)->Clone()); - } + parameters[0] = libreallive::ExpressionPiece::IntConstant(i); // Now Dispatch based on these parameters. handler->SetProperty(P_PARENTOBJ, objset); - handler->Dispatch(machine, currentInstantiation); + handler->Dispatch(machine, parameters); } machine.AdvanceInstructionPointer(); diff --git a/src/modules/module_sys_timetable2.cc b/src/modules/module_sys_timetable2.cc index 55d44df0..f595fb1c 100644 --- a/src/modules/module_sys_timetable2.cc +++ b/src/modules/module_sys_timetable2.cc @@ -34,9 +34,8 @@ #include "utilities/math_util.h" // static -int TimeTableMapper::GetTypeForTag( - const libreallive::SpecialExpressionPiece& sp) { - switch (sp.overload_tag()) { +int TimeTableMapper::GetTypeForTag(const libreallive::ExpressionPiece& sp) { + switch (sp.GetOverloadTag()) { case 48: return 0; case 65584: @@ -57,7 +56,7 @@ int TimeTableMapper::GetTypeForTag( return 8; default: { std::ostringstream oss; - oss << "Invalid timetable2 tag: " << sp.overload_tag(); + oss << "Invalid timetable2 tag: " << sp.GetOverloadTag(); throw rlvm::Exception(oss.str()); } } diff --git a/src/modules/module_sys_timetable2.h b/src/modules/module_sys_timetable2.h index eceae9e5..77bd9e84 100644 --- a/src/modules/module_sys_timetable2.h +++ b/src/modules/module_sys_timetable2.h @@ -37,7 +37,7 @@ class RLModule; // Maps the time table commands high tags down to normal. struct TimeTableMapper { - static int GetTypeForTag(const libreallive::SpecialExpressionPiece& sp); + static int GetTypeForTag(const libreallive::ExpressionPiece& sp); }; // Defines timetable2's input pattern. diff --git a/src/utilities/exception.cc b/src/utilities/exception.cc index c2454250..07a98201 100644 --- a/src/utilities/exception.cc +++ b/src/utilities/exception.cc @@ -123,9 +123,8 @@ void UnimplementedOpcode::SetFullDescription(RLMachine& machine) { // Take the binary stuff and try to get usefull, printable values. const char* start = it->c_str(); try { - std::unique_ptr piece( - libreallive::GetData(start)); - oss << piece->GetDebugString(); + libreallive::ExpressionPiece piece(libreallive::GetData(start)); + oss << piece.GetDebugString(); } catch (libreallive::Error& e) { // Any error throw here is a parse error. diff --git a/test/expression_test.cc b/test/expression_test.cc index 8d062e64..516c2293 100644 --- a/test/expression_test.cc +++ b/test/expression_test.cc @@ -138,8 +138,7 @@ TEST(ExpressionTest, ParseWithNewlineInIt) { // This shouldn't throw. const char* start = parsable.c_str(); - std::unique_ptr piece( - libreallive::GetData(start)); + libreallive::ExpressionPiece piece(libreallive::GetData(start)); - ASSERT_TRUE(piece->IsSpecialParameter()); + ASSERT_TRUE(piece.IsSpecialParameter()); }