Code:
#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.