diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 12f63d3aa..79b6f3447 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -155,6 +155,25 @@ namespace Compiler popOperator(); } + void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner) + { + ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); + + for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end(); + ++iter) + { + parser.reset(); + scanner.scan (parser); + + char type = parser.append (mCode); + + if (type!=*iter) + Generator::convert (mCode, type, *iter); + + mOperands.push_back (*iter); + } + } + ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), @@ -193,6 +212,17 @@ namespace Compiler bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (keyword==Scanner::K_getsquareroot && mNextOperand) + { + mTokenLoc = loc; + parseArguments ("f", scanner); + + Generator::squareRoot (mCode); + + mNextOperand = false; + return true; + } + return Parser::parseKeyword (keyword, loc, scanner); } @@ -234,14 +264,17 @@ namespace Compiler return true; } - mTokenLoc = loc; - - switch (code) + if (!mNextOperand) { - 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; + 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); diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index a87dd995b..6dba519ea 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -44,6 +44,8 @@ namespace Compiler void pushBinaryOperator (char c); void close(); + + void parseArguments (const std::string& arguments, Scanner& scanner); public: diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 971fd81b3..e704ac724 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "literals.hpp" @@ -144,6 +145,11 @@ namespace { code.push_back (segment5 (18)); } + + void opSquareRoot (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (19)); + } } namespace Compiler @@ -297,6 +303,24 @@ namespace Compiler opDivFloat (code); } } + + void convert (CodeContainer& code, char fromType, char toType) + { + if (fromType!=toType) + { + if (fromType=='f' && toType=='l') + opFloatToInt (code); + else if (fromType=='l' && toType=='f') + opIntToFloat (code); + else + throw std::logic_error ("illegal type conversion"); + } + } + + void squareRoot (CodeContainer& code) + { + opSquareRoot (code); + } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index cea8a8636..44b0fc4f2 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -29,6 +29,10 @@ namespace Compiler void mul (CodeContainer& code, char valueType1, char valueType2); void div (CodeContainer& code, char valueType1, char valueType2); + + void convert (CodeContainer& code, char fromType, char toType); + + void squareRoot (CodeContainer& code); } } diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 17b2dc305..e04e2114b 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -213,6 +213,7 @@ namespace Compiler "return", "messagebox", "set", "to", + "getsquareroot", 0 }; diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 63a0dbb4d..5a490d70e 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -35,7 +35,8 @@ namespace Compiler K_while, K_endwhile, K_return, K_messageBox, - K_set, K_to + K_set, K_to, + K_getsquareroot }; enum special diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index db85e6af8..748e6e3ee 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -70,6 +70,7 @@ 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 +op 19: take square root of stack[0] (float) +opcodes 20-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index a0f90b98e..b96a0a1a5 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -35,6 +35,7 @@ namespace Interpreter interpreter.installSegment5 (14, new OpMulInt); interpreter.installSegment5 (15, new OpDivInt); interpreter.installSegment5 (16, new OpDivInt); + interpreter.installSegment5 (19, new OpSquareRoot); } } diff --git a/components/interpreter/mathopcodes.hpp b/components/interpreter/mathopcodes.hpp index 4cec3bfc9..bb12274d3 100644 --- a/components/interpreter/mathopcodes.hpp +++ b/components/interpreter/mathopcodes.hpp @@ -2,6 +2,7 @@ #define INTERPRETER_MATHOPCODES_H_INCLUDED #include +#include #include "opcodes.hpp" #include "runtime.hpp" @@ -84,6 +85,24 @@ namespace Interpreter runtime[0] = *reinterpret_cast (&result); } }; + + class OpSquareRoot : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Float value = *reinterpret_cast (&runtime[0]); + + if (value<0) + throw std::runtime_error ( + "square root of negative number (we aren't that imaginary)"); + + value = std::sqrt (value); + + runtime[0] = *reinterpret_cast (&value); + } + }; } #endif