Thread: A simple calculator

  1. #1
    Registered User
    Join Date
    Nov 2012
    Location
    Heraklion, Greece, Greece
    Posts
    26

    Unhappy A simple calculator

    Hello guys,i have an assigment which includes an exercise about creating a calculator gui(fltk).This is the algorithm used from professor Stroustrup without the gui.
    Code:
    //
    // This is example code from Chapter 7.8.3 "Predefined names" of
    // "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
    //
    
    #include "std_lib_facilities.h"
    
    /*
        Simple calculator
    
        Revision history:
    
            Revised by Bjarne Stroustrup May 2007
            Revised by Bjarne Stroustrup August 2006
            Revised by Bjarne Stroustrup August 2004
            Originally written by Bjarne Stroustrup
                ([email protected]) Spring 2004.
    
        This program implements a basic expression calculator.
        Input from cin; output to cout.
    
        The grammar for input is:
    
        Calculation:
            Statement
            Print
            Quit
            Calculation Statement
        
        Statement:
            Declaration
            Expression
        
        Declaration:
            "let" Name "=" Expression
    
        Print:
            ;
    
        Quit:
            q 
    
        Expression:
            Term
            Expression + Term
            Expression - Term
        Term:
            Primary
            Term * Primary
            Term / Primary
            Term % Primary
        Primary:
            Number
            Name
            ( Expression )
            - Primary
            + Primary
        Number:
            floating-point-literal
    
    
            Input comes from cin through the Token_stream called ts.
    */
    
    //------------------------------------------------------------------------------
    
    const char number = '8';    // t.kind==number means that t is a number Token
    const char quit   = 'q';    // t.kind==quit means that t is a quit Token
    const char print  = ';';    // t.kind==print means that t is a print Token
    const char name   = 'a';    // name token
    const char let    = 'L';    // declaration token
    const string declkey = "let";// declaration keyword 
    const string prompt  = "> ";
    const string result  = "= "; // used to indicate that what follows is a result
    
    //------------------------------------------------------------------------------
    
    class Token {
    public:
        char kind;        // what kind of token
        double value;     // for numbers: a value 
        string name;      // for names: name itself
        Token(char ch)             : kind(ch), value(0)   {}
        Token(char ch, double val) : kind(ch), value(val) {}
        Token(char ch, string n)   : kind(ch), name(n)    {}
    };
    
    //------------------------------------------------------------------------------
    
    class Token_stream {
    public: 
        Token_stream();   // make a Token_stream that reads from cin
        Token get();      // get a Token (get() is defined elsewhere)
        void putback(Token t);    // put a Token back
        void ignore(char c);      // discard tokens up to an including a c
    private:
        bool full;        // is there a Token in the buffer?
        Token buffer;     // here is where we keep a Token put back using putback()
    };
    
    //------------------------------------------------------------------------------
    
    // The constructor just sets full to indicate that the buffer is empty:
    Token_stream::Token_stream()
    :full(false), buffer(0)    // no Token in buffer
    {
    }
    
    //------------------------------------------------------------------------------
    
    // The putback() member function puts its argument back into the Token_stream's buffer:
    void Token_stream::putback(Token t)
    {
        if (full) error("putback() into a full buffer");
        buffer = t;       // copy t to buffer
        full = true;      // buffer is now full
    }
    
    //------------------------------------------------------------------------------
    
    Token Token_stream::get() // read characters from cin and compose a Token
    {
        if (full) {         // check if we already have a Token ready
            full=false;
            return buffer;
        }  
    
        char ch;
        cin >> ch;          // note that >> skips whitespace (space, newline, tab, etc.)
    
        switch (ch) {
        case quit:
        case print:
        case '(':
        case ')':
        case '+':
        case '-':
        case '*':
        case '/': 
        case '%':
        case '=':
            return Token(ch); // let each character represent itself
        case '.':             // a floating-point literal can start with a dot
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':    // numeric literal
        {
            cin.putback(ch);// put digit back into the input stream
            double val;
            cin >> val;     // read a floating-point number
            return Token(number,val);
        }
        default:
            if (isalpha(ch)) {
                string s;
                s += ch;
                while (cin.get(ch) && (isalpha(ch) || isdigit(ch))) s+=ch;
                cin.putback(ch);
                if (s == declkey) return Token(let); // keyword "let"
                return Token(name,s);
            }
            error("Bad token");
        }
    }
    
    //------------------------------------------------------------------------------
    
    void Token_stream::ignore(char c)
        // c represents the kind of a Token
    {
        // first look in buffer:
        if (full && c==buffer.kind) {
            full = false;
            return;
        }
        full = false;
    
        // now search input:
        char ch = 0;
        while (cin>>ch)
            if (ch==c) return;
    }
    
    //------------------------------------------------------------------------------
    
    Token_stream ts;        // provides get() and putback() 
    
    //------------------------------------------------------------------------------
    
    class Variable {
    public:
        string name;
        double value;
        Variable (string n, double v) :name(n), value(v) { }
    };
    
    //------------------------------------------------------------------------------
    
    vector<Variable> var_table;
    
    //------------------------------------------------------------------------------
    
    double get_value(string s)
        // return the value of the Variable names s
    {
        for (int i = 0; i<var_table.size(); ++i)
            if (var_table[i].name == s) return var_table[i].value;
        error("get: undefined variable ", s);
    }
    
    //------------------------------------------------------------------------------
    
    void set_value(string s, double d)
        // set the Variable named s to d
    {
        for (int i = 0; i<var_table.size(); ++i)
            if (var_table[i].name == s) {
                var_table[i].value = d;
                return;
            }
        error("set: undefined variable ", s);
    }
    
    //------------------------------------------------------------------------------
    
    bool is_declared(string var)
        // is var already in var_table?
    {
        for (int i = 0; i<var_table.size(); ++i)
            if (var_table[i].name == var) return true;
        return false;
    }
    
    //------------------------------------------------------------------------------
    
    double define_name(string var, double val)
        // add (var,val) to var_table
    {
        if (is_declared(var)) error(var," declared twice");
        var_table.push_back(Variable(var,val));
        return val;
    }
    
    //------------------------------------------------------------------------------
    
    double expression();    // declaration so that primary() can call expression()
    
    //------------------------------------------------------------------------------
    
    // deal with numbers and parentheses
    double primary()
    {
        Token t = ts.get();
        switch (t.kind) {
        case '(':           // handle '(' expression ')'
            {
                double d = expression();
                t = ts.get();
                if (t.kind != ')') error("')' expected");
                return d;
            }
        case number:    
            return t.value;    // return the number's value
        case name:
            return get_value(t.name); // return the variable's value
        case '-':
            return - primary();
        case '+':
            return primary();
        default:
            error("primary expected");
        }
    }
    
    //------------------------------------------------------------------------------
    
    // deal with *, /, and %
    double term()
    {
        double left = primary();
        Token t = ts.get(); // get the next token from token stream
    
        while(true) {
            switch (t.kind) {
            case '*':
                left *= primary();
                t = ts.get();
                break;
            case '/':
                {    
                    double d = primary();
                    if (d == 0) error("divide by zero");
                    left /= d; 
                    t = ts.get();
                    break;
                }
            case '%':
                {    
                    int i1 = narrow_cast<int>(left);
                    int i2 = narrow_cast<int>(term());
                    if (i2 == 0) error("%: divide by zero");
                    left = i1%i2; 
                    t = ts.get();
                    break;
                }
            default: 
                ts.putback(t);        // put t back into the token stream
                return left;
            }
        }
    }
    
    //------------------------------------------------------------------------------
    
    // deal with + and -
    double expression()
    {
        double left = term();      // read and evaluate a Term
        Token t = ts.get();        // get the next token from token stream
    
        while(true) {    
            switch(t.kind) {
            case '+':
                left += term();    // evaluate Term and add
                t = ts.get();
                break;
            case '-':
                left -= term();    // evaluate Term and subtract
                t = ts.get();
                break;
            default: 
                ts.putback(t);     // put t back into the token stream
                return left;       // finally: no more + or -: return the answer
            }
        }
    }
    
    //------------------------------------------------------------------------------
    
    double declaration()
        // handle: name = expression
        // declare a variable called "name" with the initial value "expression"
    {
        Token t = ts.get();
        if (t.kind != name) error ("name expected in declaration");
        string var_name = t.name;
    
        Token t2 = ts.get();
        if (t2.kind != '=') error("= missing in declaration of ", var_name);
    
        double d = expression();
        define_name(var_name,d);
        return d;
    }
    
    //------------------------------------------------------------------------------
    
    double statement()
    {
        Token t = ts.get();
        switch (t.kind) {
        case let:
            return declaration();
        default:
            ts.putback(t);
            return expression();
        }
    }
    
    //------------------------------------------------------------------------------
    
    void clean_up_mess()
    { 
        ts.ignore(print);
    }
    
    //------------------------------------------------------------------------------
    
    void calculate()
    {
        while (cin)
          try {
            cout << prompt;
            Token t = ts.get();
            while (t.kind == print) t=ts.get();    // first discard all "prints"
            if (t.kind == quit) return;        // quit
            ts.putback(t);
            cout << result << statement() << endl;
        }
        catch (exception& e) {
            cerr << e.what() << endl;        // write error message
            clean_up_mess();
        }
    }
    
    //------------------------------------------------------------------------------
    
    int main()
    try {
        // predefine names:
        define_name("pi",3.1415926535);
        define_name("e",2.7182818284);
    
        calculate();
    
        keep_window_open();    // cope with Windows console mode
        return 0;
    }
    catch (exception& e) {
        cerr << e.what() << endl;
        keep_window_open("~~");
        return 1;
    }
    catch (...) {
        cerr << "exception \n";
        keep_window_open("~~");
        return 2;
    }
    
    //------------------------------------------------------------------------------
    If you notice,in Token Token_stream::get(),there is use of a char called ch to input data.

    The aim of the exercise is to input in a box the things you want to calcualte and than you will output the result in another box.

    Please note i already tried breaking the string into an array of characters and didnt do the job.

    tl;dr I need a way to stream a string,character by character.

    Thanks in advance.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You can enumerate all characters in a string:

    for (auto elem : str)
    // elem is your character

    // Or for pre-C++11
    for (std::string::iterator it = str.begin(); it != str.end(); ++it)
    // *it is your character
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. simple calculator
    By symcy in forum C Programming
    Replies: 2
    Last Post: 02-05-2011, 12:04 PM
  2. simple calculator
    By yacek in forum C Programming
    Replies: 10
    Last Post: 10-07-2010, 05:24 AM
  3. Simple calculator
    By princeyeni in forum C++ Programming
    Replies: 6
    Last Post: 05-05-2010, 03:54 AM
  4. very simple calculator
    By N_D_E in forum C Programming
    Replies: 4
    Last Post: 03-22-2010, 07:18 PM
  5. A simple calculator in C
    By AlphaMac in forum C Programming
    Replies: 11
    Last Post: 10-14-2006, 01:26 AM

Tags for this Thread