Expr Class Reference

#include <expr.h>

Class Description

See also
Class Point3, Expression Types, Expression Variable Types, Expression Return Codes, Guidelines for Handling Character Strings.

Description:
This class may be used by developers to parse mathematical expressions. The expression is created as a character string using a straightforward syntax. Expressions consist of operators (+, -, *, /, etc.), literal constants (numbers like 180, 2.718, etc.), variables (single floating point values or vector (Point3) values), and functions (mathematical functions that take one ore more arguments and return a result). The return value from the expression may be a floating point value or a vector. There are many built in functions, operators and constants available for use.

All methods of this class are implemented by the system.

Developers wishing to use these APIs should #include /MAXSDK/INCLUDE/EXPRLIB.H and should link to /MAXSDK/LIB/EXPR.LIB.

Sample code using these APIs is shown below, and is also available as part of the expression controller in /MAXSDK/SAMPLES/CONTROLLERS/EXPRCTRL.CPP.

Variables may be defined and used in expressions. Variable names are case sensitive, and must begin with a letter of the alphabet, but may include numbers. They may be any length. To create a named variable, you use the method defVar(). This takes a name and returns a register number. Defining the variable creates storage space in a list of variables maintained by the parser, and the register number is used as an array index into the variable value arrays passed into the expression evaluation method (eval()).

To use the variable in an expression just use its name. For example if you define a variable named radius, you can use it in an expression like: 2*pi*radius. To give the variable a value, you define two arrays of variables and pass them to the evaluation method (eval()). There is one array for scalar variables, and one for vector variables. You pass these arrays along with the number of variables in each list. See the sample code below for an example.

The order of calling the methods of this class to evaluate an expression is as follows:

Declare an expression instance (Expr expr;)

Define the expression (char e1[] = "2*pi*radius";).

Define any variables (expr.defVar(SCALAR_VAR, _M("radius"));)

Load the expression (expr.load(e1);)

Evaluate the expression (expr.eval(...);)

There are no restrictions on the use of white space in expressions – it may be used freely to make expressions more readable. In certain instances, white space should be used to ensure non-ambiguous parsing. For example, the x operator is used for to compute the cross product of two vectors. If a developer has several vectors: Vec, Axis and xAxis and wanted to compute the cross product, VecxAxis is ambiguous while Vec x Axis is not.

All the necessary information to evaluate an expression is completely stored within an expression object. For example, if you are passed a pointer to an expression object for which some variables have been defined that you knew the value of, you could get all the information you needed from the expression object to completely evaluate the expression. This includes the expression string, variable names, variable types, and variable register indices.

For complete documentation of the built in functions please refer to the 3ds Max User's Guide under Using Expression Controllers. Below is an overview of the operators, constants and functions that are available:
Expression Operators:
Scalar Operators

Operator Use Meaning

+ p+q addition

- p-q subtraction

- -p additive inverse

* p*q multiplication

/ p/q division

^ p^q power (p to the power of q)

** p**q same as p^q

Boolean Operators

= p=q equal to

< p<q less than

> p>q greater than

<= p<=q less than or equal to

>= p>=q greater than or equal to

| p|q logical OR

& p&q logical AND

Vector Operators

+ V+W addition

- V-W subtraction

* p*V scalar multiplication

V*p "

* V*W dot product

x VxW cross product

/ V/p scalar division

. V.x first component (X)

. V.y second component (Y)

. V.z third component (Z)
Built-In Constants:
pi 3.1415...

e 2.7182...

TPS 4800 (ticks per second)
Expression Functions:
Trigonometric Functions

The angles are specified and returned in degrees.

sin(p) sine

cos(p) cosine

tan(p) tangent

asin(p) arc sine

acos(p) arc cosine

atan(p) arc tangent

Hyperbolic Functions

sinh(p) hyperbolic sine

cosh(p) hyperbolic cosine

tanh(p) hyperbolic tangent

Conversion between Radians and Degrees

radToDeg(p) takes p in radians and returns the same angle in degrees

degToRad(p) takes p in degrees and returns the same angle in radians

Rounding Functions

ceil(p) smallest integer greater than or equal to p.

floor(p) largest integer less than or equal to p.

Standard Calculations

ln(p) natural (base e) logarithm

log(p) common (base 10) logarithm

exp(p) exponential function – exp(e) = e^p

pow(p, q) p to the power of q – p^q

sqrt(p) square root

abs(p) absolute value

min(p, q) minimum – returns p or q depending on which is smaller

