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 );
}