here it goes
#include stdio.h>
#include stdlib.h>
#include string.h>
#include ctype.h>
#define T_EOL ';'
#define T_CONST 'C'
#define T_SYMBOL 'S'
#define T_LPAR '('
#define T_RPAR ')'
#define T_COMMA ','
#define T_ASSIGN '='
#define T_POINT '$'
#define T_MUL '*'
#define T_DIV '/'
#define T_MOD '%'
#define T_ADD '+'
#define T_SUB '-'
#define T_NEG '_'
#define T_NOT '~'
#define T_SHL 'L'
#define T_SHR 'R'
#define T_AND '&'
class StringCalculator {
// I don't know why defining another class makes all messages of redefinitions...,
// just put postfix calcualtor here
public:
StringCalculator();
double push_eval( double val );
double push( double val );
double pop_eval();
double pop();
char getoken(int* v = NULL);
int isbinop( char** cpp );
int expression();
double evaluate();
int primary();
int binop( char op );
int op_prim( int precedence, int lvalue );
void generate( char tkn, double val, int index=-1 );
double calc( char* line );
void setup_symbol(int index, double value);
#define STAKSZ 128
struct OPSTK {
char o_token;
double o_value;
int symbol_index;
} Opstk[ STAKSZ ];
int Opbase;
int Opsp;
double Valstk[ STAKSZ ];
int Valbase;
int Valsp;
double Valstk_eval[ STAKSZ ];
int Valbase_eval;
int Valsp_eval;
double Symbols[26];
double Value;
char buff[128];
#define MAXLEVEL 32
char Level; /* current recursion level in calc() */
char Token; /* current input token */
char Eol; /* set when end of line encountered */
char *Lineptr; /* points to next character in input line */
char *Ofmt; /* current output format (set by "base" command) */
int Error; /* set if parsing error occurred */
char Nohelp; /* set if help was given already */
int symbol_index;
};
StringCalculator::StringCalculator()
{
Nohelp = 1;
Level = 0;
Token = 0;
Eol = 0;
Lineptr = NULL;
Ofmt = NULL;
Error = 0;
Nohelp = 0;
Opbase=0;
Opsp=0;
Valbase=0;
Valsp=0;
push( 10 );
for( int i=0; i<26; i++ )
{
Symbols[i]=0;
}
}
void StringCalculator::setup_symbol(int index, double value)
{
Symbols[index] = value;
}
double StringCalculator::calc( char* line )
{
char *savLineptr;
int savValbase, savValsp, savOpbase, savOpsp;
/* save in my buff */
strncpy(buff, line, 128);
line = buff;
if ( ++Level > MAXLEVEL )
{
printf("recursion\n");
}
else
{
savLineptr = Lineptr;
savValbase = Valbase;
savValsp = Valsp;
savOpbase = Opbase;
savOpsp = Opsp;
Valbase = Valsp;
Opbase = Opsp;
Lineptr = line;
Eol = 0;
if ( getoken() != T_EOL )
{
expression();
if ( Error <= 0 )
{
}
else {
printf("parse error: %s\n", buff);
}
}
}
return 0.0;
}
double StringCalculator::evaluate()
{
int opsp;
double val;
char op;
Valsp_eval = Valsp;
Valbase_eval = Valbase;
memcpy(Valstk_eval, Valstk, sizeof(Valstk));
#define TOS (Valstk_eval[Valsp_eval-1]) /* top of stack macro */
for ( opsp=Opbase; opsp
op = Opstk[ opsp ].o_token;
if ( op == T_CONST )
{
push_eval( Opstk[ opsp ].o_value );
}
else if ( op == T_SYMBOL )
{
push_eval( Symbols[Opstk[ opsp ].symbol_index] );
}
else if ( op == T_ADD )
{
val = pop_eval();
TOS += val;
}
else if ( op == T_SUB )
{
val = pop_eval();
TOS -= val;
}
else if ( op == T_NEG )
TOS = -TOS;
else if ( op == T_MUL )
{
val = pop_eval();
TOS *= val;
}
else if ( op == T_DIV )
{
val = pop_eval();
TOS /= val;
}
else
printf( "bad operator in stack: 0x%x (%c)\n", op, op );
}
return Valstk_eval[ Valbase_eval ];
}
double StringCalculator::push( double val )
{
if ( Valsp >= STAKSZ )
printf( "stack overflow" );
return Valstk[ Valsp++ ] = val;
}
double StringCalculator::pop()
{
if ( --Valsp < 0 )
Valsp = 0;
return Valstk[ Valsp ];
}
double StringCalculator::push_eval( double val )
{
if ( Valsp_eval >= STAKSZ )
printf( "stack overflow" );
return Valstk_eval[ Valsp_eval++ ] = val;
}
double StringCalculator::pop_eval()
{
if ( --Valsp_eval < 0 )
Valsp_eval = 0;
return Valstk_eval[ Valsp_eval ];
}
int StringCalculator::expression()
{
int lvalue;
if ( !(lvalue = primary()) )
{
printf( "bad expression" );
}
else if ( Eol )
{
if ( lvalue < 0 )
generate( T_POINT, 0 );
}
else
{
op_prim( 0, lvalue );
}
return 1;
}
int StringCalculator::op_prim( int precedence, int lvalue )
{
char tkn;
int pr, lv;
while ( ! Eol )
{
pr = binop( Token );
if (
(pr>precedence && pr>0) ||
(Token==T_ASSIGN && pr>=precedence)
)
{
if ( Token == T_ASSIGN )
{
if ( lvalue > 0 )
printf( "= needs and lvalue" );
}
else if ( lvalue < 0 )
generate( T_POINT, 0 );
tkn = Token;
getoken();
if ( ! (lv = primary()) )
printf( "missing an operand" );
lvalue = op_prim( pr, lv );
if ( Token != T_ASSIGN && lvalue < 0 )
{
generate( T_POINT, 0 );
lvalue = 1;
}
else if ( tkn!=T_ASSIGN && Token==T_ASSIGN )
{
printf( "= needs an lvalue" );
}
generate( tkn, 0 );
}
else
break;
}
return lvalue;
}
int StringCalculator::primary()
{
int rtn;
if ( Eol )
return 0;
rtn = 1;
switch ( Token )
{
case T_SYMBOL: /* a symbol */
generate( Token, Value, symbol_index );
getoken();
break;
case T_CONST: /* a constant */
generate( Token, Value );
getoken();
break;
case T_LPAR: /* a parenthesized expression */
getoken();
expression();
if ( Token != T_RPAR )
{
printf( "missing ')'" );
rtn = 0;
}
else
getoken();
break;
case T_SUB: /* unary - */
getoken();
expression();
generate( T_NEG, 0 );
break;
case T_NOT: /* unary ~ */
getoken();
expression();
generate( T_NOT, 0 );
break;
case T_ADD: /* unary + */
getoken();
expression();
break;
default:
rtn = 0;
}
return rtn;
}
int StringCalculator::binop( char op )
{
switch ( op )
{
case T_ADD:
case T_SUB:
return 7;
case T_MUL:
case T_DIV:
case T_MOD:
return 8;
case T_NOT:
return 9;
}
return 0;
}
void StringCalculator::generate( char tkn, double val, int index )
{
if ( Opsp < STAKSZ )
{
Opstk[ Opsp ].o_token = tkn;
Opstk[ Opsp ].o_value = val;
Opstk[ Opsp ].symbol_index = index;
++Opsp;
}
else
printf( "expression too complex" );
}
char StringCalculator::getoken(int* )
{
char *cp, buf[ 128 ];
if ( ! *Lineptr )
{
Eol = 1;
Token = T_EOL;
}
else if ( isdigit( *Lineptr ) )
{
Token = T_CONST;
for ( cp = buf; isdigit( *Lineptr ) || *Lineptr == '.'; )
*cp++ = *Lineptr++;
*cp = 0;
Value = atof(buf);
}
else if ( (Token = isbinop( &Lineptr )) )
{
;
}
else if ( isalpha( *Lineptr ) )
{
Token = T_SYMBOL;
symbol_index = toupper( *Lineptr ) - 'A';
++Lineptr;
}
else
{
printf( "bad syntax: %s", Lineptr );
++Lineptr;
}
return Token;
}
int StringCalculator::isbinop( char** cpp )
{
int tkn=1;
char c;
c = **cpp;
if ( c == ',' )
tkn = T_COMMA;
else if ( c == '=' )
tkn = T_ASSIGN;
else if ( c == '<' )
{
if ( *(++(*cpp)) == '<' )
tkn = T_SHL;
}
else if ( c == '>' )
{
if ( *(++(*cpp)) == '>' )
tkn = T_SHR;
}
else if ( c == '(' )
tkn = T_LPAR;
else if ( c == ')' )
tkn = T_RPAR;
else if ( c == '*' )
tkn = T_MUL;
else if ( c == '/' )
tkn = T_DIV;
else if ( c == '+' )
tkn = T_ADD;
else if ( c == '-' )
tkn = T_SUB;
else
tkn = 0;
if ( tkn )
++(*cpp);
return tkn;
}
No comments:
Post a Comment