#include "func.h"
#include "parser.h"

// token types
#define DELIMITER 1
#define VARIABLE 2
#define NUMBER 3
#define FUNCTION 4
#define FINISHED 10

// error codes
#define ERR_BADFUNCTION -1
#define ERR_BADNUMER -2
#define ERR_GENERAL -3
#define ERR_NOBRACKET -4
#define ERR_BADVARIABLE -5
#define ERR_OVERFLOW -6

double __cdecl tg(double d)
{
	return sin(d) / cos(d);
}

double __cdecl ctg(double d)
{
	return cos(d) / sin(d);
}

double __cdecl exp(double x)
{
	__asm {
		fld	x 
		FLDL2E
		FMUL 

		FLD st(0) 

		FLD1

		FXCH 
		FPREM 
		F2XM1 
		fadd 
		FSCALE
		FSTP st(1)
	}
	
}

double __cdecl log(double x)
{
	//return 0.0;
	__asm {
		FLD1
		FLD     x
		FYL2X
		FLDLN2
		FMUL
	}
}

double __cdecl sqrt(double x)
{
	__asm {
		fld x
		fsqrt
	}
}

double __cdecl atan(double x)
{
	return 0.0; // â ëîì
}

double pow(double x, double y)
{
	return 0.0; // â ëîì, ïóñêàé ñ÷èòàþò ÷åðåõ exp è log
}


// represents general mathematical function
typedef double(__cdecl*matfunc)(double);

// used to link function name to the function
typedef struct  
{
	char name[10];
	matfunc f;
} func;

// the list of functions
const int max_func = 12;
func functions[max_func] = 
{
	"", NULL,
	"sin", &sin,
	"cos", &cos,
	"exp", &exp,
	"sqrt", &sqrt,
	"log", &log,
	"tg", &tg,
	"ctg", &ctg,
	"arcsin", &asin,
	"arccos", &acos,
	"arctg", &atan,
	"abs", &fabs
};

// all delimiters
const char *delim="+-*^/%=;(),><";		// not bad words

// structure for most parser functions

	char token[80];
	int token_type;
	char *prog;
	double x_value;
  int code;    // error code

int isdelim(char c)
{
	//return strchr(delim, c) != 0;
	for (int i = 0; i < 14; i++)
		if (c == delim[i])
			return 1;
	return 0;
}

int isdigit(char c)
{
	return (c >= '0' && c <= '9');
}

int isalpha2(char c)
{
	return ((c >= 'a' && c <= 'z')
		|| (c >= 'A' && c <= 'Z'));
}

int iswhite(char c)
{
	return (c==' ' || c=='\t');
}


void serror(int code)
{
	::code = code;
//  longjmp(j, code);
}

void set_exp(char *exp, double x)
{
	prog = exp;
	x_value = x;
}

int get_token()
{
	int tok;
	char *temp;
	(token_type) = 0;
	tok = 0;
	temp = (token);

	if (*(prog) == '\0')
	{
		*(token) = 0;
		tok = FINISHED;
		return ((token_type) = DELIMITER);
	}
	while (iswhite(*(prog))) ++(prog);
	if (isdelim(*(prog)))
	{
		*temp = *(prog);
		(prog)++;
		temp++;
		*temp = 0;
		return ((token_type) = DELIMITER);
	}
	if (isdigit(*(prog)))
	{
		while (!isdelim(*(prog)))
			*temp++=*(prog)++;
		*temp = '\0';
		return ((token_type) = NUMBER);
	}
	if (isalpha2(*(prog)))
	{
		while (!isdelim(*(prog)))
			*temp++=*(prog)++;
		(token_type) = VARIABLE;
	}
	*temp = '\0';
	if ((token_type) == VARIABLE)
	{
		tok = look_up((token));
		if (tok)
			(token_type) = FUNCTION;
	}
	return (token_type);
}

int sign(double d)
{
  if (d > 0.0)
    return 1.0;
  if (d < 0.0)
    return -1.0;
  return 0.0;
}

void putback()
{
	char *t;
	t = (token);
	for (;*t;t++)
		(prog)--;
}

int get_exp(double *hold)
{
  int res;
  code = 0;
//  if (res = setjmp(j) != 0)
//    return code;
	get_token();
	if (!*(token))
	{
		return 0;
	}
	level2( hold);
	putback();
  return 0;
}

void level2(double *hold)
{
	char op;
	double h;

	level3( hold);
	while ((op=*(token)) == '+' || op == '-')
	{
		get_token();
		level3( &h);
		arith(op, hold, &h);
	}
}

