Skip to content

Instantly share code, notes, and snippets.

@garyburd
Created December 8, 2011 07:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save garyburd/1446409 to your computer and use it in GitHub Desktop.
Save garyburd/1446409 to your computer and use it in GitHub Desktop.
My first C program
/* rpn.c -- reverse polish notation calculator. G.S.BURD 25-Mar-1984 */
#include <math.h>
#include <stdio.h>
#include <ctype.h>
extern char *fgets();
extern double push(), pop();
/* function codes */
#define TRUE 1
#define FALSE 0
#define EXITPROGRAM 1
#define GIVEHELP 2
#define CLEAR 3
#define CHANGESIGN 4
#define ADD 5
#define SUBTRACT 6
#define MULTIPLY 7
#define DIVIDE 8
#define RECIPROCAL 9
#define SQUARE 10
#define SQUAREROOT 11
#define SINE 12
#define COSINE 13
#define TANGENT 14
#define ARCSINE 15
#define ARCOSINE 16
#define ARCTANGENT 17
#define RADIAN 18
#define DEGREE 19
#define PI 20
#define NATURALLOG 21
#define BASE10LOG 22
#define ETOTHEX 23
#define POWER 24
#define NUMFUNCTIONS 24
#define UNKNOWN -1
#define NUMBER 0
/* function table; must be in lexical order */
struct function {
char *text;
int code;
} funtable[] = {
"*", MULTIPLY,
"+", ADD,
"-", SUBTRACT,
"/", DIVIDE,
"?", GIVEHELP,
"acos", ARCOSINE,
"asin", ARCSINE,
"atan", ARCTANGENT,
"chs", CHANGESIGN,
"clr", CLEAR,
"cos", COSINE,
"deg", DEGREE,
"exp", ETOTHEX,
"ln", NATURALLOG,
"log", BASE10LOG,
"pi", PI,
"pow", POWER,
"rad", RADIAN,
"rec", RECIPROCAL,
"sin", SINE,
"sqr", SQUARE,
"sqrt", SQUAREROOT,
"tan", TANGENT,
"\0", 0,
};
#define MAXOP 40 /* max size of operand, operator */
#define MAXLINE 132 /* max size of a line */
#define RADPERDEG (3.1415926535897 / 180.0)
main(argc, argv)
int argc;
char *argv[];
{
char line[MAXLINE];
if (argc <= 1) {
printf("\t\t\t> ");
while ( fgets( line, MAXLINE, stdin) != NULL ) {
process( line );
print_top();
printf( "\t> ");
}
}
else {
while (--argc > 0)
process( *++argv );
print_top();
}
}
/* process -- process a string */
process( str )
char str[];
{
char s[MAXOP];
int i;
i = 0;
while ( i = getword( str, i, s ) )
dofun( getfun( s ), s );
}
/* getword -- get next word from str at i */
getword( str, i, out )
char str[], out[];
int i;
{
int j;
while ( isspace( str[i] ) )
i++;
if( str[ i ] == '\0' ) return( 0 );
j = 0;
while ( ( ! isspace( str[i] ) ) && ( str[i] != '\0' ) )
out[ j++ ] = tolower( str[ i++ ] );
out[ j ] = '\0';
return( i );
}
/* getfun -- get function code from s */
getfun( s )
char s[];
{
int high, low, mid, cond;
if ( isanumber(s) )
return( NUMBER );
else {
low = 0;
high = NUMFUNCTIONS - 1;
while ( low <= high ) {
mid = ( low + high ) / 2;
if (( cond = strcmp( s, funtable[mid].text )) < 0 )
high = mid - 1;
else if ( cond > 0 )
low = mid + 1;
else
return( funtable[mid].code );
}
return( UNKNOWN );
}
}
/* isanumber -- determine if s contains a digit */
isanumber( s )
char s[];
{
int i;
for( i = 0; s[i] != '\0'; i++ )
if ( isdigit( s[i] ) ) return( TRUE );
return( FALSE );
}
/* dofun -- do a function */
dofun( i, s )
int i;
char s[];
{
static double degrad = 1.0;
double op, op2;
double atof(), pop(), push();
switch ( i ) {
case NUMBER:
push( atof(s) );
break;
case ADD:
push( pop() + pop() );
break;
case SUBTRACT:
op2 = pop();
push( pop() - op2 );
break;
case MULTIPLY:
push( pop() * pop() );
break;
case DIVIDE:
op2 = pop();
if ( op2 != 0.0 )
push( pop() / op2 );
else {
push( op2 );
printf("? zero divisor\n");
}
break;
case RECIPROCAL:
op = pop();
if ( op != 0.0 )
push( 1.0 / op );
else {
push( op );
printf("? zero divisor\n");
}
break;
case CHANGESIGN:
push( pop() * -1.0 );
break;
case DEGREE:
degrad = RADPERDEG;
break;
case RADIAN:
degrad = 1.0;
break;
case PI:
push( 3.1415926535897 );
break;
case ARCOSINE:
op = pop();
if ( fabs(op) <= 1.0 )
push( acos(op) / degrad );
else {
push( op );
printf("? |x| > 1 for acos\n");
}
break;
case ARCSINE:
op = pop();
if ( fabs(op) <= 1.0 )
push( asin( op ) / degrad );
else {
push( op );
printf("? |x| > 1 for asin\n");
}
break;
case ARCTANGENT:
push( atan( pop() ) / degrad );
break;
case COSINE:
push( cos( pop() * degrad ) );
break;
case ETOTHEX:
push( exp( pop() ) );
break;
case NATURALLOG:
op = pop();
if ( op > 0.0 )
push( log( op ) );
else {
push( op );
printf("? x <= 0 for ln\n");
}
break;
case BASE10LOG:
op = pop();
if ( op > 0.0 )
push( log10( op ) );
else {
push( op );
printf("? x <= 0 for ln\n");
}
break;
case POWER:
op2 = pop();
push( pow( pop(), op2 ) );
break;
case SINE:
push( sin( pop() * degrad ) );
break;
case SQUAREROOT:
op = pop();
if( op < 0.0 ) {
push( op );
printf("? x < 0 for sqrt\n");
}
else
push( sqrt( op ) );
break;
case SQUARE:
op = pop();
push( op * op );
break;
case TANGENT:
push( tan( pop() * degrad ) );
break;
case CLEAR:
clear();
break;
case GIVEHELP:
help();
break;
case UNKNOWN:
printf("? unknown function \"%s\",\n type \"?\" for help\n",s);
break;
};
error_clear();
}
/* help -- print out help information */
help()
{
int i;
printf("\n\nthe available functions are:\n");
for(i=0; i < NUMFUNCTIONS; i++)
printf((i % 7) ? " %-5s" : "\n%-5s", funtable[i].text );
printf("\n");
}
/* s t a c k r o u t i n e s */
#define MAXVAL 127
int stack_ptr = 0; /* index of top value on stack */
double stack_val[MAXVAL]; /* the value stack */
int stack_err = 0; /* non zero on stack error */
/* push -- pushes f on value stack */
double push( f )
double f;
{
if ( stack_err ) return( 0 );
if ( stack_ptr < MAXVAL )
return( stack_val[ ++stack_ptr ] = f );
else {
printf("? stack is full\n");
++stack_err;
return( 0 );
}
}
/* pop -- pops top value from stack */
double pop()
{
if ( stack_err ) return( 0 );
if ( stack_ptr > 0 )
return( stack_val[ stack_ptr-- ] );
else {
printf("? stack is empty\n");
++stack_err;
return( 0 );
}
}
/* clear -- clear the stack */
clear()
{
stack_ptr = 0;
}
/* print_top -- print the top of the stack */
print_top()
{
if ( stack_ptr <= 0 )
printf(" "); /* print blanks if it is empty */
else
printf( "%16g" ,stack_val[ stack_ptr ] );
}
/* error_clear -- clear errors on stack access */
error_clear()
{
stack_err = 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment