/** @file Parser: @b math parser class. Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) Author: Alexander Petrosyan (http://design.ru/paf) $Id: math.C,v 1.6 2001/09/26 10:32:25 parser Exp $ */ #include "pa_config_includes.h" #include "pa_common.h" #include "pa_vint.h" #include "pa_vmath.h" #include "pa_request.h" #ifdef WIN32 # include #endif // defines #define PI 3.1415926535 #define MATH_CLASS_NAME "math" // class class MMath : public Methoded { public: MMath(Pool& pool); void configure_admin(Request& r); public: // Methoded bool used_directly() { return true; } }; // methods static unsigned int randomizer=0; static void _random(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); Value& range=params->as_junction(0, "range must be expression"); uint max=(uint)r.process(range).as_double(); if(max<=1) PTHROW(0, 0, &method_name, "bad range [0..%u]", max); Value& result=*new(pool) VInt(pool, (int)( ((double)((randomizer=rand())% RAND_MAX)) / RAND_MAX * (max + 1))); result.set_name(method_name); r.write_no_lang(result); } typedef double (*math1_func_ptr)(double); static double round(double param) { return floor(param+0.5); } static double sign(double param) { return param > 0 ? 1 : ( param < 0 ? -1 : 0 ); } static double trunc(double param) { return param > 0? floor(param) : ceil(param); } static double frac(double param) { return param-trunc(param); } static double degrees(double param) { return param /PI *180; } static double radians(double param) { return param /180 *PI; } static void math1(Request& r, const String& method_name, MethodParams *params, math1_func_ptr func) { Pool& pool=r.pool(); Value& param=params->as_junction(0, "parameter must be expression"); Value& result=*new(pool) VDouble(pool, (*func)(r.process(param).as_double())); result.set_name(method_name); r.write_no_lang(result); } #define MATH1(name) \ static void _##name(Request& r, const String& method_name, MethodParams *params) {\ math1(r, method_name, params, &name);\ } #define MATH1P(name_parser, name_c) \ static void _##name_parser(Request& r, const String& method_name, MethodParams *params) {\ math1(r, method_name, params, &name_c);\ } MATH1(round); MATH1(floor); MATH1P(ceiling, ceil); MATH1(trunc); MATH1(frac); MATH1P(abs, fabs); MATH1(sign); MATH1(exp); MATH1(log); MATH1(sin); MATH1(asin); MATH1(cos); MATH1(acos); MATH1(tan); MATH1(atan); MATH1(degrees); MATH1(radians); MATH1(sqrt); typedef double (*math2_func_ptr)(double, double); static void math2(Request& r, const String& method_name, MethodParams *params, math2_func_ptr func) { Pool& pool=r.pool(); Value& a=params->as_junction(0, "parameter must be expression"); Value& b=params->as_junction(1, "parameter must be expression"); Value& result=*new(pool) VDouble(pool, (*func)( r.process(a).as_double(), r.process(b).as_double())); result.set_name(method_name); r.write_no_lang(result); } #define MATH2(name) \ static void _##name(Request& r, const String& method_name, MethodParams *params) {\ math2(r, method_name, params, &name);\ } MATH2(pow); // constructor MMath::MMath(Pool& apool) : Methoded(apool) { set_name(*NEW String(pool(), MATH_CLASS_NAME)); // ^FUNC(expr) #define ADD1(name) \ add_native_method(#name, Method::CT_STATIC, _##name, 1, 1) ADD1(round); ADD1(floor); ADD1(ceiling); ADD1(trunc); ADD1(frac); ADD1(abs); ADD1(sign); ADD1(exp); ADD1(log); ADD1(sin); ADD1(asin); ADD1(cos); ADD1(acos); ADD1(tan); ADD1(atan); ADD1(degrees); ADD1(radians); ADD1(sqrt); ADD1(random); #define ADD2(name) \ add_native_method(#name, Method::CT_STATIC, _##name, 2, 2) // ^pow(x;y) ADD2(pow); } // in MSVC each thread has it's own pseudo-random sequence // in win32 apache each thread can handle multiple requests // so to get proper randoms we remember random generated in one thread void MMath::configure_admin(Request&) { // setting seed srand( randomizer ^ #ifdef WIN32 GetCurrentThreadId() ^ #else getpid() ^ #endif (unsigned int)time(NULL) ); if(!randomizer) randomizer=rand(); } // global variables Methoded *math_base_class; Hash *math_consts; // creator Methoded *MMath_create(Pool& pool) { math_consts=new(pool) Hash(pool); math_consts->put( *new(pool) String(pool, "PI"), new(pool) VDouble(pool, PI)); return math_base_class=new(pool) MMath(pool); }