D
D
desmeoni2020-08-08 03:07:30
C++ / C#
desmeoni, 2020-08-08 03:07:30

How does the calculator process the expression in parentheses?

I am analyzing the second version of the calculator from Chapter 6 of Mr. Stroustrup. I can not understand how such an example is processed: 5*(2*3).
Where does the first and second token go? Primary encounters a parenthesis and then there is a multiplication in parentheses, but we have already passed the first and second token to the term() function. How, after completing the operation inside the brackets, can we perform the multiplication on the first token?

spoiler

double primary()
{
    Token t = ts.get();
    switch (t.kind) {
    case '(':
        {
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error("')' expected");
            return d;
        }
    case '8':
        return t.value;
    default:
        error("primary expected");
    }
}
//------------------------------------------------------------------------------

int main()
try {
    while (cin)
        cout << expression() << '\n';
    keep_window_open("~0");
}
catch (exception& e) {
    cerr << e.what() << endl;
    keep_window_open ("~1");
    return 1;
}
catch (...) {
    cerr << "exception \n";
    keep_window_open ("~2");
    return 2;
}

//------------------------------------------------------------------------------

double expression()
{
    double left = term();    
    Token t = ts.get();      
    while(true) {
        switch(t.kind) {
        case '+':
            left += term();
            t = ts.get();
            break;
        case '-':
            left -= term();
            t = ts.get();
            break;
        default:
            ts.putback(t);
            return left;
        }
    }
}

//------------------------------------------------------------------------------

double term()
{
    double left = primary();
    Token t = ts.get(); 

    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;
            }
        default:
            ts.putback(t);
            return left;
        }
    }
}



All code

#include <./std_lib_facilities.h>

//------------------------------------------------------------------------------

class Token {
public:
    char kind;        
    double value;    
    Token(char ch)    
        :kind(ch), value(0) { }
    Token(char ch, double val)     
        :kind(ch), value(val) { }
};

class Token_stream {
    public:
        Token get();            
        void putback(Token t);  
    private:
        bool full {false};      
        Token buffer = {'0'};   
};

void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;         
    full = true;        
}

Token Token_stream::get()
{
    if (full) {
        full = false;
        return buffer;
    }
    char ch;
    cin >> ch;

    switch (ch) {
        case ';':       
        case 'q':       
        case '(':
        case ')':
        case '+':
        case '-':
        case '*':
        case '/':
            return Token{ch};  
        case '.':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            {
                cin.putback(ch);
                double val;
                cin >> val;
                return Token{'8', val};
            }
        default:
            error("Bad Token");
    }
}

//------------------------------------------------------------------------------

Token_stream ts;

//------------------------------------------------------------------------------

double expression();

//------------------------------------------------------------------------------

double term();

//------------------------------------------------------------------------------

double primary()
{
    Token t = ts.get();
    switch (t.kind) {
    case '(':
        {
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error("')' expected");
            return d;
        }
    case '8':
        return t.value;
    default:
        error("primary expected");
    }
}
//------------------------------------------------------------------------------

int main()
try {
    while (cin)
        cout << expression() << '\n';
    keep_window_open("~0");
}
catch (exception& e) {
    cerr << e.what() << endl;
    keep_window_open ("~1");
    return 1;
}
catch (...) {
    cerr << "exception \n";
    keep_window_open ("~2");
    return 2;
}

//------------------------------------------------------------------------------

double expression()
{
    double left = term();     
    Token t = ts.get();        
    while(true) {
        switch(t.kind) {
        case '+':
            left += term();
            t = ts.get();
            break;
        case '-':
            left -= term();
            t = ts.get();
            break;
        default:
            ts.putback(t);
            return left;
        }
    }
}

//------------------------------------------------------------------------------

double term()
{
    double left = primary(); 
    Token t = ts.get();    

    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;
            }
        default:
            ts.putback(t); 
            return left; 
        }
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Denis Zagaevsky, 2020-08-08
@desmeoni

This is a rather clumsy implementation of recursive descent.
After the completion of the expression in brackets, there will be a recursive return to the line from which primary was called, that is, on left *= primary()
left at this point will be 5, primary is the result of the expression in brackets.
The key word is recursion.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question