Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 4077 → Rev 4078

/branches/Version13x/Scribus/fparser.txt
1,5 → 1,5
Function parser for C++ v2.63 by Warp.
======================================
Function parser for C++ v2.8 by Warp.
=====================================
 
Optimization code contributed by Bisqwit (http://iki.fi/bisqwit/)
 
8,33 → 8,23
 
 
 
What's new in v2.63
-------------------
- Some tiny fixes to make the library more compatible with BCB4.
What's new in v2.8
------------------
- Put the compile-time options to a separate file fpconfig.hh.
- Added comparison operators "!=", "<=" and ">=".
- Added an epsilon value to the comparison operators (its value can be
changed in fpconfig.hh or it can be completely disabled there).
- Added unary not operator "!".
- Now user-defined functions can take 0 parameters.
- Added a maximum recursion level to the "eval()" function (definable in
(fpconfig.hh). Now "eval()" should never cause an infinite recursion.
(Note however, that it may still be relevant to disable it completely
because it is possible to write functions which take enormous amounts
of time to evaluate even when the maximum recursion level is not reached.)
- Separated the optimizer code to its own file (makes developement easier).
 
What's new in v2.62
-------------------
- Only an addition to the usage license. (Please read it.)
 
What's new in v2.61
-------------------
- Tiny bug fix: Tabs and carriage returns now allowed in the function
string.
 
What's new in v2.6
-------------------
- Added a new method: GetParseErrorType(). This method can be used to
get the type of parsing error (which can be used eg. for customized
error messages in another language).
- Added working copy constructor and assignment operator (using the
copy-on-write technique for efficiency). See the "Usage" section for
details.
- Fixed a problem with the comma operator (,): Comma is not allowed
anymore anywhere else than separating function parameters. In other
words, comma is not an operator anymore (just a parameter separator).
 
 
 
=============================================================================
- Preface
=============================================================================
63,32 → 53,45
- Usage
=============================================================================
 
To use the FunctionParser class, you have to include "fparser.hh". When
compiling, you have to compile fparser.cc and link it to the main program.
You can also make a library from the fparser.cc (see the help on your
compiler to see how this is done).
To use the FunctionParser class, you have to include "fparser.hh" in
your source code files which use the FunctionParser class.
 
When compiling, you have to compile fparser.cc and fpoptimizer.cc and
link them to the main program. In some developement environments it's
enough to add those two files to your current project.
 
* Conditional compiling:
---------------------
If you are not going to use the optimizer (ie. you have commented out
SUPPORT_OPTIMIZER in fpconfig.hh), you can leave the latter file out.
 
There is a set of precompiler options at the beginning of fparser.cc
which can be used for setting certain features on or off. These lines
can be commented or uncommented depending on the desired behaviour:
 
* Configuring the compilation:
---------------------------
 
There is a set of precompiler options in the fpconfig.hh file
which can be used for setting certain features on or off:
 
NO_ASINH : (Default on)
By default the library does not support the asinh(), acosh()
and atanh() functions because they are not part of the ISO C++
standard. If your compiler supports them and you want the
parser to support them as well, comment this line.
parser to support them as well, comment out this line.
 
DISABLE_EVAL : (Default off)
The eval() function can be dangerous because it can cause an
infinite recursion in the parser when not used properly (which
causes the function stack created by the compiler to overflow).
If this possibility should be prevented then the eval() function
can be disabled completely by uncommenting this line.
Even though the maximum recursion level of the eval() function
is limited, it is still possible to write functions which never
reach this maximum recursion level but take enormous amounts of
time to evaluate (this can be undesirable eg. in web server-side
applications).
Uncommenting this line will disable the eval() function completely,
thus removing the danger of exploitation.
 
Note that you can also disable eval() by specifying the
DISABLE_EVAL precompiler constant in your compiler (eg.
with -DDISABLE_EVAL in gcc).
 
EVAL_MAX_REC_LEVEL : (Default 1000)
Sets the maximum recursion level allowed for eval().
 
SUPPORT_OPTIMIZER : (Default on)
If you are not going to use the Optimize() method, you can comment
this line out to speed-up the compilation of fparser.cc a bit, as
95,7 → 98,15
well as making the binary a bit smaller. (Optimize() can still be
called, but it will not do anything.)
 
You can also disable the optimizer by specifying the
NO_SUPPORT_OPTIMIZER precompiler constant in your compiler
(eg. with -DNO_SUPPORT_OPTIMIZER in gcc).
 
FP_EPSILON : (Default 1e-14)
Epsilon value used in comparison operators.
If this line is commented out, then no epsilon will be used.
 
 
* Copying and assignment:
----------------------
 
212,7 → 223,7
"VAR" and "Var" are *different* variable names). Letters, digits and
underscores can be used in variable names, but the name of a variable
can't begin with a digit. Each variable name can appear only once in
the string. Function names are not legal variable names.
the 'Vars' string. Function names are not legal variable names.
 
Using longer variable names causes no overhead whatsoever to the Eval()
method, so it's completely safe to use variable names of any size.
265,8 → 276,8
EMPTY_PARENTH : "Empty parentheses"
EXPECT_OPERATOR : "Syntax error: Operator expected"
OUT_OF_MEMORY : "Not enough memory"
UNEXPECTED_ERROR : "An unexpected error ocurred. Please make a full bug "
"report to warp@iki.fi"
UNEXPECTED_ERROR : "An unexpected error occurred. Please make a full bug "
"report to the author"
INVALID_VARS : "Syntax error in parameter 'Vars' given to "
"FunctionParser::Parse()"
ILL_PARAMS_AMOUNT : "Illegal number of parameters to function"
308,6 → 319,7
2: sqrt error (sqrt of a negative value)
3: log error (logarithm of a negative value)
4: trigonometric error (asin or acos of illegal value)
5: maximum recursion level in eval() reached
 
 
---------------------------------------------------------------------------
341,9 → 353,9
Optimize() and checking EvalError().
 
If the destination application is not going to use this method,
the compiler constant SUPPORT_OPTIMIZER can be undefined at the beginning
of fparser.cc to make the library smaller (Optimize() can still be called,
but it will not do anything).
the compiler constant SUPPORT_OPTIMIZER can be undefined in fpconfig.hh
to make the library smaller (Optimize() can still be called, but it will
not do anything).
 
(If you are interested in seeing how this method optimizes the opcode,
you can call the PrintByteCode() method before and after the call to
374,10 → 386,10
The return value will be false if the 'name' of the constant was
illegal, else true. If the name was illegal, the method does nothing.
 
Example: parser.AddConstant("pi", 3.14159265);
Example: parser.AddConstant("pi", 3.1415926535897932);
 
Now for example parser.Parse("x*pi", "x"); will be identical to the
call parser.Parse("x*3.14159265", "x");
call parser.Parse("x*3.1415926535897932", "x");
 
 
---------------------------------------------------------------------------
401,9 → 413,9
must have the form:
double functionName(const double* params);
 
- The number of parameters the function takes. NOTE: Currently this
value must be at least 1; the parser does not support functions which
take no parameters (this problem may be fixed in the future).
- The number of parameters the function takes. 0 is a valid value
in which case the function takes no parameters (such function
should simply ignore the double* it gets as a parameter).
 
The return value will be false if the given name was invalid (either it
did not follow the variable naming conventions, or the name was already
424,10 → 436,22
parser.Parse("2*sqr(x)", "x");
 
 
An example of a useful function taking no parameters is a function
returning a random value. For example:
 
double Rand(const double*)
{
return drand48();
}
 
parser.AddFunction("rand", Rand, 0);
 
 
IMPORTANT NOTE: If you use the Optimize() method, it will assume that
the user-given function has no side-effects, that is, it always
returns the same value for the same parameters. The optimizer will
optimize the function call away in some cases, making this assumption.
(The Rand() function given as example above is one such problematic case.)
 
 
---------------------------------------------------------------------------
446,18 → 470,14
want to use the parser A in the parser B, you must call A.Parse()
before you can call B.AddFunction("name", A).
 
- The amount of parameters in the FunctionParser instance given as
- The amount of variables in the FunctionParser instance given as
parameter must not change after it has been given to the AddFunction()
of another instance. Changing the number of parameters will result in
of another instance. Changing the number of variables will result in
malfunction.
 
- AddFunction() will fail (ie. return false) if a recursive loop is
formed. The method specifically checks that no such loop is built.
 
- As with the other AddFunction(), the number of parameters taken by
the user-defined function must be at least 1 (this may be fixed in
the future).
 
Example:
 
FunctionParser f1, f2;
464,32 → 484,15
f1.Parse("x*x", "x");
f2.AddFunction("sqr", f1);
 
This version of the AddFunction() method can be useful to eg. chain
user-given functions. For example, ask the user for a function F1,
and then ask the user another function F2, but now the user can
call F1 in this second function if he wants (and so on with a third
function F3, where he can call F1 and F2, etc).
 
---------------------------------------------------------------------------
 
Example program:
 
#include "fparser.hh"
#include <iostream>
 
int main()
{
FunctionParser fp;
 
int ret = fp.Parse("x+y-1", "x,y");
if(ret >= 0)
{
std::cerr << "At col " << ret << ": " << fp.ErrorMsg() << std::endl;
return 1;
}
 
double vals[] = { 4, 8 };
 
std::cout << fp.Eval(vals) << std::endl;
}
 
 
 
=============================================================================
- The function string
=============================================================================
499,19 → 502,26
or functions using the following operators in this order of precedence:
 
() expressions in parentheses first
A^B exponentiation (A raised to the power B)
-A unary minus
A^B exponentiation (A raised to the power B)
!A unary logical not (result is 1 if int(A) is 0, else 0)
A*B A/B A%B multiplication, division and modulo
A+B A-B addition and subtraction
A=B A<B A>B comparison between A and B (result is either 0 or 1)
A&B result is 1 if int(A) and int(B) differ from 0, else 0.
A|B result is 1 if int(A) or int(B) differ from 0, else 0.
A=B A!=B A<B A<=B A>B A>=B
comparison between A and B (result is either 0 or 1)
A&B result is 1 if int(A) and int(B) differ from 0, else 0
A|B result is 1 if int(A) or int(B) differ from 0, else 0
 
Since the unary minus has higher precedence than any other operator, for
example the following expression is valid: x*-y
Note that the '=' comparison can be inaccurate due to floating point
precision problems (eg. "sqrt(100)=10" probably returns 0, not 1).
 
The comparison operators use an epsilon value, so expressions which may
differ in very least-significant digits should work correctly. For example,
"0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1" should always return 1, and
the same comparison done with ">" or "<" should always return 0.
(The epsilon value can be configured in the fpconfig.hh file.)
Without epsilon this comparison probably returns the wrong value.
 
The class supports these functions:
 
abs(A) : Absolute value of A. If A is negative, returns -A otherwise
538,7 → 548,7
csc(A) : Cosecant of A (equivalent to 1/sin(A)).
eval(...) : This a recursive call to the function to be evaluated. The
number of parameters must be the same as the number of parameters
taken by the function. Usually called inside if() to avoid
taken by the function. Must be called inside if() to avoid
infinite recursion.
exp(A) : Exponential of A. Returns the value of e raised to the power
A where e is the base of the natural logarithm, i.e. the
581,15 → 591,14
extremely deep recursions should be avoided (eg. millions of nested recursive
calls).
 
Also note that the if() function is the only place where making a recursive
call is safe. In any other place it will cause an infinite recursion (which
will make the program eventually run out of memory). If this is something
which should be avoided, it may be a good idea to disable the eval()
function completely.
The eval() function can be disabled with the DISABLE_EVAL precompiler
constant (see the beginning of fparser.cc).
Also note that even though the maximum recursion level of eval() is
limited, it is possible to write functions which never reach that level
but still take enormous amounts of time to evaluate.
This can sometimes be undesirable because it is prone to exploitation,
but you can disable the eval() function completely in the fpconfig.hh file.
 
 
 
=============================================================================
- Contacting the author
=============================================================================
676,7 → 685,7
Usage license:
=============================================================================
 
Copyright © 2003 Juha Nieminen, Joel Yliluoma
Copyright © 2003-2005 Juha Nieminen, Joel Yliluoma
 
This library is distributed under two distinct usage licenses depending
on the software ("Software" below) which uses the Function Parser library