diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 4b572b6b15..b1522d99aa 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -20,19 +20,28 @@ namespace Compiler return 0; + case 'e': // == + case 'n': // != + case 'l': // < + case 'L': // <= + case 'g': // < + case 'G': // >= + + return 1; + case '+': case '-': - return 1; + return 2; case '*': case '/': - return 2; + return 3; case 'm': - return 3; + return 4; } return 0; @@ -125,6 +134,20 @@ namespace Compiler replaceBinaryOperands(); break; + case 'e': + case 'n': + case 'l': + case 'L': + case 'g': + case 'G': + + Generator::compare (mCode, op, getOperandType (1), getOperandType()); + popOperator(); + popOperand(); + popOperand(); + mOperands.push_back ('l'); + break; + default: throw std::logic_error ("unknown operator"); @@ -164,7 +187,7 @@ namespace Compiler void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner) { - ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); + ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true); for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end(); ++iter) @@ -182,9 +205,9 @@ namespace Compiler } ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, - Literals& literals) + Literals& literals, bool argument) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), - mNextOperand (true), mFirst (true) + mNextOperand (true), mFirst (true), mArgument (argument) {} bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) @@ -345,6 +368,7 @@ namespace Compiler if (!mNextOperand) { mTokenLoc = loc; + char c = 0; // comparison switch (code) { @@ -352,6 +376,26 @@ namespace Compiler case Scanner::S_minus: pushBinaryOperator ('-'); return true; case Scanner::S_mult: pushBinaryOperator ('*'); return true; case Scanner::S_div: pushBinaryOperator ('/'); return true; + case Scanner::S_cmpEQ: c = 'e'; break; + case Scanner::S_cmpNE: c = 'n'; break; + case Scanner::S_cmpLT: c = 'l'; break; + case Scanner::S_cmpLE: c = 'L'; break; + case Scanner::S_cmpGT: c = 'g'; break; + case Scanner::S_cmpGE: c = 'G'; break; + } + + if (c) + { + if (mArgument && !isOpen()) + { + // expression ends here + // Thank you Morrowind for this rotten syntax :( + scanner.putbackSpecial (code, loc); + return false; + } + + pushBinaryOperator (c); + return true; } } diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 47b2151bb8..db7074056d 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -23,6 +23,7 @@ namespace Compiler TokenLoc mTokenLoc; std::vector mCode; bool mFirst; + bool mArgument; int getPriority (char op) const; @@ -53,8 +54,10 @@ namespace Compiler public: ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, - Literals& literals); + Literals& literals, bool argument = false); ///< constructor + /// \param argument Parser is used to parse function- or instruction- + /// arguments (this influences the precedence rules). char getType() const; ///< Return type of parsed expression ('l' integer, 'f' float) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index f540f3314e..e6af416732 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -195,6 +195,66 @@ namespace { code.push_back (segment5 (25)); } + + void opEqualInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (26)); + } + + void opNonEqualInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (27)); + } + + void opLessThanInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (28)); + } + + void opLessOrEqualInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (29)); + } + + void opGreaterThanInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (30)); + } + + void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (31)); + } + + void opEqualFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (32)); + } + + void opNonEqualFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (33)); + } + + void opLessThanFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (34)); + } + + void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (35)); + } + + void opGreaterThanFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (36)); + } + + void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (segment5 (37)); + } } namespace Compiler @@ -439,6 +499,48 @@ namespace Compiler jump (code, offset); } + + void compare (CodeContainer& code, char op, char valueType1, char valueType2) + { + if (valueType1=='l' && valueType2=='l') + { + switch (op) + { + case 'e': opEqualInt (code); break; + case 'n': opNonEqualInt (code); break; + case 'l': opLessThanInt (code); break; + case 'L': opLessOrEqualInt (code); break; + case 'g': opGreaterThanInt (code); break; + case 'G': opGreaterOrEqualInt (code); break; + + default: + + assert (0); + } + } + else + { + if (valueType1=='l') + opIntToFloat1 (code); + + if (valueType2=='l') + opIntToFloat (code); + + switch (op) + { + case 'e': opEqualFloat (code); break; + case 'n': opNonEqualFloat (code); break; + case 'l': opLessThanFloat (code); break; + case 'L': opLessOrEqualFloat (code); break; + case 'g': opGreaterThanFloat (code); break; + case 'G': opGreaterOrEqualFloat (code); break; + + default: + + assert (0); + } + } + } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index 7d1f52df46..8864d51ece 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -47,6 +47,8 @@ namespace Compiler void jumpOnZero (CodeContainer& code, int offset); void jumpOnNonZero (CodeContainer& code, int offset); + + void compare (CodeContainer& code, char op, char valueType1, char valueType2); } } diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 4cd6b66082..3337479116 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -84,6 +84,18 @@ op 22: replace stack[0] with local long stack[0] op 23: replace stack[0] with local float stack[0] op 24: skip next instruction if stack[0]==0; pop op 25: skip next instruction if stack[0]!=0; pop -opcodes 26-33554431 unused +op 26: compare (intger) stack[1] with stack[0]; pop twice; push 1 if equal, 0 else +op 27: compare (intger) stack[1] with stack[0]; pop twice; push 1 if no equal, 0 else +op 28: compare (intger) stack[1] with stack[0]; pop twice; push 1 if lesser than, 0 else +op 29: compare (intger) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else +op 30: compare (intger) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else +op 31: compare (intger) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else +op 32: compare (float) stack[1] with stack[0]; pop twice; push 1 if equal, 0 else +op 33: compare (float) stack[1] with stack[0]; pop twice; push 1 if no equal, 0 else +op 34: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser than, 0 else +op 35: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else +op 36: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else +op 37: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else +opcodes 38-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 5066fd5a0e..3567d5943d 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -1,6 +1,8 @@ #include "installopcodes.hpp" +#include + #include "interpreter.hpp" #include "genericopcodes.hpp" #include "localopcodes.hpp" @@ -40,8 +42,33 @@ namespace Interpreter interpreter.installSegment5 (14, new OpMulInt); interpreter.installSegment5 (15, new OpDivInt); interpreter.installSegment5 (16, new OpDivInt); - interpreter.installSegment5 (19, new OpSquareRoot); - + interpreter.installSegment5 (19, new OpSquareRoot); + interpreter.installSegment5 (26, + new OpCompare >); + interpreter.installSegment5 (27, + new OpCompare >); + interpreter.installSegment5 (28, + new OpCompare >); + interpreter.installSegment5 (29, + new OpCompare >); + interpreter.installSegment5 (30, + new OpCompare >); + interpreter.installSegment5 (31, + new OpCompare >); + + interpreter.installSegment5 (32, + new OpCompare >); + interpreter.installSegment5 (33, + new OpCompare >); + interpreter.installSegment5 (34, + new OpCompare >); + interpreter.installSegment5 (35, + new OpCompare >); + interpreter.installSegment5 (36, + new OpCompare >); + interpreter.installSegment5 (37, + new OpCompare >); + // control structures interpreter.installSegment5 (20, new OpReturn); interpreter.installSegment5 (24, new OpSkipZero); diff --git a/components/interpreter/mathopcodes.hpp b/components/interpreter/mathopcodes.hpp index bb12274d36..d569a54709 100644 --- a/components/interpreter/mathopcodes.hpp +++ b/components/interpreter/mathopcodes.hpp @@ -103,6 +103,23 @@ namespace Interpreter runtime[0] = *reinterpret_cast (&value); } }; + + template + class OpCompare : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + int result = C() ( + *reinterpret_cast (&runtime[1]), + *reinterpret_cast (&runtime[0])); + + runtime.pop(); + + runtime[0] = *reinterpret_cast (&result); + } + }; } #endif