calc.y
%{
/************************************
 Calculation  made by T-Satoh
	 Ver 0.01 1999.08.29
	 Ver 0.02 1999.08.31 hex対応
	 Ver 0.03 1999.09.01 '.'処理修正
************************************/

#include <stdio.h>

#define	YYSTYPE	double
#define	CONSOLEAP	0	/* if console AP then set not zero */

#ifdef	DEBUG
#define	DebOut( s )	printf( "<%s>", s )
#else
#define	DebOut( s )
#endif

char	OutBuf[ 64 ];	/* result output buffer */
YYSTYPE	result;
%}

%token	EOL
%token	NUMBER
%token	LP RP
%left	ADDOP SUBOP
%left	MULOP DIVOP
%right	MINUS
%start	s

%%

s		: expr EOL
			{
				result = $1;
				dspresult();
				YYACCEPT;
			}
		;
expr	: expr ADDOP expr
			{	$$ = $1 + $3; }
		| expr SUBOP expr
			{	$$ = $1 - $3; }
		| expr MULOP expr
			{ $$ = $1 * $3; }
		| expr DIVOP expr
			{
				if( $3 == 0.0 ) {
					sprintf( OutBuf, "divieded by zero");
					YYACCEPT;
				} else {
					$$ = $1 / $3;
				}
			}
		| SUBOP expr	%prec MINUS
			{ $$ = -$2; }
		| LP expr RP
			{ $$ = $2; }
		| NUMBER
			{ $$ = $1; }
		;
%%

// yylex の現在の位置
static const char* lexpos = NULL;

#if	CONSOLEAP
#define	ANSFORM	"\nanswer is %f\n"
#define	ANSFORMX "\nanswer is %X\n"
char	Buf[ 128 ];

/* コンソールアプリケーションの場合のメインルーチン */
int main( void )
{
	gets( Buf );
	lexpos = Buf;
	yyparse();
	puts( OutBuf );
}


#else

#define	ANSFORM	"%18.16g"
#define	ANSFORMX "%X"
char	*calculate( const char *buf )
{
	lexpos = buf;
	yyparse();
	return( OutBuf );
}
#endif


void dspresult( void )
{
	if( DspMode == 0 ) {	/* if decimal */
		sprintf( OutBuf, ANSFORM, result );
	} else {
		sprintf( OutBuf, ANSFORMX, (int)result );
	}
}


int isnum( char c )
{
	return( c >= '0' && c <= '9' ? 1 : 0 );
}

char toupperalph( char c )
{
	return( c >= 'a' && c <= 'z' ? c - ( 'a' - 'A' ) : c );
}

int ishex( char c )
{
	return( isnum( c ) || ( c >= 'A' && c <= 'F' ) );
}

int hex( char c )
{
	return( c <= '9' ? c - '0' : c - 'A' + 10 );
}


// 字句解析
static int yylex()
{
	char c;

	c = *lexpos;
	while( c == ' ' ) {	/* 空白読み飛ばし */
		c = *++lexpos;
	}
	lexpos++;
	switch( c ) {
	case '\0':
		DebOut( "EOL" );
		return( EOL );
		break;
	case '+':
		DebOut( "ADDOP" );
		return( ADDOP );
		break;
	case '-':
		DebOut( "SUBOP" );
		return( SUBOP );
		break;
	case '*':
		DebOut( "MULOP" );
		return( MULOP );
		break;
	case '/':
		DebOut( "DIVOP" );
		return( DIVOP );
		break;
	case '(':
		DebOut( "LP" );
		return( LP );
		break;
	case ')':
		DebOut( "RP" );
		return( RP );
		break;
	default:
		if( isnum( c ) || c == '.' ) {
			lexpos--;
			if( c == '0' && *(lexpos + 1) != '.' ) {	/* if hex */
				yylval = 0;
				while( ishex( c = toupperalph( *++lexpos ) ) ) {
					yylval = yylval * 16 + hex( c );
				}
			} else {
				int state;
				double point = 0.1;

				if( c == '.' ) {
					state = 1;
					yylval = 0.0;
				} else {
					state = 2;
					yylval = c - '0';
				}
				while( state ) {
					c = *++lexpos;
					switch( state ) {
					case 2:
						if( isnum( c ) ) {
							yylval = 10.0 * yylval + ( c - '0' );
						}
						else if( c == '.' ) {
							state--;
						} else {
							state = 0;
						}
						break;
					case 1:
						if( isnum( c ) ) {
							yylval += point * ( c - '0' );
							point /= 10.0;
						} else {
							state = 0;
						}
						break;
					}
				}
			}
#ifdef	DEBUG
			printf( "<NUMBER:%f>", yylval );
#endif
			return( NUMBER );
		} else {
			return( c );
		}
		break;
	}
}


int yyerror( char *msg )
{
	sprintf( OutBuf,"%s", msg );
	return( 0 );
}