Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.62/55: Рейтинг темы: голосов - 55, средняя оценка - 4.62
 Аватар для include_
0 / 0 / 0
Регистрация: 09.08.2016
Сообщений: 6

Калькулятор Страуструпа (C++)

11.08.2016, 20:53. Показов 12164. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый вечер!
Я изучаю "Принципы и практика использования C++" Страуструпа. Все, что он пишет, хорошо понимаю, но следующая логика поставила меня в тупик... Пожалуйста, объясните новичку в C++, зачем в следующем фрагменте кода используется вызов функции term() в конструкции switch(t.kind), если функция term() вызывалась до этого? И, если несложно, пожалуйста, объясните каким образом это все работать должно (можно с объяснением линейной логикой, поэтапно). Просто не хочу двигаться дальше, пока не пойму эту логику, иначе вообще тонуть начну.
Сам фрагмент из 6 главы, где реализуется калькулятор:
C
1
2
3
4
5
6
7
8
9
10
11
12
double expression() {
    // Реализует сложение и вычитание. Вызывает get_token() и term()
    double left = term(); // вызов функции умножения для получения результата, который запишется в double d
    token t = get_token();
    while (true) {
        switch (t.kind) {
        case '+': left += term(); t = get_token(); break;
        case '-': left -= term(); t = get_token(); break;
        default: return left;
        }
    }
}
1. Моя логика: вызываем функцию term(), тем самым "поднимаемся вверх" по приоритетам функций, пока не дойдем до фигурных скобок. Это term() до while(t.kind) Но тогда зачем нам вызывать term() перед сложением и вычитанием? Думаю, чтобы, например, если мы прошли всю иерархию и находимся в фигурных скобках, опять пойти "вверх" по функциям, вплоть до закрытия скобок. Боюсь ошибиться, а в книге ясного ответа я так и не нашел (четыре раза перечитывал главу).
Заранее спасибо всем, кто ответил!
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
11.08.2016, 20:53
Ответы с готовыми решениями:

Калькулятор Страуструпа
Вот код калькулятора, помогите исправить 2 вещи: 1) Когда в командной строке пишем, допустим А = 5, надо сделать так, чтобы 5 не писалось...

калькулятор Страуструпа
читаю книгу Бьерне Страуструпа "Программирование. Принципы и практика использования C++" в 6 главе описывается создание калькулятора...

Калькулятор Страуструпа С++
Я новичок в С++, пытаюсь читать Страуструпа. Дошёл до строчного калькулятора и не понимаю принципов его работы, перечитывал главу 4 раза....

13
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
11.08.2016, 21:03
include_, вы же понимаете, что мы не знаем что за методы term() и get_token() /
0
 Аватар для include_
