/* ------------------------------------------------------------------
                        MML compiler [M2]
               programmed by S.Yamamoto (SHINNOSUKE)
                m2libm.c  --  other function source
------------------------------------------------------------------ */

#include	<stdio.h>
#include	<stdlib.h>
#include	<ctype.h>
#include	<string.h>
#include	<limits.h>
#include	<math.h>
#include	"m2.h"

#define	SUCCSESS	0
#define	FAILURE	(-1)
#define	TRUE	1
#define	FALSE	0
#define	ERR	(-1)
#define	YES	1
#define	NO	0

char	*expMsg = "EXPRESSION";
char	*expBuf;
int	ch;

/* 四則演算処理 */

void	readch( void )
{
	ch = *expBuf;
	expBuf++;
	return;
}

int	number( void )
{
	int	x;
	int	dummy;
	int	sign;
	int	radix = 10;

	if ( ch == '+' || ch == '-' ) {
		sign = ch;
		readch();
	}
	if (! isdigit(ch)) errMsg(MSG_syntax,expMsg);
	if (ch == '0') {
		if(toupper(*expBuf) == 'X')	radix=16;
		if(toupper(*expBuf) == 'B')	radix=2;
		if(toupper(*expBuf) == 'O')	radix=8;
		if(radix != 10)	expBuf++;
	}
	x = ch - '0';
	for(;;) {
		readch();
		ch=toupper(ch);
		if (isdigit(ch) == 0 && ch<'A' && ch>'F')	break;

		dummy=(ch>='A'&&ch<='F')?ch-'A'+10:ch-'0';
		if(dummy<0 || dummy>=radix)	break;
		x=dummy+x*radix;
	}

	if (sign == '-') return -x;  else return x;
}

int	factor( void )
{
	int	x;

	if (ch != '(') return number();
	readch();
	x = expression();
	if (ch != ')')
		errMsg(MSG_syntax,expMsg);
	readch();
	return x;
}

int	term( void )
{
	int	x;
	int	y;

	x = factor();
	for ( ; ; )
		if (ch == '*') {
			readch();  x *= factor();
		} else if (ch == '/') {
			readch();  y = factor();
			if (y == 0) errMsg(MSG_freerr,"Divide by zero(EXPRESSION)");
			x /= y;
		} else if (ch == '%') {
			readch();  x %= factor();
		} else break;
	return x;
}

int	expression( void )
{
	int	x;

	x = term();
	for ( ; ; )
		if (ch == '+') {
			readch();  x += term();
		} else if (ch == '-') {
			readch();  x -= term();
		} else break;
    return x;
}

int	calc( char **str )
{
	char	*p;
	char	buf[256];

	int	n = 0;
	int	x;
	int	dummy = 0;

	p=*str;
	if(*p!='(')	errMsg(MSG_syntax,expMsg);
	p++;
	for(;;){
		p=skipSpace(p);
		if(*p=='\0')	errMsg(MSG_syntax,expMsg);
		if(*p=='(')	dummy++;
		if(*p==')')	dummy--;
		if(dummy<0) {
			buf[n]='\0';
			break;
		}
		buf[n]=*p;
		p++;
		n++;
		if(n>255)	errMsg(MSG_syntax,expMsg);
	}
	p++;
	*str=p;

	expBuf=&buf[0];

	readch();  x = expression();
	if (ch != '\0') errMsg(MSG_syntax,expMsg);
	return(x);
}

/* その他 */

int	comSearch( char *c[],char *s )	/* コマンド検索 */
{
	int	n = 0;
	int	ret = ERR;

	while( c[n][0] != '\0' ) {
		if( strncmp( s,c[n],strlen( c[n] )) == 0 ) {
			ret = n;
			break;
		}
		n++;
	}
	return( ret );
}

char	*skipSpace( char *s )	/* スペースを飛ばす */
{
	while( *s == ' ' )
		s++;
	return( s );
}

void	skipLine( char **s )	/* 空行を飛ばす */
	/* [EOF]だった場合はＮＵＬＬを指しているポインターを返す */
{
	char	*p;
	char	*q;

	p = *s;
	p = skipSpace( p );

	for(;;) {
		q = p;
		if( *p == '\0' ) {
			if(( p = Pre_fgets()) == NULL ) {
				p = q;
				break;	/* [EOF] */
			}
			p = skipSpace( p );
		}
		if( *p != '\0' )	break;
	}
	*s = p;
}

int	power( int x ,int y ) /* ｉｎｔ型の累乗 */
{
	int	i;
	long	ret = x;

	if ( y == 0 )
		return(1);
	for( i=1;i<y;i++ )
		ret = ret*x;
	return( (int)ret );
}

double	sine( double xx ) /* サイン（度からラジアンに変換）*/
{
	double	x = ((xx)/180*3.14159265358979323846);	/* deg>rad */
	return( sin(x) );
}

int	instr( const char *s ,int c ) /* １文字検索 */
{
	int	i;
	int	l;
	int	ret = ERR;

	l = strlen( s );
	for( i=0;i<l;i++ ) {
		if( *(s+i) == c ) {
			ret = i;
			break;
		}
	}
	return( ret );
}

int	strToInt( char **p ,int min ,int max ,int d ,char *m2 )
	/* アスキー文字からｉｎｔ型への変換 */
{
	char	*msg = "(param)";
	char	*s;
	int	pm = 1;	/* plus or minas */
	int	flags = NO;
	int	dummy;
	long	int	dat = 0;
	long	int	da2 = 0;

	if ( m2 != NULL )	msg = m2;
	s = skipSpace( *p );

	switch( *s ) {
		case '+':
			s++;
			break;
		case '-':
			s++;
			pm = -1;
			break;
		case '?':
			s++;
			dat = (long)calc( &s );
			goto	Point;
	}
	
	for(;;) {
		dummy = toupper( *s );
		dummy -= '0';
		if( dummy < 0 || dummy > 9 )	break;
		dat = dummy + dat*10;
		da2 = dat*pm;
		if( da2 > INT_MAX || da2 < INT_MIN )
			errMsg( MSG_illfnc ,msg );
		flags = YES;
		s++;
	}
	dat = dat*pm;
	if( flags == NO )
		dat = (long)d;
Point:
	if( dat < min || dat > max )
		errMsg( MSG_illfnc ,msg );
	*p = s;
	return( (int)dat );
}
