Exercise 7-5 (Calculator with scanf and sscanf)

Chapter_7     Exercise_7-4 cat_(concatenate)     Exercise_7-6







Exercise 7-5     K&R, p. 159


Exercise 7-5. Rewrite the postfix_calculator of Chapter_4 to use scanf() and/or sscanf() to do the input and number conversion.




Note:  See Exercise_5-6-10 in Chapter_5.




CONTENTS:     compute.txt     calc1.c     getcalc.c




compute.txt         download


1 2 +
1 2 * 3 + 5 -
-1 2 +
-1 -2 -
4 3 %
2 0 %
1 3 /
1 0 /





calc1.c         download


#include <stdio.h> // for getchar(), ungetc(), printf(), stdin,
// scanf(), sscanf(), EOF

#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found

int getop(char *); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack

int main()
{
int type, i1, i2;
double op1, op2; // operands
char s[MAXOP]; // operand or operator

while((type = getop(s)) != EOF)
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
sscanf(s, "%lf", &op1);
push(op1);
break;
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;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conv from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}

return 0;
}

#define MAXVAL 100 // stack size

double val[MAXVAL]; // value stack
double *sp = val; // stack pointer (*val is top of stack)

void push(double f) // push f on (top of) stack
{
if (sp < val+MAXVAL) {*sp++ = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}

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

#include <ctype.h> // for isdigit()

int getop(char *s) // get next operator or numeric operand
{
int c;
// skip beginning whitespace (' ', '\t')
while ((*s = c = getchar()) == ' ' || c == '\t')
{} // *s is not ' ' or '\t', but could be '\n' or EOF
*(s+1) = '\0'; // end string

if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or EOF)
// here c is digit or '.' or '+' or '-'

if (c == '+' || c == '-') // unary or binary sign
{
c = getchar();
if (!isdigit(c) && c != '.')
{
ungetc(c, stdin); // push c back on standard input
return *s; // binary '+' or '-'
}
else // c is digit or '.'
{
ungetc(c, stdin); // digit or '.'
if (*s == '-') {ungetc(*s, stdin);} // s[0] == '-'
// if (*s == '+') {} // ignore '+' sign
}
}
else{ungetc(*s, stdin);} // digit or '.'

scanf("%s", s);

return NUMBER;
}

/*
gcc calc1.c -o calc1
./calc1
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows

./calc1 < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/











getcalc.c         download


#include <stdio.h> // for getchar(), printf(), sscanf(), EOF

#define MAXLINE 1000 // max line length
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found

int getLine(char *, int); // getline() is declared in stdio.h
char line[MAXLINE];
int n; // no of chars read by sscanf()
char *lp; // line pointer (current position on line)

int getop(char *); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack

int main()
{
int type, i1, i2, len;
double op1, op2; // operands
char s[MAXOP]; // operand or operator

while((len = getLine(line, MAXLINE)) > 0)
{ // nonempty line ending with EOF will not be executed
lp = line;
while(sscanf(lp, "%s%n", s, &n) == 1) // until end of line
{ // %n - number of chars read
lp += n;
type = getop(s);
switch(type)
{
case NUMBER :
sscanf(s, "%lf", &op1);
push(op1);
break;
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;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conv from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
default :
printf("Unknown command: %s\n", s);
break;
} // end of switch()
} // end of inner while()
printf("\t%.8g\n", pop()); // top of stack
} // end of outer while()

return 0;
} // end of main()

// getLine(): read a line into s, return length
int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if --lim > 0:
for (p = s; (--lim > 0) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n' or not, s[lim-1]='\0'
*p = c;
}
if (c == '\n') // i < (lim-1), getchar() executed
{
*p++ = c; // '\n'
}
*p = '\0'; // the null character ends a string

return p-s; // max(p-s) == (lim-1), assuming (lim-1) > 0
}

#define MAXVAL 100 // stack size

double val[MAXVAL]; // value stack
double *sp = val; // stack pointer (*val is top of stack):


void push(double f) // push f on (top of) stack
{
if (sp < val+MAXVAL) {*sp++ = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}

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

#include <ctype.h> // for isdigit()

int getop(char *s) // get next operator or numeric operand
{
if (!isdigit(*s) && *s != '.' && *s != '+' && *s != '-')
{return *s;} // not a number, probably an operator (or '\n')
// here *s is digit or '.' or '+' or '-'
if (*s == '+' || *s == '-') // unary or binary sign
{
s++;
if (!isdigit(*s) && *s != '.')
{
s--;
return *s; // binary '+' or '-'
}
else // *s is digit or '.'
{
return NUMBER;
}
}
else{return NUMBER;} // *s is digit or '.'
}

/*
gcc getcalc.c -o getcalc
./getcalc
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows

./getcalc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/









Chapter_7     Exercise_7-4 BACK_TO_TOP cat_(concatenate)     Exercise_7-6



Comments

Popular posts from this blog

Contents

Blogger Page Margins in Contempo