Thread: reverse polish calculator

  1. #1
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272

    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 []);

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by Tool View Post
    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 View Post
    Does this mean enabling = operator for giving values to single letter variables?
    Yep!
    Quote Originally Posted by Tool View Post
    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 View Post
    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 View Post
    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.

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    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:
    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.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272
    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.

    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;
    }
    Last edited by Tool; 12-30-2009 at 04:55 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pushback question (reverse polish calculator)
    By Tool in forum C Programming
    Replies: 8
    Last Post: 12-29-2009, 02:29 PM
  2. reverse polish calculator
    By Tool in forum C Programming
    Replies: 1
    Last Post: 12-24-2009, 05:25 PM
  3. Reverse Polish Notation Calculator
    By jazzyqueen in forum C Programming
    Replies: 1
    Last Post: 09-02-2009, 03:55 AM
  4. Postfix (reverse polish notation) calculator
    By ottomated in forum C Programming
    Replies: 7
    Last Post: 05-06-2008, 05:32 PM
  5. c++ Reverse Polish Calculator Help
    By knight101 in forum C++ Programming
    Replies: 5
    Last Post: 11-12-2001, 09:31 AM