# reverse polish calculator

• 12-30-2009
Tool
reverse polish calculator
I took on these exercises related to the reverse polish calculator mentioned in K&R book.

And there is this exercise which is giving me a headache:

Add commands for handling variables. (It's easy to provide twenty-six variables with single-letter names.) Add a variable for the most recently printed value.

How exactly am i supposed to do this and what am i supposed to do? Does this mean enabling = operator for giving values to single letter variables? If so, how to implement that sort of design... i mean it has to work with the stack somehow, im just confused how... and how many variables could be at use in one time, all 26 or just one?

The code for the calculator is below:

(seperated into 5 source files with appropriate functions)
Code:

```#include "calc.h" #define MAXOP 100 int main(int argc, char *argv[]) {         int type;     double op2;     char s[MAXOP];         while((type = getop(s)) != EOF)     {       switch(type) {         case NUMBER:               push(atof(s));               break;         case WORD:               Handle_word(s);               break;         case '+':               push(pop() + pop());               break;         case '*':               push(pop() * pop());               break;         case '-':               op2 = pop();               push(pop() - op2);               break;         case '/':               if((op2 = pop()) != 0)                 push(pop() / op2);               else                 printf("zero divisor\n");               break;         case '%':               if((op2 = pop()) != 0)                 push(fmod(pop(), op2));               else                 printf("zero divisor\n");               break;         case '\n':               printf("\t%g\n", pop());               break;         default:               printf("unknown command: %s\n", s);               break;       }     }         getchar();     return 0; }```
Code:

```#include "calc.h" #define MAXVAL 100 double val[MAXVAL]; int sp = 0; void push(double c) {     if(sp < MAXVAL)       val[sp++] = c;     else       printf("stack full\n"); } double pop() {     if(sp > 0)       return val[--sp];     else {       printf("stack empty\n");       return 0.0;     } } void Handle_word(char s[]) {     double op1, op2;         if(strcmp(s, "print") == 0)     {       if(sp > 0)         printf("\t%g\n", val[sp-1]);       else         printf("stack empty, cant print\n");     }     else if(strcmp(s, "dup") == 0)     {       op1 = pop();       push(op1);       push(op1);     }     else if(strcmp(s, "swap") == 0)     {       op1 = pop();       op2 = pop();       push(op1);       push(op2);     }     else if(strcmp(s, "clear") == 0)     {       sp = 0;     }     else if(strcmp(s, "sin") == 0)     {       push(sin(pop()));     }     else if(strcmp(s, "exp") == 0)     {       push(exp(pop()));     }     else if(strcmp(s, "pow") == 0)     {       op1 = pop();       push(pow(pop(), op1));     }     else       printf("unknown command: %s\n", s); }```
Code:

```#include <ctype.h> /* isdigit */ #include "calc.h" /* get a operand or operator, or a word */ int getop(char s[]) {     int i = 0, c, next;         while((s[0] = c = getch()) == ' ' || c == '\t') /* the first character */           ;     s[1] = '\0';             /*1. if the first char is a letter, handle the string as a word */     if(isalpha(c))     {       while(isalpha(s[++i] = c = getch()))             ;             ungetch(c);       s[i] = '\0';       return WORD;     }         /*2. Handle numbers, possible unary minus - if not any of that just return */     if(!isdigit(c) && c != '.' && c != '-')       return c;         /* from now on, c can only be . or digit or - */     if(c == '-')     {         next = getch();                 if(!isdigit(next) && next != '.') { /* . because -.25 is allowed */           ungetch(next);           return c; /* not a number, but an operator, so we must return it! */         }                 c = next; /* if next is a . or a digit, just put it into c */     }     else /* if c is a . or a number, get another char since . or number is allready stored in */       c = getch();         /* now c can only be . or - */     while(isdigit(s[++i] = c))       c = getch();         if(c == '.')       while(isdigit(s[++i] = c = getch()))           ;         s[i] = '\0';     if(c!=EOF)       ungetch(c);         return NUMBER; }```
Code:

```#include "calc.h" #define MAXBUF 100 int buf[MAXBUF]; int bufp = 0; int getch() {     return (bufp > 0) ? buf[--bufp] : getchar(); } void ungetch(int c) //stores the temp char {     if(bufp >= MAXBUF)         printf("ungetch: too many characters\n");     else         buf[bufp++] = c; }```
Code:

```/* headers */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define NUMBER '0' /* used by main and getop */ #define WORD 'a' int getop(char []); void push(double); double pop(); int getch(); void ungetch(int); void Handle_word(char []);```
• 12-30-2009
itCbitC
Quote:

Originally Posted by Tool
Add commands for handling variables. (It's easy to provide twenty-six variables with single-letter names.) Add a variable for the most recently printed value.

How exactly am i supposed to do this and what am i supposed to do?

Define 26 alphabet variables.
Quote:

Originally Posted by Tool
Does this mean enabling = operator for giving values to single letter variables?

Yep!
Quote:

Originally Posted by Tool
If so, how to implement that sort of design...

Simply extend your case statement so it can parse the equality operator and the 26 alphabetic variables.
Quote:

Originally Posted by Tool
i mean it has to work with the stack somehow, im just confused how...

Need to push() the variables onto the stack exactly like you have done before, and when you see the equals sign you pop() it and assign the value to the variable.
Quote:

Originally Posted by Tool
and how many variables could be at use in one time, all 26 or just one?

You will allocate 26 variables but use only the subset that has been entered by the user at runtime.
• 12-30-2009
dwks
Let's say that you want all single-letter lowercase strings to be variables. Then that code will already parse each variable as a WORD (because this is just a sequence of alphabetic characters). So in order to recognize letters in your input you just need to look at WORDs. Let's say Handle_word() just checks the length of the word: if the length is 1, the appropriate variable value is looked up from a global array of variable values.

That would handle "dereferencing" variables, or using their values. (In a sense, it handles using variables as rvalues.) As you identified, you also have to be able to assign to variables. Perhaps you could create an "=" operator which is only valid at the beginning of the string following a variable. But I think that's more work than you need to use. Look at this part of the instructions:
Quote:

Add a variable for the most recently printed value.
I think that means that the result of the first expression is assigned to a, the result of the second is assigned to b, etc. Which would be pretty easy to implement. :)
• 12-30-2009
Tool
Well, this is what i came up for the first part of the program - assigning values to variables. I initialized 26 global variables, seting them all to 0.

Then i edited getop so it returns VARIABLE in case string len is 1 and is lower alpha.

Then i wrote a function Handle_variable, which pushes the index of the variable on the stack if the current variable has 0 value. If it has a value other then 0, push the value it contains.

Also added = case which assigns only if the operators go in this order: a 5 =, so it doesnt handles stuff like 5 a =, i dont really know how to approach this problem tho. There is one problem with this approach: seting variables to 0 wont actually work. If i set c to 0, c 5 + will give me 7, not 5.

Quote:

I think that means that the result of the first expression is assigned to a, the result of the second is assigned to b, etc. Which would be pretty easy to implement.
What expression? Im not following.
Code:

```#include "calc.h" #define MAXOP 100 double variables[26]; void Handle_variable(char s[]) {     int c = s[0];         if(variables[c - 'a'] != 0)       push(variables[c - 'a']);     else /* push index in case we wanna assign */       push(c - 'a'); }     int main(int argc, char *argv[]) {         int type;     double op2;     char s[MAXOP];     int x;         for(x=0; x<25; x++)       variables[x] = 0;         while((type = getop(s)) != EOF)     {       switch(type) {         case NUMBER:               push(atof(s));               break;         case WORD:               Handle_word(s);               break;         case VARIABLE:               Handle_variable(s);               break;         case '=':               op2 = pop();               variables[(int)pop()] = op2;               break;         case '+':               push(pop() + pop());               break;         case '*':               push(pop() * pop());               break;         case '-':               op2 = pop();               push(pop() - op2);               break;         case '/':               if((op2 = pop()) != 0)                 push(pop() / op2);               else                 printf("zero divisor\n");               break;         case '%':               if((op2 = pop()) != 0)                 push(fmod(pop(), op2));               else                 printf("zero divisor\n");               break;         case '\n':               printf("\t%g\n", pop());               break;         default:               printf("unknown command: %s\n", s);               break;       }     }         getchar();     return 0; }```
Code:

```#include <ctype.h> /* isdigit */ #include "calc.h" /* get a operand or operator, or a word */ int getop(char s[]) {     int i = 0, c, next;         while((s[0] = c = getch()) == ' ' || c == '\t') /* the first character */           ;     s[1] = '\0';         /*1. if the first char is a letter, handle the string as a word */     if(isalpha(c))     {       int temp = c;       while(isalpha(s[++i] = c = getch()))             ;             ungetch(c);       s[i] = '\0';             if(i == 1 && temp >= 'a' && temp <='z')           return VARIABLE;                 return WORD;     }         /*2. Handle numbers, possible unary minus - if not any of that just return */     if(!isdigit(c) && c != '.' && c != '-')       return c;         /* from now on, c can only be . or digit or - */     if(c == '-')     {         next = getch();                 if(!isdigit(next) && next != '.') { /* . because -.25 is allowed */           ungetch(next);           return c; /* not a number, but an operator, so we must return it! */         }                 c = next; /* if next is a . or a digit, just put it into c */     }     else /* if c is a . or a number, get another char since . or number is allready stored in */       c = getch();         /* now c can only be . or - */     while(isdigit(s[++i] = c))       c = getch();         if(c == '.')       while(isdigit(s[++i] = c = getch()))           ;         s[i] = '\0';     if(c!=EOF)       ungetch(c);         return NUMBER; }```