Thread: Reverse Polish Calcullator

  1. #16
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by thames View Post
    actually, getch and ungetch were coded.
    Ah, so they were. I don't know how I overlooked that, sorry. (I guess I just missed the h at the end.)

    I added the note just to make sure there is no confusion about how ungetc() works; it just rebuffers the character, so that following read or scan operations will see use it. It is not visible outside the process in any way.

    In fact, you could just use getchar() or fgetc(stdin) instead of getch(), and ungetc(c, stdin) instead of ungetch(c).

    You are always guaranteed to be able to push the last character you just read back into the buffer (which is what the code uses it for, only). For the code you showed, the standard functions provide the needed functionality; there is no need for the wrappers or the buffer.

    (In fact, the man page says "ungetc() pushes c back to stream, cast to unsigned char, where it is available for subsequent read operations. Pushed-back characters will be returned in reverse order; only one pushback is guaranteed." It means that the char does not have to be the one you read. It also explains the odd extra input character, ((unsigned char)EOF), if you accidentally ungetc(EOF, stdin);)

  2. #17
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    I'm doing KnR exercise 4-6:

    Add access to library functions like sin, exp and pow to the polish calculator.

    but I'm having a buffer problem. I'm trying to enter an exponent inside a function I called power (because I think people should choose the power they want).

    But I'm getting this:

    Code:
     
      current value of the top of the stack: 4.000000000000000Enter a power: You Entered: 0 Inserted value: 1.000000000000000000
    heh, that buffer problem.

    I know I have to reset the buffer. I tried to reset the val[MAXVAL] unsuccessfully.

    What do I have to reset ?

    edit:
    I tried to reset s (I thought I had to reset it because, after all, s is a char*)


    Code:
    #include <stdio.h> 
    #include <stdlib.h>
    #include <math.h> 
    #include <ctype.h> 
    
    #ifndef NUMBER 
     #define NUMBER '0' 
    #endif 
    
    
    #ifndef MAXOP 
     #define MAXOP 100 
    #endif
    
    
    #ifndef PERIOD 
     #define PERIOD '.'
    #endif 
    
    
    #ifndef MAXVAL 
     #define MAXVAL 100 
    #endif 
    
    
    #ifndef MAXBUF 
     #define MAXBUF 100 
    #endif 
    
    
    int bufp = 0; 
    char buf[MAXBUF];
    
    
    int sp = 0; 
    double val[MAXVAL];
    
    
    int getch(void); 
    void ungetch(int);
    int getop(char*);
    double pop(void);
    void push(double);
    void peek(void);
    void duplicate(void);
    void swap(void);
    void clear(void);
    double power(double);
    int isanumber(char* s);
    
    
    int main(void) 
    { 
      int type; 
      char s[MAXOP]; 
      double op2; 
      
      while( (type = getop(s)) != EOF)
      { 
        switch(type) 
        { 
          case NUMBER: 
            push(atof(s));
            break;
          
          case '+': 
            push(pop() + pop());
            break;
          
          case '-': 
            op2 = pop();
            push(pop() - op2);
            break;              
            
          case '*': 
            push(pop() * pop());
            break;
          
          case '\n': 
            printf("Polish pop: \t%.8g\n", pop());
            break;
            
          case 'i':
            push(sin(pop()));
            break;
            
          case 'e': 
            push(exp(pop()));
            break;
            
          case 'o': 
            push(power(pop()));
            break;  
          
          case 'p': 
            peek();
            break;  
            
          case 'd': 
            duplicate();
            break;  
          
          case 'c': 
            clear();
            break;  
            
          case 's': 
            swap();
            break;  
          
          case '/': 
            op2 = pop();
            if(op2 > 0.0) 
              push(pop() / op2);
            else 
              printf("error: zero divisor\n");
            break;
           
           case '%': 
             op2 = pop();
             if(op2 > 0.0) 
               push(fmod(pop(), op2));
             else 
               printf("error: zero divisor\n");
             break;
            
            default: 
              printf("error: unknown command\n");              
            break;  
        }       
      }           
      return EXIT_SUCCESS;     
    }       
    
    int isanumber(char* s) 
    { 
       int i; 
       for(i = 0; s[i] != '\0'; i++) 
        if(isalpha(s[i]))
          break;
    
    
       if(s[i] != '\0')
          return 0;
       return 1;
    }
    
    void push(double f) 
    { 
       if(sp < MAXVAL) 
       {  
          val[sp++] = f;  
          printf("Inserted value: %f\n", val[sp - 1]);
       }   
       else 
         printf("push: stack full, can't push %g\n", f);             
    }
    
    
    double power(double f) 
    { 
       char strnum[MAXVAL];
       int pw = 0;
       
       do  {
         printf("Enter a power: ");
         fgets(strnum, sizeof(strnum), stdin);    
       }while(!isanumber(strnum));
       
       pw = atoi(strnum);
       printf("You entered: %d", pw);
       
       return pow(f,pw); 
    }     
    
    
    void duplicate(void) 
    { 
       if(sp < MAXVAL) 
       { 
         val[sp++] = pop();  
       }
       else         
         printf("duplicate: stack full, can't push %f\n", pop()); 
    }  
    
    
    void swap(void) 
    { 
       double temp;
       
       if(sp > 0)
       {  
         temp = val[sp];
         val[sp] = val[sp - 1];
         val[sp - 1] = temp;    
       }
       else { 
         printf("swap: at least, two values have to be inserted for swapping.\n");
       }          
    }
    
    
    void clear(void) 
    { 
       int i;
       for(i = 0; i < MAXVAL; i++)
         val[i] = 0.0;
    }              
     
    double pop(void) 
    { 
       if(sp > 0) 
        return val[--sp];
       else 
       { 
         printf("pop: stack empty\n");
         return 0.0;  
       }             
    }
    
    
    void peek(void)
    { 
       if(sp > 0)
         printf("top element: %.2f\n", val[sp]);
       else 
         printf("peek: stack is empty\n");      
    }     
    
    
    int getop(char* s) 
    { 
       int next;
       int c, i; 
       
       while( (s[0] = c = getch()) == ' ' || c == '\t')
       ; 
       s[1] = '\0';    
        
       if(!isdigit(c) && c != PERIOD && c != '-') 
          return c;
       
       if(c == '-')   
       { 
         next = getch();  
         if(!isdigit(next) && next != PERIOD)
          return c; 
       
         c = next;
       }
       else { 
         c = getch();  
       }             
       
       i= 0;
       while(isdigit(s[++i] = c)) /* collect integer part */
         c = getch();
       if(c == PERIOD) /* collect fraction part */
        while(isdigit(s[++i] = c = getch())) 
           ; 
                    
       s[i] = '\0';
       if(c != EOF) 
        ungetch(c);      
       
       return NUMBER;  
    }
    
    
    int getch(void) 
    { 
       return (bufp > 0) ? buf[--bufp] : getchar();    
    }      
    
    
    void ungetch(int c) 
    { 
       if(bufp < MAXBUF) 
        buf[bufp++] = c; 
       else 
        printf("ungetch: too many characters."); 
    }
    Last edited by thames; 11-22-2012 at 05:46 AM.

  3. #18
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    Good evening! I'm trying to write the Reverse Polish program with arguments from argv instead of getting chars from getchar():

    Code:
    #include <stdio.h> 
    #include <stdlib.h>
    #include <math.h> 
    #include <ctype.h> 
    
    #ifndef NUMBER 
     #define NUMBER '0' 
    #endif 
    
    #ifndef MAXOP 
     #define MAXOP 100 
    #endif
    
    #ifndef PERIOD 
     #define PERIOD '.'
    #endif 
    
    #ifndef MAXVAL 
     #define MAXVAL 100 
    #endif 
    
    #ifndef MAXBUF 
     #define MAXBUF 100 
    #endif 
    
    int bufp = 0; 
    char buf[MAXBUF];
    
    int sp = 0; 
    double val[MAXVAL];
    
    int getch(void); 
    void ungetch(int);
    int getop(char*);
    double pop(void);
    void push(double);
    void peek(void);
    void duplicate(void);
    void swap(void);
    void clear(void);
    
    int main(int argc, char* argv[]) 
    { 
      int type; 
      char s[MAXOP]; 
      double op2; 
      char* argument = argv[1];
      
      while( (type = getop(argument)) != EOF)
      { 
        ++argument;
        
        switch(type) 
        { 
          case NUMBER: 
            push(atof(s));
            break;
          
          case '+': 
            push(pop() + pop());
            break;
          
          case '-': 
            op2 = pop();
            push(pop() - op2);
            break;              
            
          case '*': 
            push(pop() * pop());
            break;
          
          case '\n': 
            printf("Polish pop: \t%.8g\n", pop());
            break;
            
          case 'i':
            push(sin(pop()));
            break;
            
          case 'e': 
            push(exp(pop()));
            break;
            
          case 'o': 
            push(pow(pop(), 2));
            break;  
          
          case 'p': 
            peek();
            break;  
            
          case 'd': 
            duplicate();
            break;  
          
          case 'c': 
            clear();
            break;  
            
          case 's': 
            swap();
            break;  
          
          case '/': 
            op2 = pop();
            if(op2 > 0.0) 
              push(pop() / op2);
            else 
              printf("error: zero divisor\n");
            break;
           
           case '%': 
             op2 = pop();
             if(op2 > 0.0) 
               push(fmod(pop(), op2));
             else 
               printf("error: zero divisor\n");
             break;
            
            default: 
              printf("error: unknown command\n");              
            break;  
        }       
      }           
      return EXIT_SUCCESS;     
    }       
    
    int isanumber(char* s) { 
      
      int i = 0; 
      
      while(s[i] != '\n') 
      { 
         if(isalpha((unsigned char) s[i]) || isblank( (unsigned char) s[i]) )
           break;
         
         i++;    
      }        
      
      if(s[i] == '\n')
        return 1; 
      return 0;            
    }
    
    void push(double f) 
    { 
       if(sp < MAXVAL) 
       {  
          val[sp++] = f;  
          printf("Inserted value: %f\n", val[sp - 1]);
       }   
       else 
         printf("push: stack full, can't push %g\n", f);             
    }
    
    void duplicate(void) 
    { 
       if(sp < MAXVAL) 
       { 
         val[sp++] = pop();  
       }
       else         
         printf("duplicate: stack full, can't push %f\n", pop()); 
    }  
    
    void swap(void) 
    { 
       double temp;
       
       if(sp > 1)
       {  
         temp = val[sp - 1];
         val[sp - 1] = val[sp - 2];
         val[sp - 2] = temp;    
       }
       else { 
         printf("swap: at least, two values have to be inserted for swapping.\n");
       }          
    }
    
    void clear(void) 
    { 
       int i;
       for(i = 0; i < MAXVAL; i++)
         val[i] = 0.0;
    }              
     
    double pop(void) 
    { 
       if(sp > 0) 
        return val[--sp];
       else 
       { 
         printf("pop: stack empty\n");
         return 0.0;  
       }             
    }
    
    void peek(void)
    { 
       if(sp > 0)
         printf("top element: %.2f\n", val[sp - 1]);
       else 
         printf("peek: stack is empty\n");      
    }     
    
    int getop(char* s) 
    { 
       int next;
       int c, i; 
       
       while( (s[0] = c = getch()) == ' ' || c == '\t')
       ; 
       s[1] = '\0';    
        
       if(!isdigit(c) && c != PERIOD && c != '-') 
          return c;
       
       if(c == '-')   
       { 
         next = getch();  
         if(!isdigit(next) && next != PERIOD)
          return c; 
       
         c = next;
       }
       else { 
         c = getch();  
       }             
       
       i= 0;
       while(isdigit(s[++i] = c)) /* collect integer part */
         c = getch();
       if(c == PERIOD) /* collect fraction part */
        while(isdigit(s[++i] = c = getch())) 
           ; 
                    
       s[i] = '\0';
       if(c != EOF) 
        ungetch(c);      
       
       return NUMBER;  
    }
    
    int getch(void) 
    { 
       return (bufp > 0) ? buf[--bufp] : getchar();    
    }      
    
    void ungetch(int c) 
    { 
       if(bufp < MAXBUF) 
        buf[bufp++] = c; 
       else 
        printf("ungetch: too many characters."); 
    }
    I started by doing this:

    Code:
     
    char* argument = argv[1];
      
      while( (type = getop(argument)) != EOF)
      { 
        ++argument;
    am I doing that wrong ?

  4. #19
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    I can't see where you have tried to implement any argv/argc

    Have you read this tutorial? Command Line Arguments in C - Cprogramming.com
    Fact - Beethoven wrote his first symphony in C

  5. #20
    young grasshopper jwroblewski44's Avatar
    Join Date
    May 2012
    Location
    Where the sidewalk ends
    Posts
    294
    Here's a snippet from my solution with no buffering.

    Code:
    int get_type( char * );
    
    
    int main( int argc , char * argv[] )
    {
        if( argc < 4 )    /* it takes at least two operands & an operator */
        {
            const char * PROGRAM_NAME = argv[ 0 ];
            printf( "Usage:\t%s [ expression ]  ( multiplication operator ( * ) must be preceded by backslash '\\' )\n" , PROGRAM_NAME );
            printf( "Example:\t%s 2 2 5 \\* +\n( 5 * 2 ) + 2\n12\n" , PROGRAM_NAME );
            return 1;
        }
    
    
        char * operand;
        int type;
        double op2;
        double value_stack[ VALUE_MAX ];
    
    
        while( ( operand = ( *++argv) ) != NULL )
        {
             //heres all the operations and whatnot
            }
    }
    Note that while not talking about this particular program, they do mention how to walk through the arguments starting at the bottom of page 117 and finishing with another paragraph at the top of 118. It really helped me to understand how to walk through command line arguments using pointer arithmetic.

    EDIT: Ironically, I just noticed that the paragraph just mentioned leads into turning the RPN calc into a command line version called expr, which is where I pulled my source from.

    Also in this example, the var operand ends up being a pointer to the beginning of the char array's, or strings, containing the arguments.
    Last edited by jwroblewski44; 12-03-2012 at 09:46 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reverse polish calculator
    By Tool in forum C Programming
    Replies: 3
    Last Post: 12-30-2009, 04:46 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
    By Lucid15 in forum C Programming
    Replies: 7
    Last Post: 02-16-2009, 10:05 PM
  4. c++ Reverse Polish Calculator Help
    By knight101 in forum C++ Programming
    Replies: 5
    Last Post: 11-12-2001, 09:31 AM
  5. Reverse Polish Notation???
    By Wizard_D in forum C Programming
    Replies: 6
    Last Post: 11-01-2001, 12:20 AM

Tags for this Thread