added: expreval third party library

this is a library to perform analytic function evaluation

git-svn-id: http://svn.sintef.no/trondheim/IFEM/trunk@1335 e10b68d5-8a6e-419e-a041-bce267b0401d
This commit is contained in:
kmo 2011-12-08 13:18:01 +00:00 committed by Knut Morten Okstad
parent 9ddf27e7ff
commit 1d3cfbfacf
18 changed files with 5522 additions and 0 deletions

26
3rdparty/expreval/defs.h vendored Normal file
View File

@ -0,0 +1,26 @@
// File: defs.h
// Author: Brian Vanderburg II
// Purpose: Definitions for ExprEval
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_DEFS_H
#define __EXPREVAL_DEFS_H
namespace ExprEval
{
// constants
const double EXPREVAL_PI = 3.14159265358979323846;
const double EXPREVAL_E = 2.7182818284590452354;
} // namespace ExprEval
// CHANGED from original code: due to auto_ptr deprecation in c++0x
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#define aptr(x) std::unique_ptr<x>
#else
#define aptr(x) std::auto_ptr<x>
#endif
#endif // __EXPREVAL_DEFS_H

33
3rdparty/expreval/docs/changes.txt vendored Normal file
View File

@ -0,0 +1,33 @@
IFEM Hacks
----------
- Added a define in defs.h. auto_ptr is deprecated in c++0x. uses
std::unique_ptr instead. Quells the warnings
ExprEval 3.6
------------
- Removed support for arbitrary data objects. It seemed unused anyhow.
- Fixed locale handling. It can now parse expressions correctly no matter
what locale the program is in.
ExprEval 3.3
------------
- Added support for arbitrary data objects to be passed to functions
with the '@' operator. The expression library itself does not have
any understanding of the arbitrary data, but the functions can.
ExprEval 3.2
------------
- Added Exception::GetType method to determine the type of error
without needing many catch statements.
ExprEval 3.1
------------
- Removed Exception::what due to language problems. Each application should
do testing and report the exception to the user itself, in whatever language
it needs.
- Added Exception::GetStart and Exception::GetEnd to report where in the
expression string the error occurs when parsing.
- Added Exception::GetValue to get the name of the object, function, etc
that is responsible for an exception, depending on the exception itself
- In header files, replaced 'std::X' with '::std::X'

771
3rdparty/expreval/docs/expreval.txt vendored Normal file
View File

@ -0,0 +1,771 @@
ExprEval 3.x Help
-----------------
Introduction
------------
ExprEval 3.x is an expression evaluation library for C++. It can take an
expression string, parse it, and evaluate it. Several key features of ExprEval
include:
- Object Oriented. ExprEval 3.x is a C++ library, where 2.x was a C library.
- POEM (Parse Once, Evaluate Many), the expression string is parsed on time.
After that, it can be evaluated over and over many times.
- Seperation of objects. By keeping the function and value lists seperate from
the expression, the programmer can choose how to connect them. Each
expression may have a private value list, or several expressions can share
a single value list.
- Fast variable lookup. The variables and constants are stored as pointers in
the parsed expression. This means there is no need to search through a list
for the value. Additionally, applications can do the same.
- Custom functions. An application can create custom functions for use by an
expression. Doing so is easy.
- Variable constants. As the name suggests, a constant that is variable. The
expression can NOT change a constant, but the application can.
Syntax
------
Expression syntax is similar to what it may look like written on paper. The
operators '+', '-', '*', '/', and '^', are the addition, subtraction,
multiplication, division, and exponent operators and the '=' operator is used to
assign to a variable.
k = (x * x) + (y * y)
is the same as
k = x ^ 2 + y ^ 2
Parentheses are used to group items in an expression and for the
arguments to a function.
d = sqrt((x * x) + (y * y))
Semicolons are used to seperate expressions. In this way, an expresion string
can contain more than one expression. The result is the value of the last
expression.
x = r * cos(d); y = r * sin(d)
Functions can take normal arguments and reference arguments. Functions that
take reference arguments can modify the reference variable. Constants can NOT
be passed by reference. Also, normal and reference arguments can be mixed, as
long as the order is the same. Commas(',') at a parentheses level of 0 are used
to seperate the arguments. Reference parameters must be prefixed with an
ampersand('&').
f(x, y, z, &a, &b, &c)
is the same as
f(x, &a, y, &b, z, &c)
Anything that is a sub-expression is still an expression, and can be anything
that an expression can be.
y = x = 0
x = r * cos(r1 ; r2) ; y = (z ; r) * cos(r1 + sin(r2) ; r2)
Order of Operators
------------------
Within an expression, the order of operators is as follows.
1. Parentheses
2. Exponents, left to right
3. Negation, right to left
4. Multiplication/division, left to right
5. Addition/subtration, left to right
6. Assignment, right to left
The entire expression is actually parsed as a tree. This expression will look
a little like this: (view with a fixed-width font)
y = q = x + -z^-2^3 - 5 * (x + 2) * sin(x)
assign(y)
|
assign(q)
|
subtract
________________/ \_____________
/ \
add multiply
___/ \___ _____/ \_____
/ \ / \
variable(x) negate multiply function(sin)
| __/ \___ |
power / \ variable(x)
__/ \___ value(5) add
/ \ ____/ \_____
power value(3) / \
___/ \___ variable(x) value(2)
/ \
variable(z) negate
|
value(2)
Using ExprEval
--------------
To use ExprEval, just include 'expreval.h' in your program. All the items are
under the 'ExprEval' namespace:
#include "expreval.h"
using namespace ExprEval;
using namespace std;
Then, create the value and function lists, and initialize them as desired.
ValueList vlist;
FunctionLIst flist;
vlist.AddDefaultValues();
flist.AddDefaultFunctions();
Finally, create the expression and set it to use the values and functions.
Expression e;
e.SetValueList(&vlist);
e.SetFunctionList(&flist);
Now the expression is ready to be parsed and evaluated.
e.Parse("y=5");
result = e.Evaluate();
User Abort
----------
It is possible that an evaluation can take a long amount of time or enter an
infinite loop, depending on the functions used and the expression. To help
with this, an abort mechanism is introduced. Every time 'Node::Evaluate' gets
called, it calls 'Expression::TestAbort', and then 'Node::DoEvaluate'. Every so
often, 'Expression::TestAbort' will call 'Expression::DoTestAbort'. If
'Expression::DoTestAbort' returns true, and exception is thrown indicating an
abort.
The reason a real test is not conducted each time by 'Expression::TestAbort' is
that it can dramatically slow down the expression evaluation, depending how an
abort is tested. 'Expression::SetTestAbortCount' controlls how many times
'Node::Evaluate' (and therefore 'Expression::TestAbort') gets called before a
real abort is tested by 'Expression::DoTestAbort'.
To add abort testing support, derive a new expression object and override
'Expression::DoTestAbort' as follows:
class MyExpression : public Expression
{
public:
MyExpression(bool *abort) { m_abort = abort; }
bool DoTestAbort() { return *m_abort; }
private:
bool *m_abort;
};
User Data
---------
If custom function need to access user data associated with an expression,
derive a class from the expression object that stores the user data. Then,
access the expression from the function node by using the protected 'm_expr'.
class MyExpression : public Expression
{
public:
MyExpression(void *userdata);
};
class MyFunctionNode : public FunctionNode
{
public:
...
double DoEvaluate() { MyExpression *m = (MyExpression*)m_expr; ... }
};
Identifiers
-----------
Functions, variables, and constants are accessed in the expression as
identifiers. These identifiers follow a certain form by the parser:
- An identifier may consist of multiple parts, each seperated by a period('.')
- An identifier does not end in a period('.')
- Each part begins with a letter or underscore('_'), and may contain letters,
digits, or underscores('_').
The parser recognizes the above as identifiers in an expression. However, no
check is made when an application adds a function or value to the lists. It is
up to the application to make sure it is named correct.
The following are valid identifiers:
color1
color1.red
color2._rgb._red
_x
The following are invalid identifiers
1color
color.4
Value Lists
-----------
Value lists store the constants and values that are used by an expression.
A value list is associated with an expression by using 'Expression::SetValueList'
Once an expression is parsed, the expression tree stores pointers directly to
the values, and so the value list should not be freed while it is in use.
To add values to the list, use 'Add'. You can also specify the
default values and if it is a constant.
vlist.Add("x");
vlist.Add("found", 1.0);
vlist.Add("PI", 3.14159, true);
You can also add external values to the list as follows.
double x, f, p;
vlist.AddAddress("x", &x);
vlist.AddAddress("f", &f, 2.2);
vlist.AddAddress("p", &p, 3.14, true);
Sometimes a compiler may optimize code in such a way that problems occur. For
instance, the expression can change the values 'x' and 'f' above, but the code
below may get optimized:
x = 1;
f = 2.2;
for(...)
{
for(...)
{
e.Evaluate();
Use(x, f);
}
}
Since it does not appear that 'x' and 'f' are being modified inside the loop,
especially in deeply nested loops, the compiler may optimize it by loading the
values outside the loop and using the cached values in the loop. If the
expression changes the values, they will not be used, but the cached values
will be. This is just a problem I have encounted a few times. To solve this
problem, change their declarations to be volatile:
volatile double x, f, p;
vlist.AddAddress("x", (double*)&x);
vlist.AddAddress("f", (double*)&f, 2.2);
vlist.AddAddress("p", (double*)&p, 3.14, true);
Like this, the compiler must reload the variables from memory each time they
are accessed.
If you use internal storage, you can still get the address of the values and
directly manipulate them as such:
double *x;
vlist.Add("x");
x = vlist.GetAddress("x");
for(...)
{
*x = some_value;
e.Evaluate();
...
}
To initialize default values into the list, use 'AddDefaultValues':
vlist.AddDefaultValues();
vlist.Add("x");
vlist.Add("y");
...
When you want to reset all items to their default values, you can call 'Reset'.
This will reset internal and external values. Constants will also be reset
because, even though an expression can not modify a constant, the application
can.
vlist.Reset();
You can also clear all items from the list. Do this ONLY when the expression
will not be evaluated again or will be reparsed before evaluating, because the
expression stores pointers directly to the values, and evaluating the expression
if the list is cleared will likely cause an access violation. External values
will not be deleted or removed, but the list entry associated with it will be.
vlist.Clear();
e.Parse(...);
Finally, you can save the state of the value list by enumerating the values:
ValueList::size_type p, c;
c = vlist.Count();
for(p = 0; p < c; p++)
{
string name;
double value;
vlist.Item(p, &name, &value);
...
}
You can later use this to restore the list. Remember, when adding a value to
the list, if it already exists, an exception will the be thrown.
Function Lists
--------------
Function lists store the function factories for the expression. A function
factory create a function node when needed, and also reports the name used.
To create a custom function, first derive a custom function node from
'FunctionNode'.
class MyFunctionNode : public FunctionNode
{
public:
MyFunctionNode(Expression *expr);
double DoEvaluate();
};
Set the argument count in the constructor. The first two arguments control
the number of normal paramters, the second control the number of reference
parameters. A value of -1 is used for any number.
MyFunctionNode::MyFunctionNode(Expression *expr) : FunctionNode(expr)
{
SetArgumentCount(
0, // Minimum normal parameters
2, // Maximum normal parameters
2, // Minimum reference parameters
-1); // Maximum reference parameters
}
Evaluate a function by overriding 'DoEvaluate'. You can access the normal
parameters in 'm_nodes' and the reference parameters in 'm_refs' as follows.
When evaluating a node, call 'Evaluate' and NOT 'DoEvaluate'.
double MyFunctionNode::DoEvaluate()
{
*m_refs[0] = m_nodes[0]->Evalute();
return m_nodes[1]->Evaluate();
}
It is up to each function solver how to access and do the job. If you need to
iterate over the items, the types are defined as follows:
std::vector<Node*> - For normal argumnents
std::vector<double*> - For reference arguments
After a function node is created, a function factory must be created to produce
the function node:
class MyFunctionFactory : public FunctionFactory
{
public:
std::string GetName() const;
FunctionNode *DoCreate(Expression *expr);
};
std::string MyFunctionFactory::GetName() const
{
return "myfunction";
}
FunctionNode *MyFunctionFactory::DoCreate(Expression *expr)
{
return new MyFunctionNode(expr);
}
Finally, the function node needs to be added to function list:
flist.Add(new MyFunctionFactory());
To be exception safe, you can also do this:
auto_ptr<FunctionFactory> p(new MyFunctionFactory());
flist.Add(p.get());
p.release();
This way, if 'Add' throws an exception, the function factory will still
be deleted.
The library includes many internal functions. These can be initialized directly
into the list:
flist.AddDefaultFunctions();
And finally, you can clear the list if you want to. The list is automatically
cleared when it is destroyed.
flist.Clear();
Expressions
-----------
The expression is what is used to actually parse and evaluate. After the
function and value lists are created, they can be associated with an expression:
Expression e;
e.SetValueList(&vlist);
e.SetFunctionList(&flist);
e.SetDataList(&dlist);
An expression can be parsed and used over and over:
e.Parse(...);
for(...)
{
result = e.Evaluate();
}
An expression can be parsed again, it is automatically cleared each time.
'Clear' can be called if desired to clear the expression without reparsing or
destroying it.
e.Parse(...);
for(...)
{
result = e.Evaluate();
}
e.Parse(...); // Automatically clears
for(...)
{
...
}
e.Clear(); // Clear expression, maybe to free memory, without destroying it
Exceptions
----------
Exceptions are thrown to indicate a problem. The problem may or may not be
an error, depending on the exception, and the application.
Most exceptions are defined by ExprEval, but some exceptions may occur from
C++. The most likely exception to get from C++ is 'bad_alloc' if memory
allocation fails.
ExprEval defines a base exception class 'Exception', which is derived from
'std::exception'. All other ExprEval exceptiosn derive from it.
Exception
Base ExprEval exception, derived from 'std::exception'. A 'GetValue'
method returns the string of where the exception came from, depending
on the exception type.
For some exceptions generated during parsing, A 'GetStart' and 'GetEnd'
method return the position in the expression string of the start and
end of the error.
NotFoundException (parsing)
Thrown when a function is not found. It is also thrown when a value
identifer can not be found in a value list and can not be added to the
list during a parse, but this will usually not happen because if it
can not be added to the list, a 'bad_alloc' will usually be the reason.
'ValueList::GetAddress' does not throw this.
AlreadyExistsException
A name being added to a function or value list already exists.
NullPointerException
A null pointer was passed to a function that should not be null.
MathException (evaluation)
A math error occured during an evaluation.
DivideByZeroException (evaluation)
A division by zero was attempted during evaluation.
NoValueListException (parsing)
An expression is trying to use a value identifier, but no value list
is associated with it.
NoFunctionListException (parsing)
An expression is trying to use a function identifier, but no value list
is associated with it.
AbortException (evaluation)
'Expression::DoTestAbort' returned true.
EmptyExpressionException (parsing, evaluation)
At parse time, there is no expression. At evaluation time, the expression
is not parsed.
UnknownTokenException (parsing)
An unknown token was encounted.
InvalidArgumentCountException (parsing, evaluation)
An invalid count of arguments was passed to a function. At parse time, this
is controlled by 'FunctionNode::SetArgumentCount'. Some functions may take
various parameter counts depending on a situation, and may throw this at
evaluation time.
ConstantAssignException (parsing)
An attempt to assign to a constant occured.
ConstantReferenceException (parsing)
An attempt to pass a constant to a function by reference occured.
SyntaxException (parsing)
A general syntax exception occured
UnmatchedParenthesisException (parsing)
The parenthesis are unmatched or missing the opening or closing parenthesis.
Tricks
------
A single value list can be shared by more than one expression. In this way, each
expression shares all values of that list:
ValueList vlist;
Expression e1, e2;
e1.SetValueList(&vlist);
e2.SetValueLIst(&vlist);
An external value can be shared by several value lists, and can be constant in
one and not in another:
double x;
ValueList v1, v2;
Expression e1, e2;
v1.AddAddress("x", &x);
v2.AddAddress("x", &x, 0.0, true);
e1.SetValueList(&v1);
e2.SetValueList(&v2);
An empty expression can be ignored:
Expression e1, e2;
bool eval2;
// Expression 1 must exist
e1.Parse(...);
// Expression 2 can be blank
eval2 = true;
try
{
e2.Parse(...);
}
catch(EmptyExpresionExceptin &e)
{
eval2 = false;
}
for(...)
{
e1.Evaluate();
if(eval2)
e2.Evaluate();
}
Internal Values
---------------
A call to 'ValueList::AddDefaultValues' will add the following values to a
value list:
PI
The value of PI, equal to 3.14159265358979323846
E
The value of e, equal to 2.7182818284590452354
Internal Functions
------------------
A call to 'FunctionList::AddDefaultFunctions' will add the following functions
to a function list:
abs(x)
Return the absolute value of 'x'
mod(x, y)
Return the remainder of 'x' divided by 'y'
ipart(x)
Return the interger portion of 'x'
fpart(x)
Return the fraction portion of 'x'
min(x, y, z, ...)
Return the value of the smallest parameter
max(x, y, z, ...)
Return the value of the largest parameter
sqrt(x)
Return the square root of 'x'
sin(x), cos(x), tan(x)
Return the sine, cosine, or tangent of 'x'
sinh(x), cosh(x), tanh(x)
Return the hyperbolic sine, cosine, or tangent of 'x'
asin(x), acos(x), atan(x)
Return the inverse since, cosine, or tangent of 'x'
atan(y, x)
Return the inverse tangent of 'y' divided by 'x', with the correct
angle for the quadrant of (x, y)
log(x)
Return the base 10 logarithm of 'x'
ln(x)
Return the natural logarithm of 'x'
exp(x)
Return the value of e raised to the power of 'x'
logn(x, y)
Return the base 'y' logarithm of 'x'
ceil(x)
Return the value of 'x' raised to the nearest integer
floor(x)
Return the value of 'x' dropped to the nearest integer
rand(&seed)
Return a random number from 0 to 1 inclusive. 'seed' is used to generate
the number and is changed for the next number.
random(min, max, &seed)
Return a random number from 'min' to 'max'
randomize(&seed)
Initialize the seed with a random value, based on the computer time and
the number of times randomize has been used.
deg(x)
Return 'x' radians converted to degrees
rad(x)
Return 'x' degrees converted to radians
rect2pol(x, y, &distance, &angle)
Convert rectangular coordinates 'x' and 'y' to polar coordinates and stores
the result in 'distance' and 'angle'. Returns distance.
pol2rect(distance, angle, &x, &y)
Convert polar coordinates 'distance' and 'angle' to rectangular coordinates
and stores the result in 'x' and 'y'. Returns x.
if(c, t, f)
If 'c' is not zero, evaluates and returns 't', otherwise evaluates and
returns 'f'. Only one of 't' or 'f' is evaluated.
select(c, n, z), select(c, n, z, p)
If 'c' is less than zero, evaluates and returns 'n'. If 'c' is zero,
evaluates and returns 'z'. If 'c' is greater than zero, evaluates and
returns 'z' for three arguments and 'p' for four arguments. Only one of
'n', 'z', or 'p' is evaluated.
equal(x, y)
Returns 1 if 'x' is equal to 'y', else returns 0
above(x, y)
Returns 1 if 'x' is greater than 'y', else returns 0
below(x, y)
Returns 1 if 'x' is less than 'y', else returns 0
clip(x, min, max)
Clips 'x' to the range 'min' and 'max'
clamp(x, min, max)
Clamps 'x' to the range 'min' and 'max', wrapping as needed
rescale(p, o1, o2, n1, n2)
Rescales a point 'p' from the range 'o1' - 'o2' to the range 'n1' - 'n2'
poly(x, ...)
Calculate the polynomial with the value of 'x' and given terms. The
right-most argument is the multiplier for the exponent of zero, and
increases to the left.
poly(4, 3, 5, 2, 8) is 3 * 4 ^ 3 + 5 * 4 ^ 2 + 2 * 4 ^ 1 + 8
and(x, y)
Returns 0 if 'x' or 'y' is 0, else returns 1
or(x, y)
Returns 0 if 'x' and 'y' is 0, else returns 1
not(x)
Returns 1 if 'x' is 0, else returns 0
More Information
----------------
For more information, view the source code for the library.

20
3rdparty/expreval/docs/license.txt vendored Normal file
View File

@ -0,0 +1,20 @@
ExprEval - Expression Evaluation Library
Version 3.x
Copyright (C) 2006 Brian Allen Vanderburg II
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

167
3rdparty/expreval/except.cpp vendored Normal file
View File

@ -0,0 +1,167 @@
// File: except.cpp
// Author: Brian Vanderburg II
// Purpose: ExprEval exceptions
//------------------------------------------------------------------------------
// Includes
#include "except.h"
using namespace std;
using namespace ExprEval;
// Default/unknown ExprEval exception
//------------------------------------------------------------------------------
Exception::Exception() :
m_start((string::size_type)-1),
m_end((string::size_type)-1)
{
m_type = Type_Exception;
}
Exception::~Exception() throw()
{
}
Exception::Type Exception::GetType() const
{
return m_type;
}
const string &Exception::GetValue() const
{
return m_value;
}
void Exception::SetStart(string::size_type start)
{
m_start = start;
}
void Exception::SetEnd(string::size_type end)
{
m_end = end;
}
string::size_type Exception::GetStart() const
{
return m_start;
}
string::size_type Exception::GetEnd() const
{
return m_end;
}
// Not found exception
//------------------------------------------------------------------------------
NotFoundException::NotFoundException(const string &name)
{
m_type = Type_NotFoundException;
m_value = name;
}
// Already exists exception
//------------------------------------------------------------------------------
AlreadyExistsException::AlreadyExistsException(const string &name)
{
m_type = Type_AlreadyExistsException;
m_value = name;
}
// Null pointer exception
//------------------------------------------------------------------------------
NullPointerException::NullPointerException(const string &method)
{
m_type = Type_NullPointerException;
m_value = method;
}
// Math error exception
//------------------------------------------------------------------------------
MathException::MathException(const string &function)
{
m_type = Type_MathException;
m_value = function;
}
// Divide by zero
//------------------------------------------------------------------------------
DivideByZeroException::DivideByZeroException()
{
m_type = Type_DivideByZeroException;
}
// No value list found during parsing
//------------------------------------------------------------------------------
NoValueListException::NoValueListException()
{
m_type = Type_NoValueListException;
}
// No function list found during parsing
//------------------------------------------------------------------------------
NoFunctionListException::NoFunctionListException()
{
m_type = Type_NoFunctionListException;
}
// Expression abort
//------------------------------------------------------------------------------
AbortException::AbortException()
{
m_type = Type_AbortException;
}
// Empty expression
//------------------------------------------------------------------------------
EmptyExpressionException::EmptyExpressionException()
{
m_type = Type_EmptyExpressionException;
}
// Unknown token found during parsing
//------------------------------------------------------------------------------
UnknownTokenException::UnknownTokenException()
{
m_type = Type_UnknownTokenException;
}
// Invalid argument count
//------------------------------------------------------------------------------
InvalidArgumentCountException::InvalidArgumentCountException(const string &function)
{
m_type = Type_InvalidArgumentCountException;
m_value = function;
}
// Assign to constant
//------------------------------------------------------------------------------
ConstantAssignException::ConstantAssignException(const string &value)
{
m_type = Type_ConstantAssignException;
m_value = value;
}
// Pass constant by reference
//------------------------------------------------------------------------------
ConstantReferenceException::ConstantReferenceException(const string &value)
{
m_type = Type_ConstantReferenceException;
m_value = value;
}
// Syntax error exception
//------------------------------------------------------------------------------
SyntaxException::SyntaxException()
{
m_type = Type_SyntaxException;
}
// Unmatched parenthesis
//------------------------------------------------------------------------------
UnmatchedParenthesisException::UnmatchedParenthesisException()
{
m_type = Type_UnmatchedParenthesisException;
}

189
3rdparty/expreval/except.h vendored Normal file
View File

@ -0,0 +1,189 @@
// File: except.h
// Author: Brian Vanderburg II
// Purpose: ExprEval exceptions
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_EXCEPT_H
#define __EXPREVAL_EXCEPT_H
// Includes
#include <exception>
#include <string>
// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class Expression;
// Exception class
//--------------------------------------------------------------------------
class Exception : public ::std::exception
{
public:
// Types of exceptions (to simplify some error handling)
// Each exception must set m_type in the construct
// Each exception should have a different type
enum Type
{
Type_Exception = 1,
Type_NotFoundException,
Type_AlreadyExistsException,
Type_NullPointerException,
Type_MathException,
Type_DivideByZeroException,
Type_NoValueListException,
Type_NoFunctionListException,
Type_AbortException,
Type_EmptyExpressionException,
Type_UnknownTokenException,
Type_InvalidArgumentCountException,
Type_ConstantAssignException,
Type_ConstantReferenceException,
Type_SyntaxException,
Type_UnmatchedParenthesisException
};
Exception();
virtual ~Exception() throw();
Type GetType() const;
const ::std::string &GetValue() const;
void SetStart(::std::string::size_type start);
void SetEnd(::std::string::size_type end);
::std::string::size_type GetStart() const;
::std::string::size_type GetEnd() const;
protected:
Type m_type;
::std::string m_value;
::std::string::size_type m_start, m_end;
};
// Not found exception (for functions)
//--------------------------------------------------------------------------
class NotFoundException : public Exception
{
public:
NotFoundException(const ::std::string &name);
};
// Already exists exception (function or value already exists)
//--------------------------------------------------------------------------
class AlreadyExistsException : public Exception
{
public:
AlreadyExistsException(const ::std::string &name);
};
// A null pointer was passed
//--------------------------------------------------------------------------
class NullPointerException : public Exception
{
public:
NullPointerException(const ::std::string &method);
};
// A bad math error occured
//--------------------------------------------------------------------------
class MathException : public Exception
{
public:
MathException(const ::std::string &function);
};
// Divide by zero exception
//--------------------------------------------------------------------------
class DivideByZeroException : public Exception
{
public:
DivideByZeroException();
};
// No value list exception (if expression uses variables or constants
// but list does not exist) during parsing
//--------------------------------------------------------------------------
class NoValueListException : public Exception
{
public:
NoValueListException();
};
// No function list exception (if expression uses functions) during parsing
//--------------------------------------------------------------------------
class NoFunctionListException : public Exception
{
public:
NoFunctionListException();
};
// Abort exception (if DoTestAbort returns true)
//--------------------------------------------------------------------------
class AbortException : public Exception
{
public:
AbortException();
};
// Empty expression (for parsing or evaluation)
//--------------------------------------------------------------------------
class EmptyExpressionException : public Exception
{
public:
EmptyExpressionException();
};
// Unknown token in expression string
//--------------------------------------------------------------------------
class UnknownTokenException : public Exception
{
public:
UnknownTokenException();
};
// Invalid argument count to function
//--------------------------------------------------------------------------
class InvalidArgumentCountException : public Exception
{
public:
InvalidArgumentCountException(const ::std::string &function);
};
// Assign to a constant
//--------------------------------------------------------------------------
class ConstantAssignException : public Exception
{
public:
ConstantAssignException(const ::std::string &value);
};
// Pass constant by reference
//--------------------------------------------------------------------------
class ConstantReferenceException : public Exception
{
public:
ConstantReferenceException(const ::std::string &value);
};
// A general syntax exception
//--------------------------------------------------------------------------
class SyntaxException : public Exception
{
public:
SyntaxException();
};
// Unmatched parenthesis
//--------------------------------------------------------------------------
class UnmatchedParenthesisException : public Exception
{
public:
UnmatchedParenthesisException();
};
} // namespace ExprEval
#endif // __EXPREVAL_EXCEPT_H

141
3rdparty/expreval/expr.cpp vendored Normal file
View File

@ -0,0 +1,141 @@
// File: expr.cpp
// Author: Brian Vanderburg II
// Purpose: Expression object
//------------------------------------------------------------------------------
// Includes
#include <new>
#include <memory>
#include "defs.h"
#include "expr.h"
#include "parser.h"
#include "node.h"
#include "except.h"
using namespace std;
using namespace ExprEval;
// Expression object
//------------------------------------------------------------------------------
// Constructor
Expression::Expression() : m_vlist(0), m_flist(0), m_expr(0)
{
m_abortcount = 200000;
m_abortreset = 200000;
}
// Destructor
Expression::~Expression()
{
// Delete expression nodes
delete m_expr;
}
// Set value list
void Expression::SetValueList(ValueList *vlist)
{
m_vlist = vlist;
}
// Get value list
ValueList *Expression::GetValueList() const
{
return m_vlist;
}
// Set function list
void Expression::SetFunctionList(FunctionList *flist)
{
m_flist = flist;
}
// Get function list
FunctionList *Expression::GetFunctionList() const
{
return m_flist;
}
// Test for an abort
bool Expression::DoTestAbort()
{
// Derive a class to test abort
return false;
}
// Test for an abort
void Expression::TestAbort(bool force)
{
if(force)
{
// Test for an abort now
if(DoTestAbort())
{
throw(AbortException());
}
}
else
{
// Test only if abort count is 0
if(m_abortcount == 0)
{
// Reset count
m_abortcount = m_abortreset;
// Test abort
if(DoTestAbort())
{
throw(AbortException());
}
}
else
{
// Decrease abort count
m_abortcount--;
}
}
}
// Set test abort count
void Expression::SetTestAbortCount(unsigned long count)
{
m_abortreset = count;
if(m_abortcount > count)
m_abortcount = count;
}
// Parse expression
void Expression::Parse(const string &exstr)
{
// Clear the expression if needed
if(m_expr)
Clear();
// Create parser
aptr(Parser) p(new Parser(this));
// Parse the expression
m_expr = p->Parse(exstr);
}
// Clear the expression
void Expression::Clear()
{
delete m_expr;
m_expr = 0;
}
// Evaluate an expression
double Expression::Evaluate()
{
if(m_expr)
{
return m_expr->Evaluate();
}
else
{
throw(EmptyExpressionException());
}
}

63
3rdparty/expreval/expr.h vendored Normal file
View File

@ -0,0 +1,63 @@
// File: expr.h
// Author: Brian Vanderburg II
// Purpose: Expression object
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_EXPR_H
#define __EXPREVAL_EXPR_H
// Includes
#include <string>
// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class ValueList;
class FunctionList;
class Node;
// Expression class
//--------------------------------------------------------------------------
class Expression
{
public:
Expression();
virtual ~Expression();
// Variable list
void SetValueList(ValueList *vlist);
ValueList *GetValueList() const;
// Function list
void SetFunctionList(FunctionList *flist);
FunctionList *GetFunctionList() const;
// Abort control
virtual bool DoTestAbort();
void TestAbort(bool force = false);
void SetTestAbortCount(unsigned long count);
// Parse an expression
void Parse(const ::std::string &exstr);
// Clear an expression
void Clear();
// Evaluate expression
double Evaluate();
protected:
ValueList *m_vlist;
FunctionList *m_flist;
Node *m_expr;
unsigned long m_abortcount;
unsigned long m_abortreset;
};
} // namespace ExprEval
#endif // __EXPREVAL_EXPR_H

18
3rdparty/expreval/expreval.h vendored Normal file
View File

@ -0,0 +1,18 @@
// File: expreval.h
// Author: Brian Allen Vanderburg II
// Purpose: ExprEval 3.x main include file
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_EXPREVAL_H
#define __EXPREVAL_EXPREVAL_H
// Include items
#include "vallist.h"
#include "funclist.h"
#include "expr.h"
#include "node.h"
#include "parser.h"
#include "except.h"
#endif // __EXPREVAL_EXPREVAL_H

1644
3rdparty/expreval/func.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

113
3rdparty/expreval/funclist.cpp vendored Normal file
View File

@ -0,0 +1,113 @@
// File: funclist.cpp
// Author: Brian Vanderburg II
// Purpose: Function list
//------------------------------------------------------------------------------
// Includes
#include <new>
#include "funclist.h"
#include "except.h"
#include "node.h"
using namespace std;
using namespace ExprEval;
// Function factory
//------------------------------------------------------------------------------
// Constructor
FunctionFactory::FunctionFactory()
{
}
// Destructor
FunctionFactory::~FunctionFactory()
{
}
// Create
FunctionNode *FunctionFactory::Create(Expression *expr)
{
FunctionNode *n = DoCreate(expr);
if(n)
n->m_factory = this;
return n;
}
// Function list
//------------------------------------------------------------------------------
// Constructor
FunctionList::FunctionList()
{
}
// Destructor
FunctionList::~FunctionList()
{
// Free function factories
Clear();
}
// Add factory to list
void FunctionList::Add(FunctionFactory *factory)
{
// Check it
if(factory == 0)
throw(NullPointerException("FunctionList::Add"));
// Make sure it does not exist
size_type pos;
for(pos = 0; pos < m_functions.size(); pos++)
{
if(m_functions[pos]->GetName() == factory->GetName())
throw(AlreadyExistsException(factory->GetName()));
}
m_functions.push_back(factory);
}
// Create a node for a function
FunctionNode *FunctionList::Create(const string &name, Expression *expr)
{
// Make sure pointer exists
if(expr == 0)
throw(NullPointerException("FunctionList::Create"));
size_type pos;
for(pos = 0; pos < m_functions.size(); pos++)
{
if(m_functions[pos]->GetName() == name)
{
// Found it
return m_functions[pos]->Create(expr);
}
}
// Not found
return 0;
}
// FunctionList::AddDefaultFunctions is located in func.cpp
// along with the default function factories
// Free function list
void FunctionList::Clear()
{
size_type pos;
for(pos = 0; pos < m_functions.size(); pos++)
{
delete m_functions[pos];
}
}

64
3rdparty/expreval/funclist.h vendored Normal file
View File

@ -0,0 +1,64 @@
// File: funclist.h
// Author: Brian Vanderburg II
// Purpose: Function list
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_FUNCLIST_H
#define __EXPREVAL_FUNCLIST_H
// Includes
#include <string>
#include <vector>
// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class FunctionNode;
class Expression;
// Function factory
//--------------------------------------------------------------------------
class FunctionFactory
{
public:
FunctionFactory();
virtual ~FunctionFactory();
virtual ::std::string GetName() const = 0;
virtual FunctionNode *DoCreate(Expression *expr) = 0;
FunctionNode *Create(Expression *expr);
};
// Function list
//--------------------------------------------------------------------------
class FunctionList
{
public:
typedef ::std::vector<FunctionFactory*>::size_type size_type;
FunctionList();
~FunctionList();
// Add a function factory to the list
void Add(FunctionFactory *factory);
// Create a node for a function
FunctionNode *Create(const ::std::string &name, Expression *expr);
// Initialize default functions
void AddDefaultFunctions();
// Free items and clear memory
void Clear();
private:
::std::vector<FunctionFactory*> m_functions;
};
}
#endif // __EXPREVAL_FUNCLIST_H

863
3rdparty/expreval/node.cpp vendored Normal file
View File

@ -0,0 +1,863 @@
// File: node.cpp
// Author: Brian Vanderburg II
// Purpose: Expression node
//------------------------------------------------------------------------------
// Includes
#include <new>
#include <memory>
#include <cmath>
#include <cerrno>
#include "defs.h"
#include "node.h"
#include "expr.h"
#include "vallist.h"
#include "funclist.h"
#include "except.h"
using namespace std;
using namespace ExprEval;
// Node
//------------------------------------------------------------------------------
// Constructor
Node::Node(Expression *expr) : m_expr(expr)
{
if(expr == 0)
throw(NullPointerException("Node::Node"));
}
// Destructor
Node::~Node()
{
}
// Evaluate
double Node::Evaluate()
{
m_expr->TestAbort();
return DoEvaluate();
}
// Function node
//------------------------------------------------------------------------------
// Constructor
FunctionNode::FunctionNode(Expression *expr) : Node(expr),
m_argMin(0), m_argMax(0), m_refMin(0), m_refMax(0)
{
}
// Destructor
FunctionNode::~FunctionNode()
{
// Delete child nodes
vector<Node*>::size_type pos;
for(pos = 0; pos < m_nodes.size(); pos++)
{
delete m_nodes[pos];
}
}
// Get name
string FunctionNode::GetName() const
{
return m_factory->GetName();
}
// Set argument count
void FunctionNode::SetArgumentCount(long argMin, long argMax, long refMin, long refMax)
{
m_argMin = argMin;
m_argMax = argMax;
m_refMin = refMin;
m_refMax = refMax;
}
// Parse expression
void FunctionNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
Parser::size_type pos, last;
int plevel = 0;
// Sanity check (start/end are function parenthesis)
if(start >= end)
throw(SyntaxException());
// Look
last = start + 1;
for(pos = start + 1; pos <= end && start + 1 != end; pos++)
{
switch(parser[pos].GetType())
{
case Token::TypeOpenParenthesis:
{
plevel++;
break;
};
case Token::TypeComma:
case Token::TypeCloseParenthesis:
{
// Handle Close parenthesis for all but the last one at the end
if(parser[pos].GetType() == Token::TypeCloseParenthesis && pos != end)
{
plevel--;
if(plevel < 0)
{
UnmatchedParenthesisException e;
e.SetStart(parser[pos].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
break;
}
// Handle comma, or if it was the ending parenthesis treat it like comma
if(plevel == 0)
{
if(pos > last)
{
// reference parameter?
if(parser[last].GetType() == Token::TypeAmpersand)
{
// Reference parameter, check position and type of next parameter
if(last == pos - 2 && parser[last + 1].GetType() == Token::TypeIdentifier)
{
// Get value list
ValueList *vlist = m_expr->GetValueList();
if(vlist == 0)
{
NoValueListException e;
e.SetStart(parser[last + 1].GetStart());
e.SetEnd(parser[last + 1].GetEnd());
throw(e);
}
// Get name
string ident = parser[last + 1].GetIdentifier();
// Make sure it is not a constant
if(vlist->IsConstant(ident))
{
ConstantReferenceException e(ident);
e.SetStart(parser[last + 1].GetStart());
e.SetEnd(parser[last + 1].GetEnd());
throw(e);
}
// Get address
double *vaddr = vlist->GetAddress(ident);
if(vaddr == 0)
{
// Try to add it and get again
vlist->Add(ident);
vaddr = vlist->GetAddress(ident);
}
if(vaddr == 0)
{
NotFoundException e(ident);
e.SetStart(parser[last + 1].GetStart());
e.SetEnd(parser[last + 1].GetEnd());
throw(e);
}
// Add it
m_refs.push_back(vaddr);
}
else
{
SyntaxException e;
e.SetStart(parser[last].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
} // TypeAmpersand
else
{
// Create node
aptr(Node) n(parser.ParseRegion(last, pos - 1));
m_nodes.push_back(n.get());
n.release();
}
}
else
{
SyntaxException e;
e.SetStart(parser[pos].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
last = pos + 1;
}
break;
}
default:
break;
}
}
// plevel should be zero
if(plevel != 0)
{
UnmatchedParenthesisException e;
e.SetStart(parser[end].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Check argument count
if(m_argMin != -1 && m_nodes.size() < (vector<Node*>::size_type)m_argMin)
{
InvalidArgumentCountException e(GetName());
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
if(m_argMax != -1 && m_nodes.size() > (vector<Node*>::size_type)m_argMax)
{
InvalidArgumentCountException e(GetName());
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
if(m_refMin != -1 && m_refs.size() < (vector<double*>::size_type)m_refMin)
{
InvalidArgumentCountException e(GetName());
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
if(m_refMax != -1 && m_refs.size() > (vector<double*>::size_type)m_refMax)
{
InvalidArgumentCountException e(GetName());
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
}
// Multi node
//------------------------------------------------------------------------------
// Constructor
MultiNode::MultiNode(Expression *expr) : Node(expr)
{
}
// Destructor
MultiNode::~MultiNode()
{
// Free child nodes
vector<Node*>::size_type pos;
for(pos = 0; pos < m_nodes.size(); pos++)
{
delete m_nodes[pos];
}
}
// Evaluate
double MultiNode::DoEvaluate()
{
vector<Node*>::size_type pos;
double result = 0.0;
for(pos = 0; pos < m_nodes.size(); pos++)
{
result = m_nodes[pos]->Evaluate();
}
return result;
}
// Parse
void MultiNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
Parser::size_type pos, last;
int plevel = 0;
// Sanity check
if(start >= end)
throw(SyntaxException());
// Look
last = start;
for(pos = start; pos <= end; pos++)
{
switch(parser[pos].GetType())
{
case Token::TypeOpenParenthesis:
{
plevel++;
break;
};
case Token::TypeCloseParenthesis:
{
plevel--;
if(plevel < 0)
{
UnmatchedParenthesisException e;
e.SetStart(parser[pos].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
break;
}
case Token::TypeSemicolon:
{
if(plevel == 0)
{
if(pos > last)
{
// Everything from last to pos - 1
aptr(Node) n(parser.ParseRegion(last, pos - 1));
m_nodes.push_back(n.get());
n.release();
}
else
{
SyntaxException e;
e.SetStart(parser[last].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
last = pos + 1;
}
break;
}
default:
break;
}
}
// plevel should be zero
if(plevel != 0)
{
UnmatchedParenthesisException e;
e.SetStart(parser[pos].GetStart());
e.SetEnd(parser[pos].GetEnd());
throw(e);
}
// If the end was not a semicolon, test it as well
if(last < end + 1)
{
aptr(Node) n(parser.ParseRegion(last, end));
m_nodes.push_back(n.get());
n.release();
}
}
// Assign node
//------------------------------------------------------------------------------
// Constructor
AssignNode::AssignNode(Expression *expr) : Node(expr), m_var(0), m_rhs(0)
{
}
// Destructor
AssignNode::~AssignNode()
{
// Free child node
delete m_rhs;
}
// Evaluate
double AssignNode::DoEvaluate()
{
return (*m_var = m_rhs->Evaluate());
}
// Parse
void AssignNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 != start + 1 || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Get the value list
ValueList *vlist = m_expr->GetValueList();
if(vlist == 0)
{
NoValueListException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[start].GetEnd());
throw(e);
}
// Determine variable name
string ident = parser[start].GetIdentifier();
// Make sure it is not a constant
if(vlist->IsConstant(ident))
{
ConstantAssignException e(ident);
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[v1].GetEnd());
throw(e);
}
// Get address
double *vaddr = vlist->GetAddress(ident);
if(vaddr == 0)
{
// If it does not already exist, try to create it
vlist->Add(ident);
vaddr = vlist->GetAddress(ident);
}
if(vaddr == 0)
{
NotFoundException e(ident);
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[start].GetEnd());
throw(e);
}
// Parse the node (will throw if it can not parse)
aptr(Node) n(parser.ParseRegion(v1 + 1, end));
// Set data
m_var = vaddr;
m_rhs = n.release();
}
// Add node
//------------------------------------------------------------------------------
// Constructor
AddNode::AddNode(Expression *expr) : Node(expr), m_lhs(0), m_rhs(0)
{
}
// Destructor
AddNode::~AddNode()
{
// Free child nodes
delete m_lhs;
delete m_rhs;
}
// Evaluate
double AddNode::DoEvaluate()
{
return m_lhs->Evaluate() + m_rhs->Evaluate();
}
// Parse
void AddNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 <= start || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) left(parser.ParseRegion(start, v1 - 1));
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_lhs = left.release();
m_rhs = right.release();
}
// Subtract node
//------------------------------------------------------------------------------
// Constructor
SubtractNode::SubtractNode(Expression *expr) : Node(expr), m_lhs(0), m_rhs(0)
{
}
// Destructor
SubtractNode::~SubtractNode()
{
// Free child nodes
delete m_lhs;
delete m_rhs;
}
// Evaluate
double SubtractNode::DoEvaluate()
{
return m_lhs->Evaluate() - m_rhs->Evaluate();
}
// Parse
void SubtractNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 <= start || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) left(parser.ParseRegion(start, v1 - 1));
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_lhs = left.release();
m_rhs = right.release();
}
// Multiply node
//------------------------------------------------------------------------------
// Constructor
MultiplyNode::MultiplyNode(Expression *expr) : Node(expr), m_lhs(0), m_rhs(0)
{
}
// Destructor
MultiplyNode::~MultiplyNode()
{
// Free child nodes
delete m_lhs;
delete m_rhs;
}
// Evaluate
double MultiplyNode::DoEvaluate()
{
return m_lhs->Evaluate() * m_rhs->Evaluate();
}
// Parse
void MultiplyNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 <= start || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) left(parser.ParseRegion(start, v1 - 1));
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_lhs = left.release();
m_rhs = right.release();
}
// Divide node
//------------------------------------------------------------------------------
// Constructor
DivideNode::DivideNode(Expression *expr) : Node(expr), m_lhs(0), m_rhs(0)
{
}
// Destructor
DivideNode::~DivideNode()
{
// Free child nodes
delete m_lhs;
delete m_rhs;
}
// Evaluate
double DivideNode::DoEvaluate()
{
double r2 = m_rhs->Evaluate();
if(r2 != 0.0)
{
return m_lhs->Evaluate() / r2;
}
else
{
throw(DivideByZeroException());
}
}
// Parse
void DivideNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 <= start || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) left(parser.ParseRegion(start, v1 - 1));
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_lhs = left.release();
m_rhs = right.release();
}
// Negate node
//------------------------------------------------------------------------------
// Constructor
NegateNode::NegateNode(Expression *expr) : Node(expr), m_rhs(0)
{
}
// Destructor
NegateNode::~NegateNode()
{
// Free child nodes
delete m_rhs;
}
// Evaluate
double NegateNode::DoEvaluate()
{
return -(m_rhs->Evaluate());
}
// Parse
void NegateNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(start != v1 || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_rhs = right.release();
}
// Exponent node
//------------------------------------------------------------------------------
// Constructor
ExponentNode::ExponentNode(Expression *expr) : Node(expr), m_lhs(0), m_rhs(0)
{
}
// Destructor
ExponentNode::~ExponentNode()
{
// Free child nodes
delete m_lhs;
delete m_rhs;
}
// Evaluate
double ExponentNode::DoEvaluate()
{
errno = 0;
double result = pow(m_lhs->Evaluate(), m_rhs->Evaluate());
if(errno)
throw(MathException("^"));
return result;
}
// Parse
void ExponentNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(v1 <= start || v1 >= end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Parse sides
aptr(Node) left(parser.ParseRegion(start, v1 - 1));
aptr(Node) right(parser.ParseRegion(v1 + 1, end));
m_lhs = left.release();
m_rhs = right.release();
}
// Variable node
//------------------------------------------------------------------------------
// Constructor
VariableNode::VariableNode(Expression *expr) : Node(expr), m_var(0)
{
}
// Destructor
VariableNode::~VariableNode()
{
}
// Evaluate
double VariableNode::DoEvaluate()
{
return *m_var;
}
// Parse
void VariableNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check some basic syntax
if(start != end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Get value list
ValueList *vlist = m_expr->GetValueList();
if(vlist == 0)
{
NoValueListException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[start].GetEnd());
throw(e);
}
// Get name
string ident = parser[start].GetIdentifier();
// Get address
double *vaddr = vlist->GetAddress(ident);
if(vaddr == 0)
{
// If it does not already exist, try to create it
vlist->Add(ident);
vaddr = vlist->GetAddress(ident);
}
if(vaddr == 0)
{
NotFoundException e(ident);
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[start].GetEnd());
throw(e);
}
// Set information
m_var = vaddr;
}
// Value node
//------------------------------------------------------------------------------
// Constructor
ValueNode::ValueNode(Expression *expr) : Node(expr), m_val(0)
{
}
// Destructor
ValueNode::~ValueNode()
{
}
// Evaluate
double ValueNode::DoEvaluate()
{
return m_val;
}
// Parse
void ValueNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1)
{
// Check basic syntax
if(start != end)
{
SyntaxException e;
e.SetStart(parser[start].GetStart());
e.SetEnd(parser[end].GetEnd());
throw(e);
}
// Set info
m_val = parser[start].GetValue();
}

248
3rdparty/expreval/node.h vendored Normal file
View File

@ -0,0 +1,248 @@
// File: node.h
// Author: Brian Vanderburg II
// Purpose: Expression node
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_NODE_H
#define __EXPREVAL_NODE_H
// Includes
#include <vector>
#include "parser.h"
// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class Expression;
class FunctionFactory;
// Node class
//--------------------------------------------------------------------------
class Node
{
public:
Node(Expression *expr);
virtual ~Node();
virtual double DoEvaluate() = 0;
virtual void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0) = 0;
double Evaluate(); // Calls Expression::TestAbort, then DoEvaluate
protected:
Expression *m_expr;
};
// General function node class
//--------------------------------------------------------------------------
class FunctionNode : public Node
{
public:
FunctionNode(Expression *expr);
~FunctionNode();
// Parse nodes and references
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
// Function factory
FunctionFactory *m_factory;
// Argument count
long m_argMin;
long m_argMax;
long m_refMin;
long m_refMax;
protected:
// Set argument count (called in derived constructors)
void SetArgumentCount(long argMin = 0, long argMax = 0,
long refMin = 0, long refMax = 0);
// Function name (using factory)
::std::string GetName() const;
// Normal, reference, and data parameters
::std::vector<Node*> m_nodes;
::std::vector<double*> m_refs;
friend class FunctionFactory;
};
// Mulit-expression node
//--------------------------------------------------------------------------
class MultiNode : public Node
{
public:
MultiNode(Expression *expr);
~MultiNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
::std::vector<Node*> m_nodes;
};
// Assign node
//--------------------------------------------------------------------------
class AssignNode : public Node
{
public:
AssignNode(Expression *expr);
~AssignNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
double *m_var;
Node *m_rhs;
};
// Add node
//--------------------------------------------------------------------------
class AddNode : public Node
{
public:
AddNode(Expression *expr);
~AddNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_lhs;
Node *m_rhs;
};
// Subtract node
//--------------------------------------------------------------------------
class SubtractNode : public Node
{
public:
SubtractNode(Expression *expr);
~SubtractNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_lhs;
Node *m_rhs;
};
// Multiply node
//--------------------------------------------------------------------------
class MultiplyNode : public Node
{
public:
MultiplyNode(Expression *expr);
~MultiplyNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_lhs;
Node *m_rhs;
};
// Divide node
//--------------------------------------------------------------------------
class DivideNode : public Node
{
public:
DivideNode(Expression *expr);
~DivideNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_lhs;
Node *m_rhs;
};
// Negate node
//--------------------------------------------------------------------------
class NegateNode : public Node
{
public:
NegateNode(Expression *expr);
~NegateNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_rhs;
};
// Exponent node
//--------------------------------------------------------------------------
class ExponentNode : public Node
{
public:
ExponentNode(Expression *expr);
~ExponentNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
Node *m_lhs;
Node *m_rhs;
};
// Variable node (also used for constants)
//--------------------------------------------------------------------------
class VariableNode : public Node
{
public:
VariableNode(Expression *expr);
~VariableNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
double *m_var;
};
// Value node
//--------------------------------------------------------------------------
class ValueNode : public Node
{
public:
ValueNode(Expression *expr);
~ValueNode();
double DoEvaluate();
void Parse(Parser &parser, Parser::size_type start, Parser::size_type end,
Parser::size_type v1 = 0);
private:
double m_val;
};
} // namespace ExprEval
#endif // __EXPREVAL_NODE_H

774
3rdparty/expreval/parser.cpp vendored Normal file
View File

@ -0,0 +1,774 @@
// File: parser.cpp
// Author: Brian Vanderburg II
// Purpose: Parser object to help parse expression
//------------------------------------------------------------------------------
// Includes
#include <new>
#include <memory>
#include "defs.h"
#include "parser.h"
#include "node.h"
#include "except.h"
#include "funclist.h"
#include "expr.h"
using namespace std;
using namespace ExprEval;
// Private functions to solve locale problems
// ------------------------------------------
namespace
{
bool expreval_isalpha(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
bool expreval_isdigit(char c)
{
return (c >= '0' && c <= '9');
}
bool expreval_isalnum(char c)
{
return expreval_isalpha(c) || expreval_isdigit(c);
}
bool expreval_isspace(char c)
{
return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
}
double expreval_atof(const char* str)
{
bool negative = false;
long double value = 0.0;
// Skip space
while(expreval_isspace(*str))
str++;
// Check for sign
if(*str == '-')
{
negative = true;
str++;
}
else if(*str == '+')
{
str++;
}
// The part before the decimal
while(*str >= '0' && *str <= '9')
{
value = (value * 10.0) + (double)(*str - '0');
str++;
}
// Decimal, if any
if(*str == '.')
{
long double divisor = 1.0;
str++;
// Part after the decimal, if any
while(*str >= '0' && *str <= '9')
{
value = (value * 10.0) + (double)(*str - '0');
divisor *= 10.0;
str++;
}
value /= divisor;
}
// The result
return negative ? -value : value;
}
};
// Token
//------------------------------------------------------------------------------
// Constructor
Token::Token(TokenType type, string::size_type start, string::size_type end) :
m_type(type),
m_start(start),
m_end(end)
{
}
// Construct identifier token
Token::Token(const string &ident, string::size_type start, string::size_type end) :
m_type(Token::TypeIdentifier),
m_ident(ident),
m_start(start),
m_end(end)
{
}
// Construct value token
Token::Token(double value, string::size_type start, string::size_type end) :
m_type(Token::TypeValue),
m_value(value),
m_start(start),
m_end(end)
{
}
// Get type
Token::TokenType Token::GetType() const
{
return m_type;
}
// Get identifier
const string &Token::GetIdentifier() const
{
return m_ident;
}
// Get value
double Token::GetValue() const
{
return m_value;
}
// Get start
string::size_type Token::GetStart() const
{
return m_start;
}
string::size_type Token::GetEnd() const
{
return m_end;
}
// Parser
//------------------------------------------------------------------------------
// Constructor
Parser::Parser(Expression *expr) : m_expr(expr)
{
if(expr == 0)
throw(NullPointerException("Parser::Parser"));
}
// Destructor
Parser::~Parser()
{
}
// Parse an expression string
Node *Parser::Parse(const string &exstr)
{
BuildTokens(exstr);
// Make sure it is not still empty
if(m_tokens.size() == 0)
throw(EmptyExpressionException());
// Parse the range
return ParseRegion(0, m_tokens.size() - 1);
}
// Parse a region of tokens
Node *Parser::ParseRegion(Parser::size_type start, Parser::size_type end)
{
size_type pos;
size_type fgopen = (size_type)-1;
size_type fgclose = (size_type)-1;
size_type assignindex = (size_type)-1;
size_type addsubindex = (size_type)-1;
size_type muldivindex = (size_type)-1;
size_type posnegindex = (size_type)-1;
size_type expindex = (size_type)-1;
bool multiexpr = false;
int plevel = 0;
// Check simple syntax
if(start > end)
throw(SyntaxException());
// Scan through tokens
for(pos = start; pos <= end; pos++)
{
switch(m_tokens[pos].GetType())
{
case Token::TypeOpenParenthesis:
{
plevel++;
// Opening of first group?
if(plevel == 1 && fgopen == (size_type)-1)
fgopen = pos;
break;
};
case Token::TypeCloseParenthesis:
{
plevel--;
// First group closed?
if(plevel == 0 && fgclose == (size_type)-1)
fgclose = pos;
if(plevel < 0)
{
UnmatchedParenthesisException e;
e.SetStart(m_tokens[pos].GetStart());
e.SetEnd(m_tokens[pos].GetEnd());
throw(e);
}
break;
}
case Token::TypeEqual:
{
if(plevel == 0)
{
if(assignindex == (size_type)-1)
assignindex = pos;
}
break;
}
case Token::TypeAsterisk:
case Token::TypeForwardSlash:
{
if(plevel == 0)
{
muldivindex = pos;
}
break;
}
case Token::TypeHat:
{
if(plevel == 0)
{
expindex = pos;
}
break;
}
case Token::TypePlus:
case Token::TypeHyphen:
{
if(plevel == 0)
{
if(pos == start)
{
// Positive or negative sign
if(posnegindex == (size_type)-1)
posnegindex = pos;
}
else
{
// What is before us
switch(m_tokens[pos - 1].GetType())
{
case Token::TypeEqual:
case Token::TypePlus:
case Token::TypeHyphen:
case Token::TypeAsterisk:
case Token::TypeForwardSlash:
case Token::TypeHat:
// After any of these, we are a positive/negative
if(posnegindex == (size_type)-1)
posnegindex = pos;
break;
default:
// After any other, we are addition/subtration
addsubindex = pos;
break;
}
}
}
break;
}
case Token::TypeSemicolon:
{
if(plevel == 0)
{
multiexpr = true;
}
break;
}
default:
break;
}
}
// plevel should be 0
if(plevel != 0)
{
UnmatchedParenthesisException e;
e.SetStart(end);
e.SetEnd(end);
throw(e);
}
// Parse in certain order to maintain order of operators
// Multi-expression first
if(multiexpr)
{
aptr(Node) n(new MultiNode(m_expr));
n->Parse(*this, start, end);
return n.release();
}
else if(assignindex != (size_type)-1)
{
// Assignment next
aptr(Node) n(new AssignNode(m_expr));
n->Parse(*this, start, end, assignindex);
return n.release();
}
else if(addsubindex != (size_type)-1)
{
// Addition/subtraction next
if(m_tokens[addsubindex].GetType() == Token::TypePlus)
{
// Addition
aptr(Node) n(new AddNode(m_expr));
n->Parse(*this, start, end, addsubindex);
return n.release();
}
else
{
// Subtraction
aptr(Node) n(new SubtractNode(m_expr));
n->Parse(*this, start, end, addsubindex);
return n.release();
}
}
else if(muldivindex != (size_type)-1)
{
// Multiplication/division next
if(m_tokens[muldivindex].GetType() == Token::TypeAsterisk)
{
// Multiplication
aptr(Node) n(new MultiplyNode(m_expr));
n->Parse(*this, start, end, muldivindex);
return n.release();
}
else
{
// Division
aptr(Node) n(new DivideNode(m_expr));
n->Parse(*this, start, end, muldivindex);
return n.release();
}
}
else if(posnegindex == start)
{
// Positive/negative next, must be at start and check before exponent
if(m_tokens[posnegindex].GetType() == Token::TypePlus)
{
// Positive
return ParseRegion(posnegindex + 1, end);
}
else
{
aptr(Node) n(new NegateNode(m_expr));
n->Parse(*this, start, end, posnegindex);
return n.release();
}
}
else if(expindex != (size_type)-1)
{
// Exponent
aptr(Node) n(new ExponentNode(m_expr));
n->Parse(*this, start, end, expindex);
return n.release();
}
else if(posnegindex != (size_type)-1)
{
// Check pos/neg again. After testing for exponent, a pos/neg
// at plevel 0 is syntax error
SyntaxException e;
e.SetStart(m_tokens[posnegindex].GetStart());
e.SetEnd(m_tokens[posnegindex].GetEnd());
throw(e);
}
else if(fgopen == start)
{
// Group parenthesis, make sure something in between them
if(fgclose == end && fgclose > fgopen + 1)
{
return ParseRegion(fgopen + 1, fgclose - 1);
}
else
{
SyntaxException e;
e.SetStart(m_tokens[fgopen].GetStart());
if(fgclose == (size_type)-1)
e.SetEnd(m_tokens[fgopen].GetEnd());
else
e.SetEnd(m_tokens[fgclose].GetEnd());
throw(e);
}
}
else if(fgopen == start + 1)
{
// Function
if(fgclose == end)
{
// Find function list
FunctionList *flist = m_expr->GetFunctionList();
if(flist == 0)
{
NoFunctionListException e;
e.SetStart(m_tokens[start].GetStart());
e.SetEnd(m_tokens[start].GetEnd());
throw(e);
}
// Get name
string ident = m_tokens[start].GetIdentifier();
// Create function node
aptr(FunctionNode) n(flist->Create(ident, m_expr));
if(n.get())
{
n->Parse(*this, fgopen, fgclose);
}
else
{
NotFoundException e(ident);
e.SetStart(m_tokens[start].GetStart());
e.SetEnd(m_tokens[start].GetEnd());
throw(e);
}
return n.release();
}
else
{
SyntaxException e;
e.SetStart(m_tokens[fgopen].GetStart());
if(fgclose == (size_type)-1)
e.SetEnd(m_tokens[fgopen].GetEnd());
else
e.SetEnd(m_tokens[fgclose].GetEnd());
throw(e);
}
}
else if(start == end)
{
// Value, variable, or constant
if(m_tokens[start].GetType() == Token::TypeIdentifier)
{
// Variable/constant
aptr(Node) n(new VariableNode(m_expr));
n->Parse(*this, start, end);
return n.release();
}
else
{
// Value
aptr(Node) n(new ValueNode(m_expr));
n->Parse(*this, start, end);
return n.release();
}
}
else
{
// Unknown, syntax
SyntaxException e;
e.SetStart(m_tokens[pos].GetStart());
e.SetEnd(m_tokens[pos].GetEnd());
throw(e);
}
}
// Get a token
const Token &Parser::operator[] (Parser::size_type pos) const
{
return m_tokens[pos];
}
// Build tokens
void Parser::BuildTokens(const string &exstr)
{
m_tokens.clear();
// Test zero-length expression
if(exstr.length() == 0)
{
throw(EmptyExpressionException());
}
// Search through list
string::size_type pos;
bool comment = false;
for(pos = 0; pos < exstr.length(); pos++)
{
// Take action based on character
switch(exstr[pos])
{
// Comment
case '#':
{
comment = true;
break;
}
// Newline ends comment
case '\r':
case '\n':
{
comment = false;
break;
}
// Open parenthesis
case '(':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeOpenParenthesis, pos, pos));
}
break;
}
// Close parenthesis
case ')':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeCloseParenthesis, pos, pos));
}
break;
}
// Equal
case '=':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeEqual, pos, pos));
}
break;
}
// Plus
case '+':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypePlus, pos, pos));
}
break;
}
// Hyphen
case '-':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeHyphen, pos, pos));
}
break;
}
// Asterisk
case '*':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeAsterisk, pos, pos));
}
break;
}
// Forward slash
case '/':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeForwardSlash, pos, pos));
}
break;
}
// Hat (exponent)
case '^':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeHat, pos, pos));
}
break;
}
// Ampersand
case '&':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeAmpersand, pos, pos));
}
break;
}
// Comma
case ',':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeComma, pos, pos));
}
break;
}
// Semicolon
case ';':
{
if(comment == false)
{
m_tokens.push_back(Token(Token::TypeSemicolon, pos, pos));
}
break;
}
// None of the above, but it may be an identifier or value
default:
{
if(comment == false)
{
// First, test for value
if(exstr[pos] == '.' || expreval_isdigit(exstr[pos]))
{
// We are a value
string::size_type start = pos;
// Digits before period
while(expreval_isdigit(exstr[pos]))
pos++;
// Period
if(exstr[pos] == '.')
pos++;
// Digits after period
while(expreval_isdigit(exstr[pos]))
pos++;
// Create token
string ident = exstr.substr(start, pos - start);
m_tokens.push_back(Token(expreval_atof(ident.c_str()), start, pos - 1));
// Move pos back so pos++ will set it right
pos--;
}
else if(exstr[pos] == '_' || expreval_isalpha(exstr[pos]))
{
// We are an identifier
string::size_type start = pos;
bool foundname = true; // Found name part
// Search for name, then period, etc
// An identifier can be multiple parts. Each part
// is formed as an identifier and seperated by a period,
// An identifier can not end in a period
//
// color1.red : 1 identifier token
// color1. : color1 is identifier, . begins new token
// color1.1red : Not value (part 2 is not right)
while(foundname)
{
// Part before period
while(exstr[pos] == '_' || expreval_isalnum(exstr[pos]))
pos++;
// Is there a period
if(exstr[pos] == '.')
{
pos++;
// There is a period, look for the name again
if(exstr[pos] == '_' || expreval_isalpha(exstr[pos]))
{
foundname = true;
}
else
{
// No name after period
foundname = false;
// Remove period from identifier
pos--;
}
}
else
{
// No period after name, so no new name
foundname = false;
}
}
// Create token
m_tokens.push_back(Token(exstr.substr(start, pos - start), start, pos - 1));
// Move pos back so pos++ will set it right
pos--;
}
else if(expreval_isspace(exstr[pos]))
{
// Do nothing, just ignore white space, but it still
// seperates tokens
}
else
{
// Unknown token
UnknownTokenException e;
e.SetStart(pos);
e.SetEnd(pos);
throw(e);
}
}
break;
}
}
}
}

