%{
/*
Auto:		smake MCalc
*/

static void	__yy_bcopy(char *from, char *to, int count);

#undef		alloca
#define		alloca(x) AllocVecPool(ParsePool, x)
#undef		malloc
#define		malloc(x) AllocVecPool(ParsePool, x)
#undef		free
#define		free(x) FreeVecPool(ParsePool, x)

#undef		YYINITDEPTH
#define		YYINITDEPTH 512

#undef		_STDC_
#define		_STDC_

#undef		error
#define		error

extern		APTR		ParsePool;
extern		double		Value;
extern		double		XMem, YMem, ZMem;

#define		outputr(x)	{Value = x;}
#define		outputx(x)	{Value = XMem = x;}
#define		outputy(x)	{Value = YMem = x;}
#define		outputz(x)	{Value = ZMem = x;}
#define		errout(x)	;
#define		erroutm(x, y)	;


/**********************************************************************/
/*                    Chars read and read-position                    */
/**********************************************************************/
extern	UWORD	PColumn;
extern	UWORD	PCharRead;


	// This is for the wanted angle

extern	UWORD		IntAngle;


/**********************************************************************/
/*                            Error-Value                             */
/**********************************************************************/
UWORD		PError;
%}



/**********************************************************************/
/*                       Possible Return-Value                        */
/**********************************************************************/
%union
{
	double	Real;
}


/**********************************************************************/
/*                      Token which returns Real                      */
/**********************************************************************/
%token <Real>   INT_CONSTANT
%token <Real>   X_MEM Y_MEM Z_MEM



/**********************************************************************/
/*                       Non-Priority functions                       */
/**********************************************************************/
%token EQU_OP OPEN_OP CLOSE_OP



/**********************************************************************/
/*                           Set priorities                           */
/**********************************************************************/
%left AND_OP OR_OP XOR_OP ASL ASR LSL LSR ROL ROR
%left ADD_OP SUB_OP
%left MUL_OP DIV_OP MOD_OP
%left NEG_OP NOT_OP PERCENT CHPERCENT TPERCENT
%left POW
%nonassoc MY_ABS COS SIN TAN ACOS ASIN ATAN EXP LOG LOG10 SQRT SINH COSH TANH FAK COT



/**********************************************************************/
/*                    Return-Value of my terminal                     */
/**********************************************************************/
%type <Real>   int_expr

%%



/**********************************************************************/
/*                          Main "sentence"                           */
/**********************************************************************/
eingabe
	: int_expr					{outputr($1);}
	| X_MEM EQU_OP int_expr				{outputx($3);}
	| Y_MEM EQU_OP int_expr				{outputy($3);}
	| Z_MEM EQU_OP int_expr				{outputz($3);}
	| error
	;