max(p, q) maximum – returns p or q depending on which is larger

mod(p, q) remainder of p divided by q

Conditional

if (p, q, r) works like the common spreadsheet "if" – if p is nonzero

then "if" returns q, otherwise r.

Vector Handling

length(V) the length of V

unit(V) returns a unit vector in the same direction as V.

comp(V, I) i-th component, where I=0, 1, or 2.

comp([5,6,7],1) = 6

Special Animation Functions

noise(p, q, r) 3D noise – returns a randomly generated position.

p, q, and r are random values used as a seed.
Sample Code:
The following code shows how the expression parser can be used. This code evaluates several expressions and displays the results in a dialog box. Both scalar and vector variables are used. One expression contains an error to show how error handling is done.

void Utility::TestExpr()
{
// Declare an expression instance and variable storage
Expr expr;
float sRegs[2]; // Must be at least getVarCount(SCALAR_VAR);
Point3 vRegs[2]; // Must be at least getVarCount(VECTOR_VAR);
float ans[3];
int status;
// Define a few expressions
char e0[] = "2+2";
char e1[] = "2.0 * pi * radius";
char e2[] = "[1,1,0] + axis";
char e3[] = "[sin(90.0), sin(radToDeg(0.5*pi)), axis.z]";
char e4[] = "2+2*!@#$%"; // Bad expression
// Define variables
int radiusReg = expr.defVar(SCALAR_VAR, _M("radius"));
int axisReg = expr.defVar(VECTOR_VAR, _M("axis"));
// Set the variable values
sRegs[radiusReg] = 50.0f;
vRegs[axisReg] = Point3(0.0f, 0.0f, 1.0f);
// Get the number of each we have defined so far
int sCount = expr.getVarCount(SCALAR_VAR);
int vCount = expr.getVarCount(VECTOR_VAR);
// Load and evaluate expression "e0"
if (status = expr.load(e0))
HandleLoadError(status, expr);
else {
status = expr.eval(ans, sCount, sRegs, vCount, vRegs);
if (status != EXPR_NORMAL)
HandleEvalError(status, expr);
else
DisplayExprResult(expr, ans);
}
// Load and evaluate expression "e1"
if (status = expr.load(e1))
HandleLoadError(status, expr);
else {
status = expr.eval(ans, sCount, sRegs, vCount, vRegs);
if (status != EXPR_NORMAL)
HandleEvalError(status, expr);
else
DisplayExprResult(expr, ans);
}
// Load and evaluate expression "e2"
if (status = expr.load(e2))
HandleLoadError(status, expr);
else {
status = expr.eval(ans, sCount, sRegs, vCount, vRegs);
if (status != EXPR_NORMAL)
HandleEvalError(status, expr);
else
DisplayExprResult(expr, ans);
}
// Load and evaluate expression "e3"
if (status = expr.load(e3))
HandleLoadError(status, expr);
else {
status = expr.eval(ans, sCount, sRegs, vCount, vRegs);
if (status != EXPR_NORMAL)
HandleEvalError(status, expr);
else
DisplayExprResult(expr, ans);
}
// Load and evaluate expression "e4"
if (status = expr.load(e4))
HandleLoadError(status, expr);
else {
status = expr.eval(ans, sCount, sRegs, vCount, vRegs);
if (status != EXPR_NORMAL)
HandleEvalError(status, expr);
else
DisplayExprResult(expr, ans);
}
}
// Display the expression and the result
void Utility::DisplayExprResult(Expr expr, float *ans)
{
MCHAR msg[128];
if (expr.getExprType() == SCALAR_EXPR) {
_stprintf(msg, _M("Answer to \"%s\" is %.1f"), expr.getExprStr(), *ans);
Message(msg, _M("Expression Result"));
}
else {
_stprintf(msg, _M("Answer to \"%s\" is [%.1f, %.1f, %.1f]"), expr.getExprStr(), ans[0], ans[1], ans[2]);
Message(msg, _M("Expression Result"));
}
}
// Display the load error message
void Utility::HandleLoadError(int status, Expr expr)
{
MCHAR msg[128];
if(status == EXPR_INST_OVERFLOW) {
_stprintf(_M("Inst stack overflow: %s"), expr.getProgressStr());
Message(msg, _M("Error"));
}
else if (status == EXPR_UNKNOWN_TOKEN) {
_stprintf(msg, _M("Unknown token: %s"), expr.getProgressStr());
Message(msg, _M("Error"));
}
else {
_stprintf(msg, _M("Cannot parse \"%s\". Error begins at last char of: %s"),
expr.getExprStr(), expr.getProgressStr());
Message(msg, _M("Error"));
}
}
// Display the evaluation error message
void Utility::HandleEvalError(int status, Expr expr)
{
MCHAR msg[128];
_stprintf(msg, _M("Can't parse expression \"%s\""), expr.getExprStr());
Message(msg, _M("Error"));
}
// Display the specified message and title in a dialog box
void Utility::Message(const MCHAR *msg, const MCHAR *title)
{
MessageBox(ip->GetMAXHWnd(), (LPCMSTR) msg, (LPCMSTR) title, MB_ICONINFORMATION|MB_OK);
}
+ Inheritance diagram for Expr:

Public Member Functions

 Expr ()
 
 ~Expr ()
 
DllExport int load (const MCHAR *s)
 
DllExport int eval (float *ans, int sRegCt, float *sRegs, int vRegCt=0, Point3 *vRegs=NULL)
 
int getExprType (void)
 
const MCHARgetExprStr (void)
 
const MCHARgetProgressStr (void)
 
DllExport int defVar (int type, const MCHAR *name)
 
DllExport int getVarCount (int type)
 
DllExport const MCHARgetVarName (int type, int i)
 
DllExport int getVarRegNum (int type, int i)
 
DllExport BOOL deleteAllVars ()
 
DllExport BOOL deleteVar (const MCHAR *name)
 
void setExprType (int type)
 
void pushInst (ExprFunc fn, float f)
 
void pushSVal (float f)
 
float popSVal ()
 
void pushVVal (Point3 &v)
 
Point3popVVal ()
 
int getSRegCt (void)
 
float getSReg (int index)
 
int getVRegCt (void)
 
Point3getVReg (int index)
 

Public Attributes

MaxSDK::Array< ExprVarvars
 

Friends

int yylex ()
 
int yyerror (char *)
 

Additional Inherited Members

- Static Public Member Functions inherited from MaxHeapOperators
static UtilExport voidoperator new (size_t size)
 Standard new operator used to allocate objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e)
 Standard new operator used to allocate objects if there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate objects that takes the type of memory, filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate arrays of objects. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport void operator delete (void *ptr)
 Standard delete operator used to deallocate an object If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an object If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an object that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, void *placement_ptr)
 Placement new operator. More...
 
static UtilExport void operator delete (void *ptr, void *placement_ptr)
 Placement delete operator. More...
 

Constructor & Destructor Documentation

Expr ( )
inline
Remarks
Constructor. Internal data structures are initialized as empty.
342 { sValStk = vValStk = instStk = nextScalar = nextVector = 0; }
~Expr ( )
inline
Remarks
Destructor. Any currently defined variables are deleted.
344 { deleteAllVars(); }
DllExport BOOL deleteAllVars()

Member Function Documentation

DllExport int load ( const MCHAR s)
Remarks
This method is used to load an expression for parsing. An error code is returned indicating if the expression was loaded. A successfully loaded expression is then ready for evaluation with the eval() method.
Parameters:
char *s

The expression to load.
Returns
See Expression Return Codes.
DllExport int eval ( float *  ans,
int  sRegCt,
float *  sRegs,
int  vRegCt = 0,
Point3 vRegs = NULL 
)
Remarks
This method is used to evaluate the expression loaded using load(). It returns either a scalar or vector result.
Parameters:
float *ans

The numeric result of the expression is returned here, i.e. the answer . For scalar values this is a pointer to a single float. For vector values, ans[0] is x, ans[1] = y, ans[2] = z. You can determine which type of result is returned using the method getExprType().

int sRegCt

The number of items in the sRegs array of scalar variables.

float *sRegs

Array of scalar variables.

int vRegCt=0

The number of items in the vRegs array of vector variables.

Point3 *vRegs=NULL

Array of vector variables.
Returns
See Expression Return Codes.
int getExprType ( void  )
inline
Remarks
Returns the type of expression. See Expression Types.
374 { return exprType; }
const MCHAR* getExprStr ( void  )
inline
Remarks
Returns a pointer to the currently loaded expression string.
377 { return origStr.data(); }
const wchar_t * data() const
const MCHAR* getProgressStr ( void  )
inline
Remarks
If there was an error parsing the expression, this method returns a string showing what portion of the expression was parsed before the error occurred.
381 { return progressStr.data(); }
const wchar_t * data() const
DllExport int defVar ( int  type,
const MCHAR name 
)
Remarks
Defines a named variable that may be used in an expression.
Parameters:
int type

The type of variable. See Expression Variable Types.

MCHAR *name

The name of the variable. This name must begin with a letter, may include numbers and may be any length.
Returns
The register number (into the sRegs or vRegs array passed to eval()) of the variable.
DllExport int getVarCount ( int  type)
Remarks
This method returns the number of variables defined of the specified type. When you call eval() on an expression, you must make sure that the variable arrays (sRegs and vRegs) are at least the size returned from this method.
Parameters:
int type

See Expression Variable Types.
DllExport const MCHAR* getVarName ( int  type,
int  i 
)
Remarks
Returns the name of the variable whose index is passed, or NULL if the variable could not be found.
Parameters:
int type

The type the variable. See Expression Variable Types.

int i

The register number of the variable.
DllExport int getVarRegNum ( int  type,
int  i 
)
Remarks
When you define a variable with defVar(), you get a back a register number. If your code is set up in such a way that saving that register number is not convenient in the block of code that defines it, you can use this method later on to find out what that return value had been. For example, one piece of code might have:

expr->defVar(SCALAR_VAR, "a"); // not saving return value...

expr->defVar(SCALAR_VAR, "b");

and then right before evaluating the expression, you might have some code such as:

for(i = 0; i < expr->getVarCount(SCALAR_VAR); i++)

if(_tcscmp("a", expr->getVarName(SCALAR_VAR, i) == 0)

aRegNum = expr->getVarRegNum(SCALAR_VAR, i);

Of course, this is a bit contrived – most real examples would probably have tables to store the variable names, register numbers, etc. and thus would not need to call this method. It is available however, and this makes the expression object self-contained in that everything you need to evaluate an expression with variables (other than the variable values themselves) is stored by the expression object.
Parameters:
int type

See Expression Variable Types.

int i

The variable index returned from the method defVar().
Returns
The register index for the variable whose type and index are passed.
DllExport BOOL deleteAllVars ( )
Remarks
Deletes all the variables from the list maintained by the expression.
Returns
TRUE if the variables were deleted; otherwise FALSE.
DllExport BOOL deleteVar ( const MCHAR name)
Remarks
Deletes the variable whose name is passed from the list maintained by the expression. Register numbers never get reassigned, even if a variable gets deleted. For example, if you delete variables 0-9, and keep variable 10, you're going to need to pass in an array of size at least 11 to the eval() method, even though the first 10 slots are unused.
Parameters:
MCHAR *name

The name of the variable to delete.
Returns
TRUE if the variable was deleted; otherwise FALSE (the name was not found).
void setExprType ( int  type)
inline
451 { exprType = type; }
void pushInst ( ExprFunc  fn,
float  f 
)
inline
453  { if(instStk >= inst.Count()) inst.SetCount(instStk+30);
454  inst[instStk].func = fn; inst[instStk++].sVal = f; }
int Count() const
Retrieves the number of items in the Tab.
Definition: tab.h:219
void SetCount(int n, BOOL resize=TRUE)
Sets the number of used items.
Definition: tab.h:242
void pushSVal ( float  f)
inline
455 { if(sValStk>=sVal.Count())sVal.SetCount(sValStk+10);sVal[sValStk++]=f; }
int Count() const
Retrieves the number of items in the Tab.
Definition: tab.h:219
void SetCount(int n, BOOL resize=TRUE)
Sets the number of used items.
Definition: tab.h:242
float popSVal ( )
inline
456 { return sVal[--sValStk]; }
void pushVVal ( Point3 v)
inline
457 { if(vValStk>=vVal.Count())vVal.SetCount(vValStk+10);vVal[vValStk++]=v; }
int Count() const
Retrieves the number of items in the Tab.
Definition: tab.h:219
void SetCount(int n, BOOL resize=TRUE)
Sets the number of used items.
Definition: tab.h:242
Point3& popVVal ( )
inline
458 { return vVal[--vValStk]; }
int getSRegCt ( void  )
inline
459 { return sRegCt; }
float getSReg ( int  index)
inline
460 { return sRegPtr[index]; }
int getVRegCt ( void  )
inline
461 { return vRegCt; }
Point3& getVReg ( int  index)
inline
462 { return vRegPtr[index]; }

Friends And Related Function Documentation

int yylex ( )
friend
int yyerror ( char *  )
friend

Member Data Documentation