@desmeoni
newbie

Как калькулятор обрабатывает выражение в скобках?

Разбираю вторую версию калькулятора из 6 главы господина Страуструпа. Не могу понять каким образом обрабатывается вот такой пример: 5*(2*3).
Куда девается первый и второй токен? Primary встречает скобку и дальше идёт умножение в скобках, но мы уже передали функции term() первый и второй токен. Как после завершения операции внутри скобок мы сможем выполнить умножение на первый токен?

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;
        }
    }
}



Весь код

#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; 
        }
    }
}

  • Вопрос задан
  • 81 просмотр
Решения вопроса 1
zagayevskiy
@zagayevskiy
Android developer at Yandex
Это довольно топорная реализация рекурсивного спуска.
После завершения выражения в скобках будет рекурсивный возврат на строку, откуда primary вызвана, то есть на left *= primary()
left в этот момент будет 5, primary - результатом выражения в скобках.
Ключевое слово - рекурсия.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы