Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 7.05 on page 159

Rewrite the postfix calculator of Chapter 4 to use scanf and/or sscanf to do the input and number conversion.



Solution by Toni Romic

/* K&R Exercise 7-5 */
/* Toni Romic */

   #include <stdio.h>
   #include <stdlib.h>

   #define MAXOP 100 /* max size of operand or operator */

   void push(double);
   double pop(void);

   int main()
   {
       char *c;
       char s[MAXOP], buf[MAXOP];
       double a = 0, op2;
       char e = '\0';

       while (scanf("%s%c", s, &e) == 2) { /* get no-space string and space behind it */
             if (sscanf(s, " %lf", &a) == 1) /* is it a number */
                 push(a);
             else if (sscanf(s, "%s", buf)) {
                 for (c = buf ; *c; c++) {
                     switch (*c) {
                     case '+':
                         push(pop() + pop());
                         break;
                     case '-':
                         op2 = pop();
                         push(pop() - op2);
                         break;
                     case '*':
                         push(pop() * pop());
                         break;
                     case '/':
                         op2 = pop();
                         if (op2 != 0.0)
                             push(pop() / op2);
                         else
                             printf("error: zero divisor\n");
                         break;
                     default:
                         printf("Unknown command\n");
                         break;
                     }
                 } /* for */
                 if (e == '\n') /* print result */
                     printf("\t%.8g\n", pop());
             }
       }
       return 0;
   }

   #define MAXVAL 100  /* maximum depth of val stack */

   static int sp = 0;  /* next free stack position */
   static double val[MAXVAL]; /* value stack */

   /* push(): push f onto value stack */
   void push(double f)
   {
       if (sp < MAXVAL)
           val[sp++] = f;
       else
           printf("error: stack full, can't push %g\n", f);
   }

   /* pop(): pop and return top value from stack */
   double pop(void)
   {
       if (sp > 0)
           return val[--sp];
       else {
           printf("error: stack empty\n");
           return 0.0;
       }
   }

Solution by anonymous

I converted the old calculator using scanf and sscanf. I then added support for 16 different types of mathematical operations. Here is my code

#include <stdio.h>
#include <string.h>
#include <math.h>

/*
    Exercise 7-5. Rewrite the postfix calculator of Chapter 4 to use scanf and/or sscanf to do the input and number conversion.
*/

#define MAXOP 100  // max size of operand or operator
#define MAXVAL 100 // maximum depth of val stack

int sp = 0;         // next free stack position
double val[MAXVAL]; // value stack

void push(double f);
double pop(void);

// reverse Polish calculator
int main()
{
    printf("Reverse Polish calculator usage:\nConvert something like (1 - 2) * (4 + 5) to 1 2 - 4 5 + * for reverse Polish notation\n");
    printf("This calculator supports adding (+) subtracting (-) multiplying (*) dividing (/) modulo operation (%%), exponentiation (^),\n");
    printf("exponential function (e), square root function (r), sine operation (s), cosine operation (o), tangent operation (t),\n");
    printf("absolute value function (a), common logarithm (l), natural logarithm (n), ceiling operation (c), and flooring operation (f)\n");
    double op2, num;
    char s[MAXOP], c;

    while (scanf("%s%c", s, &c) == 2) // found something. If EOF provided, this loop will terminate. However, if \n is provided, it will not terminate
    {
        if (sscanf(s, "%lf", &num) == 1) // found a number
            push(num);
        else if (strlen(s) == 1) // found an operator
        {
            switch (*s)
            {
            case '+':
                push(pop() + pop());
                break;
            case '-': /* In push(pop() - pop());, the order in which the two calls of pop are evaluated is not defined. So get op2 first then process */
                op2 = pop();
                push(pop() - op2);
                break;
            case '*':
                push(pop() * pop());
                break;
            case '/':
                op2 = pop();
                if (op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero divisor\n");
                break;
            case '%':
                op2 = pop();
                if (op2 != 0.0)
                    push(fmod(pop(), op2));
                else
                    printf("error: zero divisor\n");
                break;
            case '^':
                op2 = pop();
                push(pow(pop(), op2));
                break;
            case 'e':
                push(exp(pop()));
                break;
            case 'r':
                push(sqrt(pop()));
                break;
            case 's':
                push(sin(pop()));
                break;
            case 'o':
                push(cos(pop()));
                break;
            case 't':
                push(tan(pop()));
                break;
            case 'a':
                push(fabs(pop()));
                break;
            case 'l':
                push(log10(pop()));
                break;
            case 'n':
                push(log(pop()));
                break;
            case 'c':
                push(ceil(pop()));
                break;
            case 'f':
                push(floor(pop()));
                break;
            default:
                printf("error: unknown command %s\n", s);
                break;
            }
        }
        else
            printf("Unsupported operator: %s\n", s);
        if (c == '\n')
            printf("\t%.8g\n", pop());
    }
    return 0;
}

// push: push f onto value stack
void push(double f)
{
    if (sp < MAXVAL) // if value stack still has space, add f
        val[sp++] = f;
    else
        printf("error: stack full, can't push %g\n", f);
}

// pop: pop and return top value from stack
double pop(void)
{
    if (sp > 0) // if the next free stack position is greater than zero, return the highest level item from stack
        return val[--sp];
    else
    {
        printf("error: stack empty\n");
        return 0.0;
    }
}
Personal tools