资源说明:MicroMath+ math parser and execution environment
This is the latest (moslty)unedited version of code from an old project; I used previous versions of this code to perform evaluation of functional representations used to describe geometrical objects, which later on turned out to be completely useless: it is way easier to directly evaluate any expression at run-time through GLSL or (now)OpenCL in parallel and record the results into an output array. ------------------------------------------------------------------------------- ______________ ______________ MicroMath+ 2.1 ______________ ______________ MicroMath+ - copyright (c) 2001 Ugo Varetto Features: - transform a mathematical expression into RPN format - compile the RPN expression into a sequence of instructions - execute the compiled program The parser returns a list of tokens using only information about operators * any word starting with '_' or a letter and containing a mix of letters, digits and '_' is parsed as a name * anything in the form '(...)' is assumed to be a function It's up to the compiler and run-time environment to figure out what to do with the parsed functions, operators, values and names. ================================================================================ RELEASE NOTES ================================================================================ Changes fromm previous versions: -------------------------------- - added CMake file - added shared_ptr smart pointer implementation and memory tracer class + oveloaded new and delete to perform automatic memory management and detect memory leaks - added support for multidimensional arguments e.g: (x,y,z) = (1,2,3) + (1,2,3) is equivalent to x=1+1, y=2+2, z=3+3 - it is now possible to use multidimensional functions R^n --> R^m e.g. dot product (R^3-->R^1): (1,2,3)*(1,2,3) == 1+4+9 - removed operator substitution: operator --> function substitution not supported anymore - generalized functions and operators, functions are actually generic operators supporting left and right multi-dimensional input and output parameters - new representation for RPN notation: operators are now represented as name[left_params right_params out_params] e.g. (1,2) + (1,2) --> 1 2 1 2 +[2 2 2] if '+' returns two values. - it is now possible to remove the check on the number of parameters in the compiler - added @list command in sample program to display all the functions and operators Build ----- Use cmake to generate the project/make files for your platform: cmake *Files: math_parser.cpp - math parser implementation test.cpp - driver program to test MicroMath+ mem_tracer.cpp - implementation of memory tracing routines (optional) Tested on: GCC 4.0 Mac OS X GCC 3.4.2 MinGW MS VS .NET 2003 Intel C++ 8.0 Windows GCC 4.4 Linux x86-64 MS VS .NET 2008 To enable the memory tracing option #define MMP_DEBUG_MEMORY Examples -------- 1) Assign 1,2,3 to x,y,z (x,y,z) = (1,2,3) 2) dot product 1 + (1,1,1)*(1,1,1) 3) add (1,2,3)+(4,5,6) Misc ---- By default the parser checks the number of arguments for operators and the compiler checks the number of arguments passed to a function. An error is not returned if and only if there are entries in the function vector matching the operator/function name AND the number of input arguments. e.g. sin(1) works, sin(1,2) doesn't because the compiler cannot find a function with name == 'sin' accepting 2 arguments; it is possible to turn the check off, in this case the compiler will only verify that a function with name == 'sin' is available but won't check the number of arguments at compile time. a. f( 1, 2 ) --> function accepting two arguments b. f( (1, 2) ) --> function accepting one argument if you want (a) and (b) to be equivalent then disable argument check in the compiler. If you want to add support for run-time user defined function have a look at the add_user_def_function() function in test.cpp. Operators are considered to be generalized functions with optional arguments on the right and left side. Only operators are checked and parsed during the parse step, in order to have functions parsed at parse time add the function as an operator into the operators list passed to the math parser constructor. E.g. operator_type( "cross3", 1, 0, 6, 3 ), creates and 'operator' with the following properties: - name = cross3 - accepts 1 argument - 0 arguments on the left side - 1 6-dimensional argument (6 values) on the right side - returns 3 values (one 3-D value) this is equivalent to the function call:vcross3(1,2,3,4,5,6) In case argument counting is turned on for operators the above expression is NOT eqivalent to cross3((1,2,3),(4,5,6)) turning operator counting off in the parser makes the two expressions equivalent Difference between operators and functions: ------------------------------------------ Operators/functions passed to the parser at construction time can have any number of spaces between the operator's name and the operands. Functions are interpreted as functions if and only if no space is present between the function name and opening parenthesis: function(...) OK function (...) WRONG interpreted as name (...) It is possible to add all the functions as operators at construction time. Stack operations ---------------- f(1,2,3) --> 1 2 3 f[3] --> function accepting three parameters At run-time the following sequence of events takes place: |Operation | Stack ----------------------------------------- number 1 pushed on the stack | 1 <-- top number 2 pushed on the stack | 2 <-- top | 1 number 3 pushed on the stack | 3 <-- top | 2 | 1 function f invoked: parameters are popped from the stack in reverse order There are three options to deal with the ordering of operands: 1) ask the parser to reverse all the operands: f(1,2,3) --> 3 2 1 f[3] 2) define functions as operators and set the swap flag on per function/operator basis; check the way assignment operators are created in the test program 3) do nothing and properly handle the parameters in f's body ================================================================================ USAGE ================================================================================ ... #include "compiler.h" #include "execution.h" #include "vm.h" #include "def_rte.h" #include "math_parser.h" ... void TestParser( const string& expr ) { typedef mmath_plus::operator_type op_t; // define operators for parser op_t ops_array[] = { // example of function accepting 6 parameters and returning // 3 values op_t( "cross3", 1, 0, 6, 3 ), op_t( "^", 2 ), op_t( "*", 2, 3, 3, 1 ), op_t( "*", 2 ), op_t( "/", 2 ), op_t( "-", 1, 0, 1, 1 ), op_t( "-", 2 ), op_t( "-", 2, 3, 3, 3 ), op_t( "+", 2, 3, 3, 3 ), op_t( "+", 2 ), op_t( "=", 2, 1, 1, 1, true ), op_t( "=", 2, 3, 3, 3, true ) // 2 arguments, swap arguments // to place variable name just // before assignment operator // x = 2 --> 2 x = // This makes it easy to find // the variable when the assignment // operator is found. }; // anything in the form 'function_name( x1, x2,..., xn)' is assumed to be // a function accepting n arguments and returning 1 value. // It is possible to define functions accepting N arguments and returning M // values as operators; in this case the functions will have to be declared together with // the operators list if parse-tme argument check is required, check the cross3 function // above. vector< op_t > ops( ops_array, ops_array + sizeof( ops_array ) / sizeof( op_t ) ); // generate default run-time environment // the default run time environment supports all the standard C math functions. rte< double > rt = generate_default_rte< double >(); // Check memory allocation here // build parser math_parser mp( ops, math_parser::DONT_SWAP_ARGS, math_parser::COUNT_ARGS, math_parser::DEBUG, &cout ); // create compiler and virtual machine for execution compiler< double > c( compiler< double >::COUNT_ARGS, compiler< double >::CREATE_VARS ); vm< rte< double > > m( rt ); // program rte< double >::prog_type program; // parse math_parser::Tokens vt = mp.parse( expr ); // compile program = c.compile( vt, rt ); // run program m.prog( &program ); m.run(); // print values on stack if( !m.rte().stack.empty() ) { // print result i.e. value on top of stack cout << '\n' << "RESULT: "; while( !m.rte().stack.empty() ) { cout << m.rte().stack.top() << ' '; // remove value on top of stack m.rte().stack.pop(); } cout << endl; } } NOTE: the execution is based on a stack and an array of instructions executed sequentially: this works fine for scalar values but it is far from optimal in the case of multi-dimensional operands; I have been testing for some time with a multi_stack structure that allows to get/set/reference multiple values at once and at functions that get references to operands in the stack without removing the values but changing the values in place where possible. Not sure when/if the new approach is going to be implemented.
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。