Exercise 4.10 - Calculator using getline

Question

An alternate organization uses getline to read an entire input line; this makes getch and ungetch unnecessary. Revise the calculator to use this approach.

/* Revise the Calculator program to use the getline instead of getch and ungetch */

#include<stdio.h>
#include<stdlib.h> /* for atof() */

#define MAXOP 100
#define NUMBER '0'

int getop(char []);
void push(double);
double pop(void);

/* reverse polish notation calculator */

int main(void)
{
    int type;
    double op2;
    char s[MAXOP];
    
    while((type = getop(s)) != EOF)
    {
        switch(type)
        {
            case NUMBER:
                    push(atof(s));
                    break;
            case '+':
                    push(pop() + pop());
                    break;
            case '*':
                    push(pop() * pop());
                    break;
            case '-':
                    op2 = pop();
                    push(pop() - op2);
                    break;
            case '/':
                    op2 = pop();
                    if ( op2 != 0.0)
                        push(pop()/op2);
                    break;
            case '\n':
                    printf("\t%.9g\n",pop());
                    break;
            default:
                    printf("error: unknown command %s\n",s);
                    break;
        }
    }
    return 0;
}

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

int sp = 0;
double val[MAXVAL];

/* 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 values from stack */

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


/* using getline instead of getch and ungetch */

#include<ctype.h>
#define MAXLINE 100

int mgetline(char line[],int limit);

int li= 0;  /* input line index */
char line[MAXLINE];  /* one input line */

/* getop: get next operator or numeric operand */

int getop(char s[])
{
    int c,i;

    if(line[li] == '\0')
        if(mgetline(line,MAXLINE) == 0)
            return EOF;
        else
            li =0;
    
    while((s[0] = c = line[li++]) == ' ' || c == '\t')
        ;
    
    s[1] = '\0';
    
    if(!isdigit(c) && c!= '.')
        return c;
    
    i = 0;
    
    if(isdigit(c))
        while(isdigit(s[++i] = c = line[li++]))
            ;
    if( c == '.')
        while(isdigit(s[++i] = c = line[li++]))
            ;
    
    s[i] = '\0';

    li--;

    return NUMBER;
}

int mgetline(char s[],int lim)
{
    int i,c;

    for(i=0;i<lim-1 && (c=getchar())!=EOF && c!='\n';++i)
        s[i] =c;
    
    if(c=='\n')
        s[i++] =c;

    s[i]='\0';
    
    return i;
}


        
Run this

Explanation

This program uses mgetline to get the characters and operands from the input and and proceeds with the RPN calculator logic.

This is the main part of the program.

/* getop: get next operator or numeric operand */

int getop(char s[])
{
        int c,i;

        if(line[li] == '\0')
                if(mgetline(line,MAXLINE) == 0)
                        return EOF;
                else
                        li =0;

        while((s[0] = c = line[li++]) == ' ' || c == '\t')
                ;

        s[1] = '\0';

        if(!isdigit(c) && c!= '.')
                return c;

        i = 0;

        if(isdigit(c))
                while(isdigit(s[++i] = c = line[li++]))
                        ;
        if( c == '.')
                while(isdigit(s[++i] = c = line[li++]))
                        ;

        s[i] = '\0';

        li--;

        return NUMBER;
}

From the mgetline function, it takes the input in the line character array, and if if the line is 0 only, then we define that as EOF and return EOF. Then we assign to c the value present at line and look for various conditions like, if line is a space or tab character, we simply skip it. If we encouter c which is not a digit or not a . character, we return c immediately. At the end if it is valid number, we return a NUMBER, which is then pushed onto the stack of the RPN calculator.

An example execution will look like this.

10 10 +
        20
10.1 20.2 +
        30.3
Comments by Disqus