mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:49:58 +00:00
added basic arithmetic
This commit is contained in:
parent
ca8002e533
commit
48f6ad0f89
9 changed files with 454 additions and 83 deletions
|
@ -2,6 +2,7 @@
|
|||
#include "exprparser.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
#include "generator.hpp"
|
||||
#include "scanner.hpp"
|
||||
|
@ -9,36 +10,139 @@
|
|||
|
||||
namespace Compiler
|
||||
{
|
||||
char ExprParser::popUnaryOperator()
|
||||
int ExprParser::getPriority (char op) const
|
||||
{
|
||||
if (mOperators.empty())
|
||||
return 0;
|
||||
|
||||
char op = mOperators[mOperators.size()-1];
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
|
||||
return 1;
|
||||
|
||||
if (op!='m') // unary -
|
||||
return 0;
|
||||
case '*':
|
||||
case '/':
|
||||
|
||||
mOperators.resize (mOperators.size()-1);
|
||||
return 2;
|
||||
|
||||
case 'm':
|
||||
|
||||
return op;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
char ExprParser::popOperand (std::vector<Interpreter::Type_Code>& code)
|
||||
{
|
||||
Operand operand = mOperands[mOperands.size()-1];
|
||||
mOperands.resize (mOperands.size()-1);
|
||||
|
||||
if (operand.mType=='l')
|
||||
Generator::pushInt (code, mLiterals, operand.mInteger);
|
||||
else if (operand.mType=='f')
|
||||
Generator::pushFloat (code, mLiterals, operand.mFloat);
|
||||
else
|
||||
throw std::logic_error ("unknown expression type");
|
||||
|
||||
return operand.mType;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char ExprParser::getOperandType (int Index) const
|
||||
{
|
||||
assert (!mOperands.empty());
|
||||
assert (Index>=0);
|
||||
assert (Index<static_cast<int> (mOperands.size()));
|
||||
return mOperands[mOperands.size()-1-Index];
|
||||
}
|
||||
|
||||
char ExprParser::getOperator() const
|
||||
{
|
||||
assert (!mOperators.empty());
|
||||
return mOperators[mOperators.size()-1];
|
||||
}
|
||||
|
||||
void ExprParser::popOperator()
|
||||
{
|
||||
assert (!mOperators.empty());
|
||||
mOperators.resize (mOperators.size()-1);
|
||||
}
|
||||
|
||||
void ExprParser::popOperand()
|
||||
{
|
||||
assert (!mOperands.empty());
|
||||
mOperands.resize (mOperands.size()-1);
|
||||
}
|
||||
|
||||
void ExprParser::replaceBinaryOperands()
|
||||
{
|
||||
char t1 = getOperandType (1);
|
||||
char t2 = getOperandType();
|
||||
|
||||
popOperand();
|
||||
popOperand();
|
||||
|
||||
if (t1==t2)
|
||||
mOperands.push_back (t1);
|
||||
else if (t1=='f' || t2=='f')
|
||||
mOperands.push_back ('f');
|
||||
else
|
||||
std::logic_error ("failed to determine result operand type");
|
||||
}
|
||||
|
||||
void ExprParser::pop()
|
||||
{
|
||||
char op = getOperator();
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case 'm':
|
||||
|
||||
Generator::negate (mCode, getOperandType());
|
||||
popOperator();
|
||||
break;
|
||||
|
||||
case '+':
|
||||
|
||||
Generator::add (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '-':
|
||||
|
||||
Generator::sub (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '*':
|
||||
|
||||
Generator::mul (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '/':
|
||||
|
||||
Generator::div (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::logic_error ("unknown operator");
|
||||
}
|
||||
}
|
||||
|
||||
void ExprParser::pushIntegerLiteral (int value)
|
||||
{
|
||||
mNextOperand = false;
|
||||
mOperands.push_back ('l');
|
||||
Generator::pushInt (mCode, mLiterals, value);
|
||||
}
|
||||
|
||||
void ExprParser::pushFloatLiteral (float value)
|
||||
{
|
||||
mNextOperand = false;
|
||||
mOperands.push_back ('f');
|
||||
Generator::pushFloat (mCode, mLiterals, value);
|
||||
}
|
||||
|
||||
void ExprParser::pushBinaryOperator (char c)
|
||||
{
|
||||
while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c))
|
||||
pop();
|
||||
|
||||
mOperators.push_back (c);
|
||||
mNextOperand = true;
|
||||
}
|
||||
|
||||
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||
|
@ -49,13 +153,7 @@ namespace Compiler
|
|||
{
|
||||
if (mNextOperand)
|
||||
{
|
||||
Operand operand;
|
||||
operand.mType = 'l';
|
||||
operand.mInteger = value;
|
||||
|
||||
mOperands.push_back (operand);
|
||||
|
||||
mNextOperand = false;
|
||||
pushIntegerLiteral (value);
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
@ -67,13 +165,7 @@ namespace Compiler
|
|||
{
|
||||
if (mNextOperand)
|
||||
{
|
||||
Operand operand;
|
||||
operand.mType = 'f';
|
||||
operand.mFloat = value;
|
||||
|
||||
mOperands.push_back (operand);
|
||||
|
||||
mNextOperand = false;
|
||||
pushFloatLiteral (value);
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
@ -109,15 +201,22 @@ namespace Compiler
|
|||
return false;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_minus)
|
||||
if (code==Scanner::S_minus && mNextOperand)
|
||||
{
|
||||
if (mNextOperand)
|
||||
{
|
||||
// unary
|
||||
mOperators.push_back ('m');
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
// unary
|
||||
mOperators.push_back ('m');
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case Scanner::S_plus: pushBinaryOperator ('+'); return true;
|
||||
case Scanner::S_minus: pushBinaryOperator ('-'); return true;
|
||||
case Scanner::S_mult: pushBinaryOperator ('*'); return true;
|
||||
case Scanner::S_div: pushBinaryOperator ('/'); return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
|
@ -128,34 +227,30 @@ namespace Compiler
|
|||
mOperands.clear();
|
||||
mOperators.clear();
|
||||
mNextOperand = true;
|
||||
mCode.clear();
|
||||
}
|
||||
|
||||
char ExprParser::write (std::vector<Interpreter::Type_Code>& code)
|
||||
char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
|
||||
{
|
||||
if (mOperands.empty() && mOperators.empty())
|
||||
getErrorHandler().error ("missing expression", mTokenLoc);
|
||||
|
||||
if (mNextOperand)
|
||||
getErrorHandler().error ("syntax error in expression", mTokenLoc);
|
||||
|
||||
char type = ' ';
|
||||
|
||||
while (!mOperands.empty())
|
||||
{
|
||||
type = popOperand (code);
|
||||
|
||||
while (char op = popUnaryOperator())
|
||||
{
|
||||
if (op=='m')
|
||||
{
|
||||
Generator::negate (code, type);
|
||||
}
|
||||
else
|
||||
throw std::logic_error ("unknown unary operator");
|
||||
}
|
||||
getErrorHandler().error ("missing expression", mTokenLoc);
|
||||
return 'l';
|
||||
}
|
||||
|
||||
return type;
|
||||
|
||||
if (mNextOperand || mOperands.empty())
|
||||
{
|
||||
getErrorHandler().error ("syntax error in expression", mTokenLoc);
|
||||
return 'l';
|
||||
}
|
||||
|
||||
while (!mOperators.empty())
|
||||
pop();
|
||||
|
||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||
|
||||
assert (mOperands.size()==1);
|
||||
return mOperands[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,25 +15,34 @@ namespace Compiler
|
|||
|
||||
class ExprParser : public Parser
|
||||
{
|
||||
struct Operand
|
||||
{
|
||||
char mType;
|
||||
int mInteger;
|
||||
float mFloat;
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
Literals& mLiterals;
|
||||
std::vector<Operand> mOperands;
|
||||
std::vector<char> mOperands;
|
||||
std::vector<char> mOperators;
|
||||
bool mNextOperand;
|
||||
TokenLoc mTokenLoc;
|
||||
std::vector<Interpreter::Type_Code> mCode;
|
||||
|
||||
char popUnaryOperator();
|
||||
///< returns 0 and not popping, if the next operator isn't unary
|
||||
int getPriority (char op) const;
|
||||
|
||||
char popOperand (std::vector<Interpreter::Type_Code>& code);
|
||||
char getOperandType (int Index = 0) const;
|
||||
|
||||
char getOperator() const;
|
||||
|
||||
void popOperator();
|
||||
|
||||
void popOperand();
|
||||
|
||||
void replaceBinaryOperands();
|
||||
|
||||
void pop();
|
||||
|
||||
void pushIntegerLiteral (int value);
|
||||
|
||||
void pushFloatLiteral (float value);
|
||||
|
||||
void pushBinaryOperator (char c);
|
||||
|
||||
public:
|
||||
|
||||
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
|
@ -67,7 +76,7 @@ namespace Compiler
|
|||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
|
||||
char write (std::vector<Interpreter::Type_Code>& code);
|
||||
char append (std::vector<Interpreter::Type_Code>& code);
|
||||
///< Generate code for parsed expression.
|
||||
/// \return Type ('l': integer, 'f': float)
|
||||
};
|
||||
|
|
|
@ -94,6 +94,56 @@ namespace
|
|||
{
|
||||
code.push_back (segment5 (8));
|
||||
}
|
||||
|
||||
void opAddInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (9));
|
||||
}
|
||||
|
||||
void opAddFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (10));
|
||||
}
|
||||
|
||||
void opSubInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (11));
|
||||
}
|
||||
|
||||
void opSubFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (12));
|
||||
}
|
||||
|
||||
void opMulInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (13));
|
||||
}
|
||||
|
||||
void opMulFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (14));
|
||||
}
|
||||
|
||||
void opDivInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (15));
|
||||
}
|
||||
|
||||
void opDivFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (16));
|
||||
}
|
||||
|
||||
void opIntToFloat1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (17));
|
||||
}
|
||||
|
||||
void opFloatToInt1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (18));
|
||||
}
|
||||
}
|
||||
|
||||
namespace Compiler
|
||||
|
@ -175,6 +225,78 @@ namespace Compiler
|
|||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void add (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opAddInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opAddFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void sub (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opSubInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opSubFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void mul (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opMulInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opMulFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void div (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opDivInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opDivFloat (code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,14 @@ namespace Compiler
|
|||
int localIndex, const CodeContainer& value, char valueType);
|
||||
|
||||
void negate (CodeContainer& code, char valueType);
|
||||
|
||||
void add (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void sub (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void mul (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void div (CodeContainer& code, char valueType1, char valueType2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Compiler
|
|||
scanner.scan (mExprParser);
|
||||
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
char type = mExprParser.write (code);
|
||||
char type = mExprParser.append (code);
|
||||
|
||||
Generator::assignToLocal (mCode, mLocals.getType (mName),
|
||||
mLocals.getIndex (mName), code, type);
|
||||
|
|
|
@ -60,6 +60,16 @@ op 5: replace stack[0] with float literal index stack[0]
|
|||
op 6: convert stack[0] from float to integer
|
||||
op 7: invert sign of int value stack[0]
|
||||
op 8: invert sign of float value stack[0]
|
||||
opcodes 9-33554431 unused
|
||||
op 9: add (integer) stack[0] to stack[1], pop twice, push result
|
||||
op 10: add (float) stack[0] to stack[1], pop twice, push result
|
||||
op 11: sub (integer) stack[1] from stack[0], pop twice, push result
|
||||
op 12: sub (float) stack[1] from stack[0], pop twice, push result
|
||||
op 13: mul (integer) stack[0] with stack[1], pop twice, push result
|
||||
op 14: mul (float) stack[0] with stack[1], pop twice, push result
|
||||
op 15: div (integer) stack[1] by stack[0], pop twice, push result
|
||||
op 16: div (float) stack[1] by stack[0], pop twice, push result
|
||||
op 17: convert stack[1] from integer to float
|
||||
op 18: convert stack[1] from float to integer
|
||||
opcodes 19-33554431 unused
|
||||
opcodes 33554432-67108863 reserved for extensions
|
||||
|
||||
|
|
|
@ -62,7 +62,31 @@ namespace Interpreter
|
|||
data = -data;
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class OpIntToFloat1 : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = *reinterpret_cast<Type_Integer *> (&runtime[1]);
|
||||
Type_Float floatValue = static_cast<Type_Float> (data);
|
||||
runtime[1] = *reinterpret_cast<Type_Data *> (&floatValue);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFloatToInt1 : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float data = *reinterpret_cast<Type_Float *> (&runtime[1]);
|
||||
Type_Integer integerValue = static_cast<Type_Integer> (data);
|
||||
runtime[1] = *reinterpret_cast<Type_Data *> (&integerValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "interpreter.hpp"
|
||||
#include "genericopcodes.hpp"
|
||||
#include "localopcodes.hpp"
|
||||
#include "mathopcodes.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
|
@ -15,13 +16,25 @@ namespace Interpreter
|
|||
interpreter.installSegment5 (6, new OpFloatToInt);
|
||||
interpreter.installSegment5 (7, new OpNegateInt);
|
||||
interpreter.installSegment5 (8, new OpNegateFloat);
|
||||
|
||||
interpreter.installSegment5 (17, new OpIntToFloat1);
|
||||
interpreter.installSegment5 (18, new OpFloatToInt1);
|
||||
|
||||
// local variables
|
||||
interpreter.installSegment5 (0, new OpStoreLocalShort);
|
||||
interpreter.installSegment5 (1, new OpStoreLocalLong);
|
||||
interpreter.installSegment5 (2, new OpStoreLocalFloat);
|
||||
interpreter.installSegment5 (4, new OpFetchIntLiteral);
|
||||
interpreter.installSegment5 (5, new OpFetchFloatLiteral);
|
||||
|
||||
// math
|
||||
interpreter.installSegment5 (9, new OpAddInt<Type_Integer>);
|
||||
interpreter.installSegment5 (10, new OpAddInt<Type_Float>);
|
||||
interpreter.installSegment5 (11, new OpSubInt<Type_Integer>);
|
||||
interpreter.installSegment5 (12, new OpSubInt<Type_Float>);
|
||||
interpreter.installSegment5 (13, new OpMulInt<Type_Integer>);
|
||||
interpreter.installSegment5 (14, new OpMulInt<Type_Float>);
|
||||
interpreter.installSegment5 (15, new OpDivInt<Type_Integer>);
|
||||
interpreter.installSegment5 (16, new OpDivInt<Type_Float>);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
90
components/interpreter/mathopcodes.hpp
Normal file
90
components/interpreter/mathopcodes.hpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef INTERPRETER_MATHOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_MATHOPCODES_H_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
template<typename T>
|
||||
class OpAddInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
+
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpSubInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
-
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpMulInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
*
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpDivInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T left = *reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
if (left==0)
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
/
|
||||
left;
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue