Thread: Infix Calculator

  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    55

    Infix Calculator

    I have written an infix calculator based on the algorithm which is coded below. It is using two stacks, one for the integer values, and one for the operators. However, it is not doing what I think it is supposed to be doing. Once it executes the Execute() function, it turns out that opStack is empty, but I have not been able to isolate the problem. If anyone is able to point me in the right direction, I would be grateful. Thanks.

    Code:
    #include <iostream>
    #include <stack>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    class Calculator
    {
     public:
      void Open(ifstream& f, string afile);
      void Process(ifstream& f);
      void Execute ();
      void Display ();
      void DisplayOp ();
     
     private:
      stack <int> valStack ;
      stack <char> opStack ;
    };
    
    int main()
    {
     Calculator Infix ;
     ifstream INFILE;
     string filename ;
     cout << "Enter filename to open: " ;
     cin >> filename ;
     
     Infix.Open(INFILE, filename) ;
     
     Infix.Process(INFILE);
        
     system ("Pause");
     return 0;
    }
    
    void Calculator :: Open(ifstream& f, string afile)
    {
     f.open (afile.c_str());
     
     if(f.fail())
     {
      cout <<"Error: File not Opened!" << "\n" ;
      cout <<"Exiting Program!" << "\n" ;
      system("Pause");
      exit(1);
     }
    }
    
    void Calculator :: Process(ifstream& f)
    {
     int result ;
     string infixExpr;
     string achar[infixExpr.length()];
      
     while(f && f.peek() != EOF)
     {
      getline(f, infixExpr);
     }
     
    
     for(int i=0; i < infixExpr.length(); i++)
     {
    
      
    //*********************************************************
    //achar = 'infixExpr[i]' ;
    //First Attempt Not Working
     //achar = infixExpr;
     
      /*
      //Handles cases where the operand is more than one digit
      // j is used as a temporary index iterator as to not affect the i from the loop
      int j = i;
      while(isdigit(infixExpr[j+1])) 
      {
       achar =  achar[j] ;
       j++;
      }
      */
    //***********************************************************  
      
       if (isdigit(infixExpr[i]))  
           valStack.push(infixExpr[i]) ;
       
       if (infixExpr[i] == '(') 
         opStack.push(infixExpr[i]) ;
        
       if(infixExpr[i] == '+' ||  '-' || '*' || '/' || '^')
        {               
         if(opStack.empty())
          opStack.push(infixExpr[i]) ;
        }
        
        else if (infixExpr[i] > opStack.top())
          opStack.push(infixExpr[i]) ;
          
        else
        {
         while ( !opStack.empty() && infixExpr[i] <= opStack.top() )
         {
          Execute() ;
          opStack.push(infixExpr[i]) ;
         }
        }
       
       if(infixExpr[i] == ')')
       {
        while (opStack.top() != '(')
        {
         Execute();
         opStack.pop() ;
        }
       }  
     }//end for
    
     while(!opStack.empty())
     {
      Execute();
      result = valStack.top();
     }        
     
    }
    
    void Calculator :: Execute ()
    {
     int operand2, operand1, result ;
     char op;
     
     operand2 = valStack.top();
     valStack.pop();
     
     operand1 = valStack.top();
     valStack.pop();
     
     op = opStack.top();
     opStack.pop();
     
     if(op == '^')
      result = operand1 + operand2 ;
     
     if(op == '*')
      {
       result = operand1 * operand2 ; 
       cout << operand1 << operand2 ;
      }
      
     if(op == '/')
      {
       if(operand2 == '0')
       cout <<"Division by zero error!";
       
       else
       result = operand1 / operand2 ; 
      }
       
     if(op == '+')
      result = operand1 + operand2 ;
    
     if(op == '-')
      result = operand1 - operand2 ;  
     
     valStack.push(result) ;
    }
    
    void Calculator :: Display()
    {
     while(!valStack.empty())
     {
      cout <<valStack.top();
      valStack.pop();
     }
    }
    
    void Calculator :: DisplayOp()
    {
     while(!opStack.empty())
     {
      cout <<opStack.top();
      opStack.pop();
     }
    }

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> string achar[infixExpr.length()];
    What are you trying to do here? You are creating an empty array since infixExpr is empty at the time. In addition, that code is not legal C++ and will only compile on a compiler that allows it as an extension.

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    Quote Originally Posted by Daved View Post
    >> string achar[infixExpr.length()];
    What are you trying to do here? You are creating an empty array since infixExpr is empty at the time. In addition, that code is not legal C++ and will only compile on a compiler that allows it as an extension.
    Oh, that was leftover from a previous attempt.

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> if(infixExpr[i] == '+' || '-' || '*' || '/' || '^')
    This is not the correct use of multiple ||'s. You've got to have a complete expression between each one. Chances are this will have more of an effect on your problem than the previous issue.

    Actually...
    Code:
       if(infixExpr[i] == '+' ||  '-' || '*' || '/' || '^')
        {               
         if(opStack.empty())
          opStack.push(infixExpr[i]) ;
        }
        
        else if (infixExpr[i] > opStack.top())
          opStack.push(infixExpr[i]) ;
          
        else
        {
         while ( !opStack.empty() && infixExpr[i] <= opStack.top() )
         {
          Execute() ;
          opStack.push(infixExpr[i]) ;
         }
        }
    Are you sure that's where you want your braces?
    Last edited by Daved; 05-14-2007 at 02:41 PM.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    I have traced my algorithm for evaluating an infix expression and it does solve the problem. However, after tracing my program, I realized that the variable achar contains the ASCII code for the character it was assigned. So for example, in my code when Execute() is called, operand 2 gets 53 and operand 1 gets 50, which is 2 and 5 respectively. Therefore, when it executes operand1 * operand 2, I get something totally wrong. Is there a way to convert ASCII codes to their corresponding characters? If not, how else can I extract an integer from a string without it converting it to ASCII?

    Here is my updated code:
    Code:
    #include <iostream>
    #include <stack>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    class Calculator
    {
     public:
      void Open(ifstream& f, string afile);
      void Process(ifstream& f);
      void Execute ();
      void Display ();
      void DisplayOp ();
     
     private:
      stack <int> valStack ;
      stack <char> opStack ;
    };
    
    int main()
    {
     Calculator Infix ;
     ifstream INFILE;
     string filename ;
     
     cout << "Enter filename to open: " ;
     cin >> filename ;
     
     Infix.Open(INFILE, filename) ;
     Infix.Process(INFILE);
        
     system ("Pause");
     return 0;
    }
    
    void Calculator :: Open(ifstream& f, string afile)
    {
     f.open (afile.c_str());
     
     if(f.fail())
     {
      cout <<"Error: File not Opened!" << "\n" ;
      cout <<"Exiting Program!" << "\n" ;
      system("Pause");
      exit(1);
     }
    }
    
    void Calculator :: Process(ifstream& f)
    {
     int result ;
     string infixExpr;
     char achar;
      
     while(f && f.peek() != EOF)
     {
      getline(f, infixExpr);
     }
      
       for(int i=0; i < infixExpr.length(); i++)
       {
        
        achar = infixExpr[i];
       
        if(isdigit(achar))
        {
         valStack.push(achar) ;
         cout << "Pushed into valStack: " << achar << "\n";
        }
        
       else
      switch(achar)
      {
       
       case('('):
       {
        opStack.push(achar);
        cout << "Pushed into opStack: " << achar << "\n";
        break;
       }
                    
       case('*'):
       {            
          if(opStack.empty())
           {
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
           
          else if (achar > opStack.top())
            {
             opStack.push(achar) ; 
             cout << "Pushed into opStack: " << achar << "\n";
            }
            
          else
          {
           while ( !opStack.empty() && achar <= opStack.top() )
           {
            Execute() ;
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
          }
          break;
       }//end if
             
                              
       case('+'):  
        {            
          if(opStack.empty())
           {
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
           
          else if (achar > opStack.top())
            {
             opStack.push(achar) ; 
             cout << "Pushed into opStack: " << achar << "\n";
            }
            
          else
          {
           while ( !opStack.empty() && achar <= opStack.top() )
           {
            Execute() ;
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
          } 
          break;
       }//end if
      
      case('-'):
       {            
          if(opStack.empty())
           {
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
           
          else if (achar > opStack.top())
            {
             opStack.push(achar) ; 
             cout << "Pushed into opStack: " << achar << "\n";
            }
            
          else
          {
           while ( !opStack.empty() && achar <= opStack.top() )
           {
            Execute() ;
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
          }
       }//end if
       break;      
       
       case('/'):
       {            
          if(opStack.empty())
           {
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
           
          else if (achar > opStack.top())
            {
             opStack.push(achar) ; 
             cout << "Pushed into opStack: " << achar << "\n";
            }
            
          else
          {
           while ( !opStack.empty() && achar <= opStack.top() )
           {
            Execute() ;
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
          }
       }//end if
       break;      
       
       case('^'):
       {            
          if(opStack.empty())
           {
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
           
          else if (achar > opStack.top())
            {
             opStack.push(achar) ; 
             cout << "Pushed into opStack: " << achar << "\n";
            }
            
          else
          {
           while ( !opStack.empty() && achar <= opStack.top() )
           {
            Execute() ;
            opStack.push(achar) ;
            cout << "Pushed into opStack: " << achar << "\n";
           }
          }
       }//end if
       break;  
       
       case(')'):
       {
        while (opStack.top() != '(')
        {
         Execute();
         opStack.pop() ;
         break;
        }
       }    
     }//end switch 
      }//end for
       
     while(!opStack.empty())
     {
      Execute();
      result = valStack.top();
     }        
    }//end of Process()
    
    void Calculator :: Execute ()
    {           
     int operand2, operand1, result ;
     char op;
     
     operand2 = valStack.top();
     valStack.pop();
     
     operand1 = valStack.top();
     valStack.pop();
     
     op = opStack.top();
     opStack.pop();
     
     switch(op)
     {
      case('^'):
      {
       result = operand1 ^ operand2 ;
       valStack.push(result);
       
       
       break;
      }
       
      case('*'):
      {
       result = operand1 * operand2 ;
       
       cout<<"values" << operand1 << " " << operand2 ;
       system("pause");
       
       valStack.push(result);
       cout << "Valstack has: ";
        Display();
       system ("pause");
       cout << "Result for * op is: " << result ;
       break;
      }
     
      case('/'):
      {
       if(operand2 == '0')
       cout <<"Division by zero error!";
       
       else
       result = operand1 / operand2 ; 
       valStack.push(result);
       break;
      }
       
      case('+'):
      {
       result = operand1 + operand2 ;
       cout << "Result:" << result ;
       valStack.push(result);
       break;
      }
      
      case('-'):
      {
       result = operand1 - operand2 ;
       valStack.push(result);
       break;
      }  
     
    }//end switch
    }
    
    
    
    
    void Calculator :: Display()
    {
     while(!valStack.empty())
     {
      cout <<valStack.top();
      valStack.pop();
     }
    }
    
    void Calculator :: DisplayOp()
    {
     while(!opStack.empty())
     {
      cout <<opStack.top();
      opStack.pop();
     }
    }

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    If it is a single digit, then subtract '0' from the character to get the actual integer value, of course, that will only work on positive single digit numbers. You'll have to do more work to get other integers.

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    Quote Originally Posted by Daved View Post
    If it is a single digit, then subtract '0' from the character to get the actual integer value, of course, that will only work on positive single digit numbers. You'll have to do more work to get other integers.
    I don't understand how subtracting '0' from the character would give me the actual integer value. Can you please explain this further? Thanks.

  8. #8
    Registered User
    Join Date
    May 2007
    Posts
    88
    >If not, how else can I extract an integer from a string without it converting it to ASCII?

    istringstreams are great for conversions.

    BTW, I think adding at least 3 more spaces to your indents might do wonders for that code.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Can you please explain this further?

    The character codes for the digits '0' through '9' are guaranteed to be in order. So, if you have the character '5' and subtract the characer '0' you will get the difference between the character codes. Since the character codes must be in order, that becomes 5. In ASCII, it turns out to be 53 ('5') - 48 ('0') = 5.

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    Quote Originally Posted by UMR_Student View Post
    >If not, how else can I extract an integer from a string without it converting it to ASCII?

    istringstreams are great for conversions.

    BTW, I think adding at least 3 more spaces to your indents might do wonders for that code.
    Yeah, I guess in its current state, it is hard to read and understand for others. But right now, I am putting all my effort into getting the program to work. Afterwards, I fix formatting and other things.

    This is the first time I hear about input string streams. I'll look into it. Thanks.

  11. #11
    Registered User
    Join Date
    May 2007
    Posts
    88
    > But right now, I am putting all my effort into getting the program to work. Afterwards, I fix
    > formatting and other things.

    Yeah, but I think you'll find that good formatting from the beginning and throughout will make everything that much easier.

  12. #12
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    I am now trying to read integers that are more than one digit long from the file, but am stuck. I am trying to implement the following:

    while the next character in infixExpr is a digit, achar gets the previous character concatenated with the next character.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    One option is to have a string variable that holds the number. Then concatenate each character to that string (you can't concatenate a character to another character). Once you no longer have a digit, convert the string to a number. This doesn't work with negative or floating point numbers or with scientific notation, but it is probably enough for you. Use a stringstream to convert that string to the number.

    Another option is to change the entire way you are reading in. Read a token at a time instead of a character at a time.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Expression: Convert infix notation to postfix notation.
    By Nutshell in forum C Programming
    Replies: 7
    Last Post: 02-27-2010, 07:44 AM
  2. Replies: 4
    Last Post: 03-12-2006, 02:17 PM
  3. GUI Calculator - Critique
    By The Brain in forum Windows Programming
    Replies: 1
    Last Post: 02-25-2006, 04:39 AM
  4. Need help with calculator program
    By Kate in forum C# Programming
    Replies: 1
    Last Post: 01-16-2004, 10:48 AM
  5. Replies: 2
    Last Post: 05-10-2002, 04:16 PM