View Single Post
  #2 (permalink)  
Old 05-28-2006, 11:43 AM
ravs2k6 ravs2k6 is offline
Newbie
 
Join Date: May 2006
Posts: 25
Credits: 0
Rep Power: 10
ravs2k6 is on a distinguished road
Default

hey...The hard part is operator precedence. For that it's much much easier to convert the expression to postfix and then use a stack based evaluation to solve it. Once you have the tokens in postfix form, it's a trivial affair to solve the equation. For example, here's a postfix calculator with a lot of functionality:

#include ctype.h
#include math.h
#include stdio.h
#include stdlib.h
#include string.h

#define UNARY 0 /* Offset into actions for unary words */
#define BINARY 6 /* Offset into actions for binary words */
#define ACLEN 17 /* Total number of actions */
#define UNLEN 6 /* Total number of unary words */
#define BILEN 11 /* Total number of binary words */

static const char *actions[] = {
".", "sqrt", "sq", "not", "abs", "log",
"+", "-", "*", "/", "mod", "pow",
"<", "=", ">", "and", "or",
};

static long int stack[1024]; /* 1024 should be MORE than enough */
static int top = 0;

static void eval ( void );
static void gather ( void );
static void process ( const char *action );
static void do_unary ( const char *action );
static void do_binary ( const char *action );
static void die ( const char *msg );

static int is_valid ( const char *action, size_t offset, size_t limit );

int main ( void )
{
while ( 1 )
eval();
}

void eval ( void )
{
gather();
puts ( " ok" );
}

void gather ( void )
{
char buffer[BUFSIZ];
char *action;
char *end;

if ( fgets ( buffer, sizeof buffer, stdin ) == NULL )
die ( "Input error" );

for ( action = strtok ( buffer, " \t\n" );
action != NULL; action = strtok ( NULL, " \t\n" ) )
{
long int number;

/* Process a number or an action */
number = strtol ( action, &end, 0 );
if ( end > action )
stack[top++] = number;
else if ( is_valid ( action, 0, ACLEN ) )
process ( action );
else if ( strcmp ( action, "bye" ) == 0 )
exit ( EXIT_SUCCESS );
else
die ( "Input error" );
}
}

void process ( const char *action )
{
if ( is_valid ( action, UNARY, UNLEN ) )
do_unary ( action );
else if ( is_valid ( action, BINARY, BILEN ) )
do_binary ( action );
}

void do_unary ( const char *action )
{
long int result = 0;
long int a;

if ( top == 0 )
die ( "Stack underflow" );
a = stack[--top];

if ( strcmp ( action, "." ) == 0 ) {
printf ( "%ld ", a );
fflush ( stdout );
return;
}
else if ( strcmp ( action, "not" ) == 0 )
result = !a;
else if ( strcmp ( action, "sqrt" ) == 0 )
result = (long int)sqrt ( a );
else if ( strcmp ( action, "sq" ) == 0 )
result = a * a;
else if ( strcmp ( action, "abs" ) == 0 )
result = abs ( a );
else if ( strcmp ( action, "log" ) == 0 )
result = (long int)log ( a );
else
die ( "Invalid format" );

stack[top++] = result;
}

void do_binary ( const char *action )
{
long int result = 0;
long int a, b;

if ( top < 2 )
die ( "Stack underflow" );
b = stack[--top];
a = stack[--top];

if ( action[0] == '+' )
result = a + b;
else if ( action[0] == '-' )
result = a - b;
else if ( action[0] == '*' )
result = a * b;
else if ( action[0] == '/' ) {
if ( b == 0 )
die ( "Division by zero" );
result = a / b;
}
else if ( strcmp ( action, "mod" ) == 0 ) {
if ( b == 0 )
die ( "Division by zero" );
result = a % b;
}
else if ( strcmp ( action, "pow" ) == 0 )
result = (long int)pow ( a, b );
else if ( action[0] == '<' )
result = a < b;
else if ( action[0] == '=' )
result = a == b;
else if ( action[0] == '>' )
result = a > b;
else if ( strcmp ( action, "and" ) == 0 )
result = a && b;
else if ( strcmp ( action, "or" ) == 0 )
result = a || b;
else
die ( "Invalid format" );

stack[top++] = result;
}

int is_valid ( const char *action, size_t offset, size_t limit )
{
size_t i;

for ( i = offset; i < limit + offset; i++ ) {
if ( strcmp ( action, actions[i] ) == 0 )
return 1;
}

return 0;
}

void die ( const char *msg )
{
fprintf ( stderr, "%s\n", msg );
exit ( EXIT_FAILURE );
}


It's very short, but very powerful. That's because all of the parsing work is done by the stack, not the program logic.

Last edited by ravs2k6; 05-28-2006 at 11:55 AM.
Reply With Quote