From 48f6ad0f898cc6d4efbb2e11e74ac020cbca4be9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Jun 2010 16:11:19 +0200 Subject: [PATCH] added basic arithmetic --- components/compiler/exprparser.cpp | 213 ++++++++++++++++------ components/compiler/exprparser.hpp | 33 ++-- components/compiler/generator.cpp | 122 +++++++++++++ components/compiler/generator.hpp | 8 + components/compiler/lineparser.cpp | 2 +- components/interpreter/docs/vmformat.txt | 12 +- components/interpreter/genericopcodes.hpp | 26 ++- components/interpreter/installopcodes.cpp | 15 +- components/interpreter/mathopcodes.hpp | 90 +++++++++ 9 files changed, 446 insertions(+), 75 deletions(-) create mode 100644 components/interpreter/mathopcodes.hpp diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 516879c40..11347e3e4 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -2,6 +2,7 @@ #include "exprparser.hpp" #include +#include #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; + } + + return 0; + } + + char ExprParser::getOperandType (int Index) const + { + assert (!mOperands.empty()); + assert (Index>=0); + assert (Index (mOperands.size())); + return mOperands[mOperands.size()-1-Index]; } - char ExprParser::popOperand (std::vector& code) + char ExprParser::getOperator() const + { + assert (!mOperators.empty()); + return mOperators[mOperators.size()-1]; + } + + void ExprParser::popOperator() { - Operand operand = mOperands[mOperands.size()-1]; - mOperands.resize (mOperands.size()-1); + assert (!mOperators.empty()); + mOperators.resize (mOperators.size()-1); + } - if (operand.mType=='l') - Generator::pushInt (code, mLiterals, operand.mInteger); - else if (operand.mType=='f') - Generator::pushFloat (code, mLiterals, operand.mFloat); + 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 - throw std::logic_error ("unknown expression type"); + 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: - return operand.mType; + 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) + { + // unary + mOperators.push_back ('m'); + mTokenLoc = loc; + return true; + } + + mTokenLoc = loc; + + switch (code) { - if (mNextOperand) - { - // unary - mOperators.push_back ('m'); - mTokenLoc = loc; - return true; - } + 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& code) + char ExprParser::append (std::vector& code) { if (mOperands.empty() && mOperators.empty()) + { getErrorHandler().error ("missing expression", mTokenLoc); + return 'l'; + } - if (mNextOperand) + if (mNextOperand || mOperands.empty()) + { getErrorHandler().error ("syntax error in expression", mTokenLoc); + return 'l'; + } - char type = ' '; + while (!mOperators.empty()) + pop(); - 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"); - } - } - - return type; + std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); + + assert (mOperands.size()==1); + return mOperands[0]; } } diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 93f5db478..73d6b82d7 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -15,25 +15,34 @@ namespace Compiler class ExprParser : public Parser { - struct Operand - { - char mType; - int mInteger; - float mFloat; - }; - Locals& mLocals; Literals& mLiterals; - std::vector mOperands; + std::vector mOperands; std::vector mOperators; bool mNextOperand; TokenLoc mTokenLoc; + std::vector mCode; + + int getPriority (char op) const; + + char getOperandType (int Index = 0) const; + + char getOperator() const; + + void popOperator(); + + void popOperand(); + + void replaceBinaryOperands(); + + void pop(); - char popUnaryOperator(); - ///< returns 0 and not popping, if the next operator isn't unary + void pushIntegerLiteral (int value); - char popOperand (std::vector& code); + 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& code); + char append (std::vector& code); ///< Generate code for parsed expression. /// \return Type ('l': integer, 'f': float) }; diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index cf9f68eef..971fd81b3 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -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); + } + } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index 42117eecb..cea8a8636 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -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); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 1685af848..92c9aad57 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -97,7 +97,7 @@ namespace Compiler scanner.scan (mExprParser); std::vector code; - char type = mExprParser.write (code); + char type = mExprParser.append (code); Generator::assignToLocal (mCode, mLocals.getType (mName), mLocals.getIndex (mName), code, type); diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 1a4db8b56..db85e6af8 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -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 diff --git a/components/interpreter/genericopcodes.hpp b/components/interpreter/genericopcodes.hpp index db22ac089..116b586e4 100644 --- a/components/interpreter/genericopcodes.hpp +++ b/components/interpreter/genericopcodes.hpp @@ -62,7 +62,31 @@ namespace Interpreter data = -data; runtime[0] = *reinterpret_cast (&data); } - }; + }; + + class OpIntToFloat1 : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer data = *reinterpret_cast (&runtime[1]); + Type_Float floatValue = static_cast (data); + runtime[1] = *reinterpret_cast (&floatValue); + } + }; + + class OpFloatToInt1 : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Float data = *reinterpret_cast (&runtime[1]); + Type_Integer integerValue = static_cast (data); + runtime[1] = *reinterpret_cast (&integerValue); + } + }; } #endif diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 15755a38a..a0f90b98e 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -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); + interpreter.installSegment5 (10, new OpAddInt); + interpreter.installSegment5 (11, new OpSubInt); + interpreter.installSegment5 (12, new OpSubInt); + interpreter.installSegment5 (13, new OpMulInt); + interpreter.installSegment5 (14, new OpMulInt); + interpreter.installSegment5 (15, new OpDivInt); + interpreter.installSegment5 (16, new OpDivInt); } } diff --git a/components/interpreter/mathopcodes.hpp b/components/interpreter/mathopcodes.hpp new file mode 100644 index 000000000..4cec3bfc9 --- /dev/null +++ b/components/interpreter/mathopcodes.hpp @@ -0,0 +1,90 @@ +#ifndef INTERPRETER_MATHOPCODES_H_INCLUDED +#define INTERPRETER_MATHOPCODES_H_INCLUDED + +#include + +#include "opcodes.hpp" +#include "runtime.hpp" + +namespace Interpreter +{ + template + class OpAddInt : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + T result = + *reinterpret_cast (&runtime[1]) + + + *reinterpret_cast (&runtime[0]); + + runtime.pop(); + + runtime[0] = *reinterpret_cast (&result); + } + }; + + template + class OpSubInt : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + T result = + *reinterpret_cast (&runtime[1]) + - + *reinterpret_cast (&runtime[0]); + + runtime.pop(); + + runtime[0] = *reinterpret_cast (&result); + } + }; + + template + class OpMulInt : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + T result = + *reinterpret_cast (&runtime[1]) + * + *reinterpret_cast (&runtime[0]); + + runtime.pop(); + + runtime[0] = *reinterpret_cast (&result); + } + }; + + template + class OpDivInt : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + T left = *reinterpret_cast (&runtime[0]); + + if (left==0) + throw std::runtime_error ("division by zero"); + + T result = + *reinterpret_cast (&runtime[1]) + / + left; + + runtime.pop(); + + runtime[0] = *reinterpret_cast (&result); + } + }; +} + +#endif +