/**********************************************************************/
/*                           Do the grammar                           */
/**********************************************************************/
int_expr
	: OPEN_OP int_expr CLOSE_OP			{$$ = $2;}
	| int_expr AND_OP int_expr			{$$ = (make_ulong($1)) & (make_ulong($3));}
	| int_expr OR_OP int_expr			{$$ = (make_ulong($1)) | (make_ulong($3));}
	| int_expr XOR_OP int_expr			{$$ = MyXOR(make_ulong($1),make_ulong($3));}
	| int_expr NOT_OP AND_OP int_expr		{$$ = MyNAND(make_ulong($1), make_ulong($4));}
	| int_expr NOT_OP OR_OP int_expr		{$$ = MyNOR(make_ulong($1), make_ulong($4));}
	| int_expr NOT_OP XOR_OP int_expr		{$$ = MyNXOR(make_ulong($1), make_ulong($4));}
	| int_expr ADD_OP int_expr PERCENT		{$$ = ($1 + (($1 * $3) / 100));}
	| int_expr SUB_OP int_expr PERCENT		{$$ = ($1 - (($1 * $3) / 100));}
	| int_expr MUL_OP int_expr PERCENT		{$$ = (($1 * $3) / 100);}
	| int_expr CHPERCENT int_expr			{$$ = ((($3 - $1) * 100) / $1);}
	| int_expr TPERCENT int_expr			{$$ = (($3 * 100) / $1);}
	| int_expr ADD_OP int_expr			{$$ = $1 + $3;}
	| int_expr SUB_OP int_expr			{$$ = $1 - $3;}
	| int_expr MUL_OP int_expr			{$$ = $1 * $3;}
	| int_expr DIV_OP int_expr			{if($3 == 0.0) {PError = ERR_DIVBY0; yyerror(NULL); } else $$ = $1 / $3;}
	| int_expr MOD_OP int_expr			{if($3 == 0.0) {PError = ERR_DIVBY0; yyerror(NULL); } else $$ = fmod($1,$3);}
	| SUB_OP int_expr %prec NEG_OP			{$$ = -$2; }
	| NOT_OP int_expr				{$$ = (~make_ulong($2)); }
	| int_expr ASL int_expr				{$$ = (double)MyASL(make_ulong($1),make_ulong($3)); }
	| int_expr ASR int_expr				{$$ = (double)MyASR(make_ulong($1),make_ulong($3)); }
	| int_expr LSL int_expr				{$$ = (double)MyLSL(make_ulong($1),make_ulong($3)); }
	| int_expr LSR int_expr				{$$ = (double)MyLSR(make_ulong($1),make_ulong($3)); }
	| int_expr ROL int_expr				{$$ = (double)MyROL(make_ulong($1),make_ulong($3)); }
	| int_expr ROR int_expr				{$$ = (double)MyROR(make_ulong($1),make_ulong($3)); }
	| int_expr POW int_expr				{$$ = pow($1,$3); }
	| SIN int_expr					{$$ = sin(calc_angle($2)); }
	| COS int_expr					{$$ = cos(calc_angle($2)); }
	| TAN int_expr					{$$ = tan(calc_angle($2)); }
	| ASIN int_expr					{$$ = asin(calc_angle($2)); }
	| ACOS int_expr					{$$ = acos(calc_angle($2)); }
	| ATAN int_expr					{$$ = atan(calc_angle($2)); }
	| COT int_expr					{$$ = cot(calc_angle($2)); }
	| SINH int_expr					{$$ = sinh(calc_angle($2)); }
	| COSH int_expr					{$$ = cosh(calc_angle($2)); }
	| TANH int_expr					{$$ = tanh(calc_angle($2)); }
	| EXP int_expr					{$$ = exp($2); }
	| LOG int_expr					{$$ = log($2); }
	| LOG10 int_expr				{$$ = log10($2); }
	| MY_ABS int_expr				{$$ = fabs($2); }
	| SQRT int_expr					{if($2 < 0.0) {PError = ERR_OVERFLOW; yyerror(NULL); } else $$ = sqrt($2);}
	| int_expr FAK					{if($1 > 170.0) { PError = ERR_OVERFLOW; yyerror(NULL); } else $$ = calc_fak($1);}
	| FAK int_expr					{if($2 > 170.0) { PError = ERR_OVERFLOW; yyerror(NULL); } else $$ = calc_fak($2);}
	| INT_CONSTANT
	| X_MEM
	| Y_MEM
	| Z_MEM
	;

%%




/**********************************************************************/
/*             Convert a double to a long (the hard way)              */
/**********************************************************************/
ULONG make_ulong(double OldVal)
{
	char	Buffer[26];
	ULONG	Dummy;

	sprintf(Buffer, "%f", OldVal);
	stcd_l(Buffer, (LONG *)&Dummy);
	return(Dummy);
}





/**********************************************************************/
/*                           Calculate Fak                            */
/**********************************************************************/
double calc_fak(double Fak)
{
	double	RetVal = 1.0, i = 1.0;

	while(i <= Fak)
	{
		RetVal *= i;
		i++;
	}

	return(RetVal);
}





/**********************************************************************/
/*              Calculate correct angle value (rad, deg)              */
/**********************************************************************/
double calc_angle(double Value)
{
	if(IntAngle == ID_DEG)
		Value = (Value / 180.0) * Pi;

	return(Value);
}



/**********************************************************************/
/*                          Error-Routine ;)                          */
/**********************************************************************/
int yyerror(char *s)
{
	return(0);
}