0 / 0 / 0
Регистрация: 09.08.2016
Сообщений: 6
11.08.2016, 21:18  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
include_, вы же понимаете, что мы не знаем что за методы term() и get_token() /
Да, но, на мой взгляд, для объяснения чистой логики это не нужно. Просто хочу узнать, каким образом вообще работает такой код. Вот сам полный код калькулятора с сайта автора (http://www.stroustrup.com/dc_except.c):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// The desk calulator
 
// reads from standard input or command line 
// uses namespaces and no exceptions
 
// pp 190-1921, sec 8.3.3, Exceptions in Calculator
 
 
// uses += rather than push_back() for string
// to work around standard library bug
 
// uses istrstream from <strstream> rather than istringstream from <sstream>
// to work around standard library bug
 
// No guarantees offered. Constructive comments to [email]bs@research.att.com[/email]
 
 
#include <map>
#include<iostream>
#include<cctype>
#include<string>
 
using namespace std;
 
namespace Error {
 
    struct Zero_divide { };
 
    struct Syntax_error {
        const char* p;
        Syntax_error(const char* q) { p = q; }
    };
}
 
namespace Lexer {
 
    enum Token_value {
        NAME,       NUMBER,     END,
        PLUS='+',   MINUS='-',  MUL='*',    DIV='/',
        PRINT=';',  ASSIGN='=', LP='(',     RP=')'
    };
 
    Token_value curr_tok;
    double number_value;
    string string_value;
 
    Token_value get_token();
}
 
namespace Parser {
    double prim(bool get);      // handle primaries
    double term(bool get);      // multiply and divide
    double expr(bool get);      // add and subtract
 
    using namespace Lexer;
    using namespace Error;
}
 
namespace Symbol_table {
    map<string,double> table;
}
 
namespace Driver {
    int no_of_errors;
    std::istream* input;
 
    void skip();
}
 
Lexer::Token_value Lexer::get_token()
{
    char ch;
 
    do {    // skip whitespace except '\n'
        if(!Driver::input->get(ch)) return curr_tok = END;
    } while (ch!='\n' && isspace(ch));
 
    switch (ch) {
    case 0:
        return END;
    case ';':
    case '\n':
        return curr_tok=PRINT;
    case '*':
    case '/':
    case '+':
    case '-':
    case '(':
    case ')':
    case '=':
        return curr_tok=Token_value(ch);
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    case '.':
        Driver::input->putback(ch);
        *Driver::input >> number_value;
        return curr_tok=NUMBER;
    default:            // NAME, NAME =, or error
        if (isalpha(ch)) {
            string_value = ch;
            while (Driver::input->get(ch) && isalnum(ch))
                string_value += ch; // string_value.push_back(ch);
                                                        // to work around library bug
            Driver::input->putback(ch);
            return curr_tok=NAME;
        }
        throw Error::Syntax_error("bad token");
    }
}
 
 
double Parser::prim(bool get)       // handle primaries
{
    if (get) get_token();
 
    switch (curr_tok) {
    case Lexer::NUMBER: // floating point constant
        get_token();
        return number_value;
    case Lexer::NAME:
    {   double& v = Symbol_table::table[string_value];
        if (get_token() == ASSIGN) v = expr(1);
        return v;
    }
    case Lexer::MINUS:      // unary minus
        return -prim(1);
    case Lexer::LP:
    {   double e = expr(1);
        if (curr_tok != RP) throw Error::Syntax_error("`)' expected");
        get_token();              // eat ')'
        return e;
    }
    case Lexer::END:
        return 1;
    default:
        throw Error::Syntax_error("primary expected");
    }
}
 
double Parser::term(bool get)       // multiply and divide
{
    double left = prim(get);
 
    for (;;)            // ``forever''
        switch (curr_tok) {
        case Lexer::MUL:
            left *= prim(true);
            break;
        case Lexer::DIV:
            if (double d = prim(true)) {
                left /= d;
                break;
            }   
            throw Error::Zero_divide();
        default:
            return left;
        }
}
 
double Parser::expr(bool get)       // add and subtract
{
    double left = term(get);    
 
    for(;;)             // ``forever''
        switch (curr_tok) {
        case Lexer::PLUS:
            left += term(true);
            break;
        case Lexer::MINUS:
            left -= term(true);
            break;
        default:
            return left;
        }
}
 
void Driver::skip()
{
    no_of_errors++;
 
    while (*input) {    // discard characters until newline or semicolon
                // note: skip doesn't know the state of the parser
                //       so if the erro rwas caused by a newline
                //       or a semicolon, we need to look for
                //       yet another terminator
        char ch;
        input->get(ch);
 
        switch (ch) {
        case '\n':
        case ';':
            return;
        }
    }
}
 
#include <strstream.h>
 
int main(int argc, char* argv[])
{
    using namespace Driver;
 
    switch (argc) {
    case 1:          // read from standard input
        input = &cin;
        break;
    case 2:          // read argument string
        input = new istrstream(argv[1],strlen(argv[1]));
        break;
    default:
        cerr << "too many arguments\n";
        return 1;
    }
 
    // insert pre-defined names:
    Symbol_table::table["pi"] = 3.1415926535897932385;
    Symbol_table::table["e"]  = 2.7182818284590452354;
 
    while (*input) {
        cout<<"new expression:\n";
        try {
            Lexer::get_token();
            if (Lexer::curr_tok == Lexer::END) break;
            if (Lexer::curr_tok == Lexer::PRINT) continue;
            cout << Parser::expr(false) << '\n';
        }
        catch(Error::Zero_divide) {
            cerr << "attempt to divide by zero\n";
            skip();
        }
        catch(Error::Syntax_error e) {
            cerr << "syntax error:" << e.p << "\n";
            skip();
        }
    }
 
    if (input != &std::cin) delete input;
    return no_of_errors;
}

Не по теме:

Написал сей пост и сразу, кажется, начал понимать логику автора... Магия?

0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
11.08.2016, 21:21
Цитата Сообщение от include_ Посмотреть сообщение
Написал сей пост и сразу кажется начал понимать логику автора... Магия?
Это нормально, часто проблема/баг в коде проговариваются голосом перед командой за чашкой кофе и по лицам тимейтов в конкретный момент можно понять где ты нагавнокодил )))
3
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2016, 21:41
Лучший ответ Сообщение было отмечено include_ как решение

Решение