void level3(double *hold)
{
	char op;
	double h;

	level4( hold);
	while ((op=*(token)) == '*' || op == '/' || op == '%')
	{
		get_token();
		level4( &h);
		arith( op, hold, &h);
	}
}

void level4(double *hold)
{
	double h;
	level5( hold);

	if (*(token) == '^')
	{
		get_token();
		level5( &h);
		arith( '^', hold, &h);
	}
}

void level5(double *hold)
{
	char op;

	op = 0;
	if (((token_type) == DELIMITER) && *(token) == '+' || *(token) == '-')
	{
		op = *(token);
		get_token();
	}
	level6( hold);

	if (op)
		unary(op, hold);
}

void level6(double *hold)
{
	if ((*(token) == '(') && ((token_type) == DELIMITER))
	{
		get_token();
		level2( hold);
		if (*(token) != ')')
      serror( ERR_NOBRACKET);
		get_token();
	}
	else
		primitive( hold);
}

void calc_function(double *hold)
{
  double d;
	int i;

	i = look_up(token);

	if (i == 0)
		serror(ERR_BADFUNCTION);	// error

	get_token();
	if (*(token) != '(')
		serror(ERR_NOBRACKET);	// error
	get_token();
	level2(hold);
	get_token();

  d = functions[i].f(*hold);
  *hold = (functions[i].f)(*hold);
//  else
//    serror( ERR_OVERFLOW);

}

void primitive(double *hold)
{
	switch (token_type)
	{
	case VARIABLE:
		*hold = find_var(token);
		get_token();
		return;
	case NUMBER:
    //
		//*hold = atof((token));
    //if (sscanf(token, "%lf", hold) != 1)
	*hold = convert(token);
	if (*hold == ERROR)
      serror( ERR_BADNUMER);
		get_token();
		return;
	case FUNCTION:
		calc_function( hold);
		return;
	default:	// error
		return;
	}
}

void arith(char op, double *r, double *h)
{
	double t;
	switch(op)
	{
	case '-':
		*r = *r - *h;
		break;
	case '+':
		*r = *r + *h;
		break;
	case '*':
		*r = *r * *h;
		break;
	case '/':
    if (*h == 0)
      serror( ERR_OVERFLOW);
    else
		  *r = (*r) / (*h);
		break;
	case '%':
		t = (*r) / (*h);
		*r = *r - (t * (*h));
		break;
	case '^':
		*r = pow(*r, *h);
		break;
	}
}

void unary(char op, double *r)
{
	if (op == '-')
		*r = -(*r);
}

double find_var(char *s)
{
	//return 0;	// not imp
	//int i;

	//for (i = 0; i < kvar; i++)
	//	if (strcmp(vars[i].name, s) == 0)
	//		return vars[i].value;

	if (s[1] == '\0' && (s[0] == 'x' || s[0] == 'X'))
	//if (strcmp(s,"x") == 0 || strcmp(s,"X") == 0)
		return x_value;

	serror( ERR_BADVARIABLE);
  return 0; // to make compiler very happy
  
	//printf("\nPlease enter value for variable \"%s\": ", s);
	//scanf("%lf", &vars[kvar].value);
	//strcpy(vars[kvar].name, s);
	//kvar++;
	//return vars[kvar - 1].value;
}

bool strcmp(char *s1, char *s2)
{
	int i;

	for (i = 0;;i++)
	{
		if (s1[i] == '\0')
			if (s2[i] == '\0')
				return 0;
			else
				return 1;
		else
			if (s2[i] == '\0')
				return 1;
			else
			{
				if (s1[i] != s2[i])
					return 1;
			}
	}
}

int look_up(char *s)
{
	int i;

	for (i = 0; i < max_func; i++)
		if (strcmp(s, functions[i].name) == 0)
			return i;
	return 0;	// search command/function name
}

/*
void delete_white(char *buf)
{
	int len = strlen(buf);
	char *d = (char *)malloc(len + 1);
	char *t = buf;
	strcpy(d, buf);
	d[len] = '\0';

	int i;

	for (i = 0; i < len; i++)
		if (!iswhite(d[i]))
			*t++=d[i];
	*t++='\0';
	free(d);
}
*/

/*
void main(void)
{

	 = (parser_struct)malloc(sizeof(parser_struct));
	double a;
	char buffer[256];


	printf("Enter expression: ");
	memset(buffer, 0, 256);
	gets(buffer);

	prog = buffer;
	delete_white(buffer);

	a = 0;
	x_value = 3;
	get_exp( &a);

	printf("result: %lg\n", a);
	getch();

}
*/