
A math expression parser with support for strings, vectors and matrices.
Create a new instance handle. You can create as many different instance handles as you like. Each will internally reference a different parser object. When using the DLL it is necessary to manually release any parser handle created by mupInit() by calling mupRelease(hParser).
muParserHandle_t hParser;
hParser = mupInit(); // Create a new handle
// use the parser...
mupRelease(hParser); // Release an existing parser handle
Internally a handle is nothing more than a pointer to a parser object casted to a void pointer.
Code for creating a new parser object. (In case of dynamic allocation use new
and delete
for initialization and deinitialization.)
mu::Parser parser;
Setting the expression when using the DLL requires a valid parser handle and a pointer to
const char
pointing to the expression.
mupSetExpr(hParser, szLine);
See also: example2/example2.c.
Setting the expression using the parser class requires a std::string
containing the expression as the
only parameter.
parser.SetExpr(line);
See also: example1/example1.cpp; src/muParserTest.cpp.
Sometimes it is necessary to change the character sets that are used for token identifiers in order to avoid conflicts. The parser uses three different character sets for names, operators and infix operators.
The name character set, is used for:The Infix operator charset is used for infix operator identifiers only
When using the default implementation mu::muParser directly, you can skip this section. (The DLL version uses the default implementation internally.)
mupDefineNameChars(hParser, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
mupDefineOprtChars(hParser, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_");
mupDefineInfixOprtChars(hParser, "/+-*^?<>=#!$%&|~'_");
parser.DefineNameChars("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
parser.DefineOprtChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_");
parser.DefineInfixOprtChars("/+-*^?<>=#!$%&|~'_");
See also: muparser/src/muParser.cpp; muparser/src/muParserInt.cpp.
Expression evaluation is done by calling the mupEval() function in the DLL version or the Eval() member function of a parser object. When evaluating an expression for the first time the parser evaluates the expression string directly and creates a bytecode during this first time evaluation. Every sucessive call to Eval() will evaluate the bytecode directly unless you call a function that will silently reset the parser to string parse mode. Some functions invalidate the bytecode due to possible changes in callback function pointers or variable addresses. By doing so they effectively cause a recreation of the bytecode during the next call to Eval().
Internally there are different evaluation functions. One for parsing from a string, the other for parsing from bytecode (and a third one used only if the expression can be simplified to a constant). Initially, Eval() will call the string parsing function which is slow due to all the necessary syntax checking, variable lookup, and bytecode creation. Once this function succeeds, Eval() will change its internal parse function pointer to either the bytecode parsing function or the const result function which are significantly (approx. 1000 times) faster. You don't have to worry about this, it's done automatically, just keep in mind that the first time evaluation of an expression is significantly slower than any successive call to Eval().
double fVal;
fVal = mupEval(hParser);
See also: example2/example2.c.
double fVal;
try
{
fVal = parser.Eval();
}
catch (Parser::exception_type &e)
{
std::cout << e.GetMsg() << endl;
}
See also: example1/example1.cpp.
If the expression contains multiple separated subexpressions the return value of Eval()/ mupEval() is the result of the last subexpression. If you need all of the results use the Eval overload described in the next section.
muparser accepts expressions that are made up of several subexpressions delimited by the function argument separator. For instance take a look at the following expression:
sin(x),y+x,x*x
It is made up of three expression separated by commas hence it will create three return values.
(Assuming the comma is defined as the argument separator). The number of return values as well
as their value can be queried with an overload of the Eval
function. This overload
takes a reference to an integer value for storing the total number of return values and returns
a pointer to an array of value_type
holding the actual values with the first value
at the botton of the array and the last at the top.
int nNum, i;
muFloat_t *v = mupEvalMulti(hParser, &nNum);
for (i=0; i<nNum; ++i)
{
printf("v[i]=%2.2f\n", v[i]);
}
int nNum;
value_type *v = parser.Eval(nNum);
for (int i=0; i<nNum; ++i)
{
std::cout << v[i] << "\n";
}
See also: example1/example1.cpp.
The function GetNumResults() can be used in order to finf out whether a given expression has produced multiple return values.
Please note: Using the bulk mode without also enabling OpenMP during compilation is pointless!
The basic idea behind the bulkmode is to minimize the overhead of function calls and allow for parallelization of the expression evaluation loop when the same espression shall be evaluated for ever changing variables. If muparser was compiled with OpenMP support the calculation load will be spread among all available CPU cores. When using the bulk mode variable pointers submitted to the DefineVar function must be arrays instead of single variables. All variable arrays must have the same size and each array index represents a distinct set of variables to be used in the expression.
Although the bulk mode does work with standard callback functions it may sometimes be necessary to have additional information inside a callback function. Especially Informations like the index of the current variable set and the index of the thread performing the calculation may be crucial to the evaluation process. To facilitate this need a special set of callback functions was added. Those must use callbacks of type bulkfun_type1...bulkfun_type10. They take two additional parameters. The first one is the variable index, the second one is the thread id.
void CalcBulk()
{
int nBulkSize = 200, i;
// allocate the arrays for variables and return values
muFloat_t *x = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
muFloat_t *y = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
muFloat_t *r = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
// initialize the parser and variables
muParserHandle_t hParser = mupCreate(muBASETYPE_FLOAT);
for (i=0; i<nBulkSize; ++i)
{
x[i] = i;
y[i] = i;
r[i] = 0;
}
// Set up variables and functions and evaluate the expression
mupDefineVar(hParser, "x", x);
mupDefineVar(hParser, "y", y);
mupDefineBulkFun1(hParser, "bulktest", BulkTest);
mupSetExpr(hParser, "bulktest(x+y)");
mupEvalBulk(hParser, r, nBulkSize);
if (mupError(hParser))
{
printf("\nError:\n");
printf("------\n");
printf("Message: %s\n", mupGetErrorMsg(hParser) );
printf("Token: %s\n", mupGetErrorToken(hParser) );
printf("Position: %d\n", mupGetErrorPos(hParser) );
printf("Errc: %d\n", mupGetErrorCode(hParser) );
return;
}
// Output the result
for (i=0; i<nBulkSize; ++i)
{
printf("%d: bulkfun(%2.2f + %2.2f) = %2.2f\n", i, x[i], y[i], r[i]);
}
free(x);
free(y);
free(r);
}