Цитата Сообщение от include_ Посмотреть сообщение
И, если несложно, пожалуйста, объясните каким образом это все работать должно
Ну так эта программа работает по методу рекурсивного спуска.
Функция expression считывает и вычисляет выражение, считывая и вычисляя цепочку слагаемых, вызывая для этого функцию term, которая вычисляет слагаемое, считывая и вычисляя цепочку сомножителей.
В функции expression первый вызов term считывает и вычисляет первое слагаемое, функция get_token считывает знак операции. Далее в цикле, пока знак операции - плюс или минус, считывается и вычисляется правое слагаемое и прибавляется или вычитается из результата. Таким образом рекурсивно действуют все функции в этом калькуляторе.
А что, правда у Страуструпа в новой книжке while (true) применено? В предыдущих у него for(; было в этом месте.

Добавлено через 1 минуту
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
include_, вы же понимаете, что мы не знаем что за методы term() и get_token()
Т.е. Страуструпа из принципа не читаете?

Добавлено через 1 минуту
Цитата Сообщение от include_ Посмотреть сообщение
Вот сам полный код калькулятора с сайта автора (http://www.stroustrup.com/dc_except.c):
Что-то не работает эта ссылка.
1
 Аватар для include_
0 / 0 / 0
Регистрация: 09.08.2016
Сообщений: 6
11.08.2016, 21:42  [ТС]
Цитата Сообщение от Mr.X Посмотреть сообщение
Что-то не работает эта ссылка.
Вот: http://www.stroustrup.com/dc_except.c , там видимо вместо со скобками считалось, судя по адресной строке.
P.s. Спасибо за подробный ответ!
Да, там while(true), но невелика разница от for(;
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2016, 21:51
Цитата Сообщение от include_ Посмотреть сообщение
Да, там while(true), но невелика разница от for(;
Да нет, по этой ссылке такой текст
C++
1
2
3
4
5
6
7
8
9
10
11
for(;;)             // ``forever''
        switch (curr_tok) {
        case Lexer::PLUS:
            left += term(true);
            break;
        case Lexer::MINUS:
            left -= term(true);
            break;
        default:
            return left;
        }
0
 Аватар для include_
0 / 0 / 0
Регистрация: 09.08.2016
Сообщений: 6
11.08.2016, 21:53  [ТС]
Цитата Сообщение от Mr.X Посмотреть сообщение
Да нет, по этой ссылке такой текст
Это на сайте (коды программ там не обновлялись очень давно). А я про книгу 2011-го года, именно там while. 233 страница глава 6.6
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2016, 22:07
Цитата Сообщение от include_ Посмотреть сообщение
Это на сайте (коды программ там не обновлялись очень давно). А я про книгу 2011-го года, именно там while. 233 страница глава 6.6
М-да, расстроил меня Страуструп. Конструкция for(;;) кажется мне гораздо более лаконичной и логичной, чем паскалевская.
0
11.08.2016, 22:12  [ТС]

Не по теме:

Цитата Сообщение от Mr.X Посмотреть сообщение
Конструкция for(;;) кажется мне гораздо более лаконичной и логичной, чем паскалевская.
Сужу со своего уровня "новичок": while(true) с ходу более понятна, так как тут ведь сразу видно, что цикл-то вечный, а цикл for(;;) более странно для нас выглядит и непривычно. ИМХО, может от этого Страуструп отталкивался :-)

0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2016, 22:24
Цитата Сообщение от include_ Посмотреть сообщение
Сужу со своего уровня "новичок": while(true) с ходу более понятна, так как тут ведь сразу видно, что цикл-то вечный, а цикл for(; более странно для нас выглядит и непривычно. ИМХО, может от этого Страуструп отталкивался :-)
Ну, в каждом языке бесконечный цикл по-своему обозначается, и в C/C++ это было очень лаконично, с чего вдруг он решил поменять на паскалевское - вообще непонятно. Так-то цикл for никуда не делся, и всем новичкам все равно надо его учить.
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.08.2016, 20:25
С чего это while стал вдруг "паскалевским" ?

Добавлено через 3 минуты
И да в разных версиях книги, код калькулятора немного качественно отличается, но это не важно ибо в данном случае важнее логика самого процесса парсинга нежели красота применения С++
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
13.08.2016, 00:24
Цитата Сообщение от Avazart Посмотреть сообщение
И да в разных версиях книги, код калькулятора немного качественно отличается, но это не важно ибо в данном случае важнее логика самого процесса парсинга нежели красота применения С++
Ну, тут Страуструп уже на самые основы покусился. Что-то он под старость вообще берегов не видит в своей дерзкой революционности!
0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
15.08.2016, 23:13
Цитата Сообщение от Avazart Посмотреть сообщение
И да в разных версиях книги, код калькулятора немного качественно отличается, но это не важно ибо в данном случае важнее логика самого процесса парсинга нежели красота применения С++
В моем издании вообще вот такая версия этого его "calculatorBuggy" как он его называет
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
15.08.2016, 23:13
Помогаю со студенческими работами здесь

калькулятор страуструпа
Всем привет, читаю книгу Страуструпа. Вроде все понимаю, циклы, условия if, switch, типы данных, вектора. Но начиная с 200й страницы когда...

Калькулятор Страуструпа
Компилятор выдает ошибку: C2361 пропуск инициализации &quot;d&quot; из-за метки &quot;default&quot;. (строка 51) Уже понятия не имею, как фиксить. Помогите. ...

Калькулятор страуструпа
Ну по крайней мере если это и не он, то очень на него похож. Проблема в скобках.Например: (1+1 - всё хорошо, выплывет ощибка...

Калькулятор в книге Страуструпа
Приветствую всех кто читает эту тему. У меня возникла проблема во время написании калькулятора. Он был описан в 6 главе книги и там же...

Калькулятор в книге Страуструпа
Я знал, что это довольно тяжелая книга, поэтому начал читать ее после другой о С++, но пример &quot;элементарного&quot; калькулятора...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Первый деплой
lagorue 16.01.2026
Не спеша развернул своё 1ое приложение в kubernetes. А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит токи на L и напряжения на C в установ. режимах до и. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru