#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

#define	NOERR	0
#define	ERR		1
#define	FUNCMAX	20
#define	PI		3.14159

/*----------     演算子情報構造体     ----------*/
typedef struct
{
	char	name[8];
	int		prior;
} FUNC ;

/*----------     演算子設定      ----------*/
static FUNC	func[FUNCMAX] = {
					{ "(", 5 }, { "number", 4 }, { "^", 3 }, { "sqr", 3 },
					{ "*", 2 }, { "/", 2 }, { "+", 1 }, { "-", 1 },
					{ ")", 0 }, { "sin", 3 }, { "cos", 3 }, { "tan", 3 },
					{ "arcsin", 3 }, { "arccos", 3 }, { "arctan", 3 },
					{ "log", 3 }, { "ln", 3 }, { "exp", 3 }, { "mod", 3 },
					{ "abs", 3 }
};

int		calcvalue( const char *, double * );
static int	CV_get_number( const char *, double *, int *, int );
static int	CV_get_function( const char *, int *, int * );
static int	topcmp( const char *, const char * );
static void	tolowerstr( const char *, char * );

/*----------     main routine     ----------*/
int		calcvalue( const char *q, double *v )
{
	int		mem_1[256],mem_2[256];
	double	mem_3[256],mem_4[256],value;
	int		code,a;
	int		*st_1,*st_2;
	double	*st_3,*st_4;
	char	*p,buf[256];

	p = buf;
	tolowerstr( q, p );
	bzero( mem_2, 256 );
/*-----------     逆ポーランド記法への変換     -----------*/

	st_1 = mem_1;
	st_2 = mem_2;
	st_3 = mem_3;
	st_4 = mem_4;

	code = 0;

	while( *p )
	{
		while( *p == ' ' )
			++ p;

		if( CV_get_number( p, &value, &a, code ) )
		{
			if( CV_get_function( p, &code, &a ) )
			{
				return ERR;
			}
		}
		else
		{
			code = 1;
		}

		p += a;
		while( func[code].prior <= func[*st_2].prior && *st_2 != 0 && st_2 > mem_2 )
		{
			*st_1 = *st_2;
			*st_3 = *st_4;
			++st_1;
			++st_3;
			--st_2;
			--st_4;
		}

		if( code != 8 )
		{
			++st_2;
			++st_4;
			*st_2 = code;
			*st_4 = value; 
		}
		else
		{
			if( *st_2 != 0 )
				return ERR;
			--st_2;
			--st_4;
		}
	}

	while( st_2 > mem_2 )
	{
		*st_1 = *st_2;
		*st_3 = *st_4;
		++st_1;
		++st_3;
		--st_2;
		--st_4;
	}

	*st_1 = 0xff;
/*-----------     逆ポーランド記法の計算     ----------*/

	st_1 = mem_1;
	st_3 = mem_3;
	st_4 = mem_4;

	while( *st_1 != 0xff )
	{
		double	x,y,z,dmy;

		switch( *st_1 )
		{
			case 1:/*-----     数値     -----*/
				*st_4 = *st_3;
				++st_4;
				break;

			case 2:/*-----     巾乗 (x ^ y)     -----*/
				y = *(st_4-1);
				x = *(st_4-2);
				st_4 -= 2;
				if( x < 0 && modf( y, &dmy ) != 0 )
					return ERR;
				z = pow( x, y );
				*st_4 = z;
				++st_4;
				break;

			case 3:/*-----     平方根 (sqr x)[x>=0]     -----*/
				x = *(st_4-1);
				--st_4;
				if( x < 0 )
					return ERR;
				z = sqrt( x );
				*st_4 = z;
				++st_4;
				break;

			case 4:/*-----     掛け算 (x * y)     -----*/
				y = *(st_4-1);
				x = *(st_4-2);
				st_4 -= 2;
				z = x * y;
				*st_4 = z;
				++st_4;
				break;

			case 5:/*-----     割り算 (x / y)[y!=0]     -----*/
				y = *(st_4-1);
				x = *(st_4-2);
				st_4 -= 2;
				z = x / y;
				if( y == 0 )
					return ERR;
				*st_4 = z;
				++st_4;
				break;

			case 6:/*-----     足し算 (x + y)     -----*/
				y = *(st_4-1);
				x = *(st_4-2);
				st_4 -= 2;
				z = x + y;
				*st_4 = z;
				++st_4;
				break;

			case 7:/*-----     引き算 (x - y)     -----*/
				y = *(st_4-1);
				if( st_4-1 == mem_4 )
				{
					x = 0;
					--st_4;
				}
				else
				{
					x = *(st_4-2);
					st_4 -= 2;
				}
				z = x - y;
				*st_4 = z;
				++st_4;
				break;

			case 9:/*-----     正弦 (sin x)     -----*/
				x = *(st_4-1);
				--st_4;
				z = sin( x );
				*st_4 = z;
				++st_4;
				break;

			case 10:/*-----     余弦 (cos x)     -----*/
				x = *(st_4-1);
				--st_4;
				z = cos( x );
				*st_4 = z;
				++st_4;
				break;

			case 11:/*-----     正接 (tan x)[x!=PI/2+2*n*PI]     -----*/
				x = *(st_4-1);
				--st_4;
				if( modf( fmod( x - PI/2, PI ), &dmy ) == 0 )
					return ERR;
				z = tan( x );
				*st_4 = z;
				++st_4;
				break;

			case 12:/*-----     正弦の逆関数 (Arcsin x)[-1<=x<=1]     -----*/
				x = *(st_4-1);
				--st_4;
				if( x > 1 || x < -1 )
					return ERR;
				z = asin( x );
				*st_4 = z;
				++st_4;
				break;

			case 13:/*-----     余弦の逆関数 (Arccos x)[-1<=x<=1]     -----*/
				x = *(st_4-1);
				--st_4;
				if( x > 1 || x < -1 )
					return ERR;
				z = acos( x );
				*st_4 = z;
				++st_4;
				break;

			case 14:/*-----     正接の逆関数 (Arctan x)     -----*/
				x = *(st_4-1);
				--st_4;
				z = atan( x );
				*st_4 = z;
				++st_4;
				break;

			case 15:/*-----     常用対数 (log x)[x>0]     -----*/
				x = *(st_4-1);
				--st_4;
				if( x <= 0 )
					return ERR;
				z = log10( x );
				*st_4 = z;
				++st_4;
				break;

			case 16:/*-----     自然対数 (ln x)[x>0]     -----*/
				x = *(st_4-1);
				--st_4;
				if( x <= 0 )
					return ERR;
				z = log( x );
				*st_4 = z;
				++st_4;
				break;

			case 17:/*-----     自然対数の巾乗 (exp x)     -----*/
				x = *(st_4-1);
				--st_4;
				z = exp( x );
				*st_4 = z;
				++st_4;
				break;

			case 18:/*-----     剰余 (x mod y)[y!=0]     -----*/
				y = *(st_4-1);
				x = *(st_4-2);
				st_4 -= 2;
				if( y == 0 )
					return ERR;
				z = fmod( x, y );
				*st_4 = z;
				++st_4;
				break;

			case 19:/*-----     絶対値 (abs x)     -----*/
				x = *(st_4-1);
				--st_4;
				z = fabs( x );
				*st_4 = z;
				++st_4;
				break;
		}
		++st_1;
		++st_3;
	}

	*v = *(st_4-1);

	return NOERR;
}

static int	CV_get_number( const char *p, double *value, int *a, int code )
{
	int		flg1,flg2,flg3;
	double	tmp;	

	*value = 0;
	*a = 0;
	flg1 = 0;
	flg2 = ERR;
	flg3 = 0;

	if( *p == '-' && code != 1 )
	{
		++ *a;
		++ p;
		flg3 = 1;
	}
	
	if( *p == '0' && *(p+1) == 'x' )
	{
		p += 2;
		*a += 2;

		while( ( *p >= '0' && *p <= '9' ) || ( *p >= 'a' && *p <= 'f' ) )
		{
			*value *= 16;
			if( *p >= '0' && *p <= '9' )
				*value += *p - '0';
			else
				*value += *p - 'a' + 10;

			++ p;
			++ *a;
		}
		flg2 = NOERR;
	}
	else
	{
		while( ( *p >= '0' && *p <= '9' ) || *p == '.' )
		{
			if( *p == '.' )
			{
				if( flg1 != 0 )
					return ERR;
				flg1 = 1;
				++ *a;
				++p;
				continue;
			}

			if( flg1 == 0 )
			{
				*value *= 10;
				*value += *p - '0';
			}
			else
			{
				tmp = *p - '0';
				tmp /= pow( 10, flg1 );
				*value += tmp;
				++flg1;
			}

			flg2 = NOERR;
			++ p;
			++ *a;
		}
	}

	if( flg3 == 1 )
	*value = 0 - *value;

	return flg2;
}

static int	CV_get_function( const char *p, int *code, int *a )
{
	int		i;

	i = 0;
	while( i < FUNCMAX )
	{
		if( strncmp( p, func[i].name, strlen(func[i].name) ) == 0 /*topcmp( p, func[i].name )*/ )
		{
			*code = i;
			*a = strlen( func[i].name );
			return NOERR;
		}
		++ i;
	}
	return ERR;
}

static int	topcmp( const char *p, const char *q )
{
	while( *q )
	{
		if( *p != *q )
			return 0;
		++p;
		++q;
	}
	return 1;
}

static void	tolowerstr( const char *in, char *out )
{
	while( *in )
		*out++ = tolower(*in++);
	*out = 0;
	return;
}
