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;
}
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