96
3rdparty/expreval/parser.h vendored Normal file
View File

@ -0,0 +1,96 @@
// File: parser.h
// Author: Brian Vanderburg II
// Purpose: Parser object to help parse expression
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_PARSER_H
#define __EXPREVAL_PARSER_H
// Includes
#include <vector>
#include <string>
// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class Expression;
class Node;
// Token class
//--------------------------------------------------------------------------
class Token
{
public:
// Token type
enum TokenType
{
TypeUnknown = 0,
// Basic types
TypeOpenParenthesis, // '('
TypeCloseParenthesis, // ')'
TypeEqual, // '='
TypePlus, // '+'
TypeHyphen, // '-'
TypeAsterisk, // '*'
TypeForwardSlash, // '/'
TypeHat, // '^'
TypeAmpersand, // '&'
TypeComma, // ','
TypeSemicolon, // ';'
TypeIdentifier, // name
TypeValue, // 0.2, .6, 2.1
};
// Constructors
Token(TokenType type, ::std::string::size_type start, ::std::string::size_type end);
Token(const ::std::string &ident, ::std::string::size_type start, ::std::string::size_type end); // May throw if can not copy string
Token(double value, ::std::string::size_type start, ::std::string::size_type end);
// Information
TokenType GetType() const;
const ::std::string &GetIdentifier() const;
double GetValue() const;
::std::string::size_type GetStart() const;
::std::string::size_type GetEnd() const;
private:
TokenType m_type; // Type of token
::std::string m_ident; // If type is Identifier
double m_value; // If type is Value
::std::string::size_type m_start, m_end;
};
// Parser class
//--------------------------------------------------------------------------
class Parser
{
public:
typedef ::std::vector<Token*>::size_type size_type;
Parser(Expression *expr);
~Parser();
Node *Parse(const ::std::string &exstr);
Node *ParseRegion(size_type start, size_type end);
const Token &operator[] (size_type pos) const;
private:
void BuildTokens(const std::string &exstr);
Expression *m_expr;
::std::vector<Token> m_tokens; // Store token and not pointer to token
};
}
#endif // __EXPREVAL_PARSER_H

208
3rdparty/expreval/vallist.cpp vendored Normal file
View File

@ -0,0 +1,208 @@
// File: vallist.cpp
// Author: Brian Vanderburg II
// Purpose: Value list used for variable and constants
//------------------------------------------------------------------------------
// Includes
#include <new>
#include <memory>
#include "defs.h"
#include "vallist.h"
#include "except.h"
using namespace std;
using namespace ExprEval;
// ValueListItem
//------------------------------------------------------------------------------
// Constructor for internal value
ValueListItem::ValueListItem(const string &name, double def, bool constant)
{
m_name = name;
m_constant = constant;
m_value = m_def = def;
m_ptr = 0;
}
// Constructor for external value
ValueListItem::ValueListItem(const string &name, double *ptr, double def, bool constant)
{
m_name = name;
m_constant = constant;
m_value = m_def = def;
m_ptr = ptr;
if(m_ptr)
*m_ptr = def;
else
throw(NullPointerException("ValueListItem::ValueListItem"));
}
// Get the name
const string &ValueListItem::GetName() const
{
return m_name;
}
// Return if it is constant
bool ValueListItem::IsConstant() const
{
return m_constant;
}
// Get value address
double *ValueListItem::GetAddress()
{
return m_ptr ? m_ptr : &m_value;
}
// Reset to default value
void ValueListItem::Reset()
{
if(m_ptr)
*m_ptr = m_def;
else
m_value = m_def;
}
// ValueList
//------------------------------------------------------------------------------
// Constructor
ValueList::ValueList()
{
}
// Destructor
ValueList::~ValueList()
{
Clear();
}
// Add value to list
void ValueList::Add(const string &name, double def, bool constant)
{
// Ensure value does not already exist
if(GetAddress(name))
{
throw(AlreadyExistsException(name));
}
else
{
// Create value
aptr(ValueListItem) i(new ValueListItem(name, def ,constant));
// Add value to list
m_values.push_back(i.get());
i.release();
}
}
// Add an external value to the list
void ValueList::AddAddress(const string &name, double *ptr, double def, bool constant)
{
if(GetAddress(name))
{
throw(AlreadyExistsException(name));
}
else if(ptr == 0)
{
throw(NullPointerException("ValueList::AddAddress"));
}
else
{
// Create value
aptr(ValueListItem) i(new ValueListItem(name, ptr, def, constant));
// Add value to list
m_values.push_back(i.get());
i.release();
}
}
// Get the address of the value, internal or external
double *ValueList::GetAddress(const string &name) const
{
size_type pos;
for(pos = 0; pos < m_values.size(); pos++)
{
if(m_values[pos]->GetName() == name)
{
// The name matches
return m_values[pos]->GetAddress();
}
}
// No item found
return 0;
}
// Is the value a constant
bool ValueList::IsConstant(const string &name) const
{
size_type pos;
for(pos = 0; pos < m_values.size(); pos++)
{
if(m_values[pos]->GetName() == name && m_values[pos]->IsConstant())
{
return true;
}
}
return false;
}
// Number of values in the list
ValueList::size_type ValueList::Count() const
{
return m_values.size();
}
// Get an item
void ValueList::Item(size_type pos, string *name, double *value) const
{
if(name)
*name = m_values[pos]->GetName();
if(value)
*value = *(m_values[pos]->GetAddress());
}
// Add some default values
void ValueList::AddDefaultValues()
{
// Math constant 'e'
Add("E", EXPREVAL_E, true);
// Math constant PI
Add("PI", EXPREVAL_PI, true);
}
// Reset values
void ValueList::Reset()
{
size_type pos;
for(pos = 0; pos < m_values.size(); pos++)
{
m_values[pos]->Reset();
}
}
// Free values
void ValueList::Clear()
{
size_type pos;
for(pos = 0; pos < m_values.size(); pos++)
{
delete m_values[pos];
}
}

84
3rdparty/expreval/vallist.h vendored Normal file
View File

@ -0,0 +1,84 @@
// File: vallist.h
// Author: Brian Vanderburg II
// Purpose: Value list used for variable and constants
//------------------------------------------------------------------------------
#ifndef __EXPREVAL_VALLIST_H
#define __EXPREVAL_VALLIST_H
// Includes
#include <string>
#include <vector>
// Part of expreval namespace
namespace ExprEval
{
// Value list item
//--------------------------------------------------------------------------
class ValueListItem
{
public:
ValueListItem(const ::std::string &name, double def = 0.0, bool constant = false);
ValueListItem(const ::std::string &name, double *ptr, double def = 0.0, bool constant = false);
const ::std::string &GetName() const;
bool IsConstant() const;
double *GetAddress();
void Reset();
private:
::std::string m_name; // Name of value
bool m_constant; // Value is constant
double m_value; // Internal value (if ptr == 0)
double *m_ptr; // Pointer to extern value if not 0
double m_def; // Default value when reset
};
// Value list
//--------------------------------------------------------------------------
class ValueList
{
public:
typedef ::std::vector<ValueListItem*>::size_type size_type;
ValueList();
~ValueList();
// Add variable or constant to the list
void Add(const ::std::string &name, double def = 0.0, bool constant = false);
// Add an external variable or constant to the list
void AddAddress(const ::std::string &name, double *ptr, double def = 0.0, bool constant = false);
// Get the address of a variable or constant, internal or external
double *GetAddress(const ::std::string &name) const;
// Is the value constant
bool IsConstant(const ::std::string &name) const;
// Enumerate values
size_type Count() const;
void Item(size_type pos, ::std::string *name = 0, double *value = 0) const;
// Initialize some default values (math constants)
void AddDefaultValues();
// Reset items to default values (constants are not changed)
void Reset();
// Free items and clear memory
void Clear();
private:
::std::vector<ValueListItem*> m_values;
};
};
#endif // __EXPREVAL_VALLIST_H