khanat-opennel-code/code/nel/include/nel/misc/eval_num_expr.h

335 lines
11 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_EVAL_NUM_EXPR_H
#define NL_EVAL_NUM_EXPR_H
#include "types_nl.h"
namespace NLMISC
{
/**
* This class performs numerical expression parsing.
*/
class CEvalNumExpr
{
public:
virtual ~CEvalNumExpr() {}
/// Eval return error.
enum TReturnState
{
NoError, // No error
UnknownValue, // Unknown value has been parsed
ValueError, // Error during user defined value evaluation
UnknownFunction, // Unknown function has been parsed
FunctionError, // Error during user defined function evaluation
NumberSyntaxError, // Syntax error in a number expression
UnknownOperator, // Unknown operator
MustBeOpen, // Should be a open parenthesis
MustBeClose, // Should be a close parenthesis
MustBeComa, // Should be a coma character
MustBeExpression, // Should be an expression
NotUnaryOperator, // Should not be an unary operator
MustBeEnd, // Should be the end
MustBeDoubleQuote, // Should be a double quote
DividByZero, // Divide by zero
ReturnValueCount
};
/**
* Evaluate a numerical expression.
*
* Doesn't allocate heap memory for common complexity expression.
*
* \param expression is an expression string. See the expression grammar.
* \param result is filled with the result if the function returns "NoError".
* \param errorIndex is a pointer on an integer value filled with the index
* of the parsing error in the input string if function doesn't return "NoError".
* This value can be NULL.
* \param userData is a user data used by user eval function
* \return NoError if the expression has been parsed. Result is filled with the evaluated value.
*
* This expression must follow the following grammar with the following evaluation priority:
*
* expression: '-' expression
* | '!' expression // Returns true if a equal false, else false (logical not)
* | '~' expression // Returns ~ round(a) (bitwise not)
* | '(' expression ')'
* | expression operator expression
* | function1 '(' expression ')'
* | function2 '(' expression ',' expression ')'
* | number
* | constant
* | string // User defined value, evaluated by the evalValue() callback
*
* operator: '*' // Calculates (a * b)
* | '/' // Calculates (a / b)
* | '%' // Calculates the remainder of (a / b)
* | '+' // Calculates (a + b)
* | '-' // Calculates (a - b)
* | '<<' // Returns round(a) left 32 bits unsigned shift by round(b)
* | '>>' // Returns round(a) right 32 bits unsigned shift by round(b)
* | '<-' // Returns round(a) left 32 bits signed shift by round(b)
* | '->' // Returns round(a) right 32 bits signed shift by round(b)
* | '<' // Returns true if a is strictly smaller than b
* | '<=' // Returns true if a is smaller or equal than b
* | '>' // Returns true if a is strictly bigger than b
* | '>=' // Returns true if a is bigger or equal than b
* | '==' // Returns true if a equal b, else returns false (warning, performs a floating point comparison)
* | '!=' // Returns false if a equal b, else returns true (warning, performs a floating point comparison)
* | '&' // Returns round(a) & round(b) over 32 bits
* | '|' // Returns round(a) | round(b) over 32 bits
* | '^' // Returns round(a) ^ round(b) over 32 bits
* | '&&' // Returns true if a equal true and b equal true else returns false
* | '||' // Returns true if a equal true or b equal true else returns false
* | '^^' // Returns true if a equal true and b equal false, or, a equal false and b equal 1.0, else returns false
*
* function1: abs // Calculates the absolute value
* | acos // Calculates the arccosine
* | asin // Calculates the arcsine
* | atan // Calculates the arctangent
* | ceil // Calculates the ceiling of a value ( ceil(-1.1) = -1, ceil(1.1) = 2 )
* | cos // Calculates the cosine
* | cosh // Calculates the hyperbolic cosine
* | exp // Calculates the exponential
* | exponent // Calculates the exponent of a floating point value
* | floor // Calculates the floor of a value ( floor(-1.1) = -2, floor(1.1) = 1 )
* | int // Calculates the C style integer value ( int(-1.6) = -1, int(1.6) = 1 )
* | log // Calculates logarithms
* | log10 // Calculates base-10 logarithms
* | mantissa // Calculates the mantissa of a floating point value
* | round // Calculates the nearest integer value ( round(-1.6) = -2, round(1.1) = 1 )
* | sin // Calculate sines
* | sinh // Calculate hyperbolic sines
* | sq // Calculates the square
* | sqrt // Calculates the square root
* | tan // Calculates the tangent
* | tanh // Calculates the hyperbolic tangent
* | string // User defined one arg function, evaluated by the evalfunction() callback
*
* function2: max // Returns the larger of two values
* | min // Returns the smaller of two values
* | atan2 // Calculates the arctangent of arg0/arg1
* | pow // Calculates a raised at the power of b
* | rand // Calculates a pseudo random value (arg0 <= randomValue < arg1)
* | string // User defined two args function, evaluated by the evalfunction() callback
*
* number: [0-9]+ // Unsigned decimal integer
* | "0x"[0-9a-fA-F]+ // Unsigned hexadecimal integer
* | "0"[0-7]+ // Unsigned octal integer
* | [0-9]*.[0-9]+ // Unsigned floating point value
* | [0-9]*.[0-9]+[eE]-?[0-9]*.[0-9]+ // Unsigned floating point value with signed exponent
*
* constant: e // 2.7182818284590452353602874713527
* | pi // 3.1415926535897932384626433832795
*
* string: [^ 0-9\t\n/\*-+=<>&|\^!%~\(\)\.,\"][^ \t\n/\*-+=<>&|\^!%~\(\)\.,\"]* // Labels ($foo, #foo01, _001)
* | \"[]+\" // All kind of labels between double quotes "123456" "foo.foo[12]"
*
* Operator precedence:
*
* 0 - unary operator (-, ~, !)
* 1 - *, /, %
* 2 - +, -,
* 3 - <<, >>, <-, ->
* 4 - <, <=, >, >=
* 5 - ==, !=
* 6 - &
* 7 - |
* 8 - ^
* 9 - &&
* 10 - ||
* 11 - ^^
*
*/
TReturnState evalExpression (const char *expression, double &result, int *errorIndex, uint32 userData = 0);
/// Get error string
const char* getErrorString (TReturnState state) const;
protected:
/// Overridable functions
/**
* Eval a user defined value. Default implementation returns UnknownValue.
* The user can parse the value and fill the result double and return NoError, UnknownValue or
* ValueError.
*
* \param value is the value to parse.
* \param result is the result to fill if the value has been successfully parsed.
* \param userData is a user data used by user eval function.
* \return UnknownValue if the value is not known, ValueError is the value evaluation failed or NoError
* if it has been parsed.
*/
virtual TReturnState evalValue (const char *value, double &result, uint32 userData);
/**
* Eval a user defined function. Default implementation returns UnknownFunction.
* The user can parse the function name and fill the result double and return NoError, UnknownFunction
* or FunctionError.
*
* To convert double argu in boolean argu, use (round (value) != 0.0) ? true : false
*
* \param funcName is the name of the function to evaluate.
* \param arg0 is the first parameter passed to the function.
* \param arg1 is the second parameter passed to the function.
* \param result is the result to fill if the value has been successfully parsed.
* \return UnknownFunction if the function doesn't exist, FunctionError if the function evaluation
* failed, NoError if it has been parsed.
*/
virtual TReturnState evalFunction (const char *funcName, double arg0, double &result);
virtual TReturnState evalFunction (const char *funcName, double arg0, double arg1, double &result);
private:
/// Implementation
/// Expression tokens
enum TToken
{
Number, // This is a number
Function1, // This is a function with one argu
Function2, // This is a function with two argu
String, // This is a user string
Operator, // This is an operator
Open, // (
Close, // )
Coma, // ,
End, // End of string
};
// Operators
enum TOperator
{
Not = 0, // !
Tilde, // ~
Mul, // *
Div, // /
Remainder, // %
Plus, // +
Minus, // -
ULeftShift, // <<
URightShift, // >>
SLeftShift, // <-
SRightShift, // ->
Inferior, // <
InferiorEqual, // <=
Superior, // >
SuperiorEqual, // >=
Equal, // ==
NotEqual, // !=
And, // &
Or, // |
Xor, // ^
LogicalAnd, // &&
LogicalOr, // ||
LogicalXor, // ^^
OperatorCount, //
NotOperator, // This is not an operator
ExtOperator, // This is a 2 characters operator
};
// Functions
enum TReservedWord
{
Abs = 0,
Acos,
Asin,
Atan,
Atan2,
Ceil,
Cos,
Cosh,
Exp,
Exponent,
Floor,
Int,
Log,
Log10,
Mantissa,
Max,
Min,
Pow,
Rand,
Round,
Sin,
Sinh,
Sq,
Sqrt,
Tan,
Tanh,
ReservedWordCount,
};
// Some constant
enum
{
InternalStringLen = 32,
InternalOperator = 4,
};
/// Members
TReturnState _State; // Current state
const char *_ExprPtr; // Current pointer on the expression
/// Read a decimal double
TReturnState readDecimal (double &value);
/// Read an integer
void readIntegerNumberDecimal (double &value);
/// Internal functions
/// Get the next token
TReturnState getNextToken (TToken &token);
/// Evaluate an expression
TReturnState evalExpression (double &result, TToken &nextToken, uint32 userData);
/// Reserved word
TReservedWord _ReservedWordFound;
/// Current string
char _InternalString[InternalStringLen];
std::string _InternalStlString;
const char *_InternalStringPtr;
/// Current value
double _Value;
/// Current operator
TOperator _Op;
/// Static values
/// Char to operator array
static const TToken _ReservedWordToken[ReservedWordCount];
static const char *_ReservedWord[ReservedWordCount];
static const TOperator _OperatorArray[128];
static const bool _StringChar[128];
static const char *_ErrorString[ReturnValueCount];
static const int _OperatorPrecedence[];
public:
bool internalCheck ();
};
}
#endif // NL_EVAL_NUM_EXPR_H