Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.65
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
#1

Калькулятор в книге Страуструпа - C++

28.07.2013, 14:48. Просмотров 2425. Ответов 29
Метки нет (Все метки)

Я знал, что это довольно тяжелая книга, поэтому начал читать ее после другой о С++, но пример "элементарного" калькулятора поставил меня в тупик с первых же строк. В этой теме я буду задавать вопросы относительно него по частям. Вот с самого начала: это всё вообще что? Даже не псевдокод, почему END в начале? Что за выражения? Что за термы? Первичное? Выражения? Прочитал весь пример, и так вопросов куча.
(стр. 70)
Грамматика языка калькулятора определяется следующими правилами:
программа:
END // END - это конец ввода
список-выраженийEND
список-выражений:
выражение PRINT // PRINT - это'\n' или';'
выражение PRINT список-выражений
выражение:
выражение+ терм
выражение - терм
терм
терм:
терм/ первичное
терм* первичное
первичное
первичное:
NUMBER // число с плавающей запятой в С++
NAME // имя в языке С++ за исключением'_'
NAME = выражение
- первичное
( выражение)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.07.2013, 14:48
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Калькулятор в книге Страуструпа (C++):

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

Задача по книге Страуструпа после главы 3.9 - C++
Вот код который у меня получился, на данный момент: #include<iostream> #include<string> using namespace std; inline void...

Для того чтобы выучить С++ по книге Бьёрна Страуструпа - C++
Для того чтобы выучить С++ по книге Бьёрна Страуструпа обязательно знать Си??

Какой компилятор выбрать для лучшего изучения С++ по книге Берна Страуструпа?п - C++
Какой компилятор выбрать для лучшего изучения С++ по книге Берна Страуструпа? Возможно вопрос туповатый, но мне хотелось бы что-то...

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

Калькулятор Страуструпа (C++) - C++
Добрый вечер! Я изучаю "Принципы и практика использования C++" Страуструпа. Все, что он пишет, хорошо понимаю, но следующая логика...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 12:23  [ТС] #16
Цитата Сообщение от Dani Посмотреть сообщение
Знаете, сколько я с этим калькулятором мучился? И как раздражает, когда он еще главы 3-4 трындит про этот калькулятор (раздражает, когда не понял как работает калькулятор). Главное - выполнить упражнения, там сразу гораздо понятнее станет. get_token - не беда, поясню как время будет.
Вы прочли его книгу? Она стоит потраченных на неё усилий? После Праты подобные листниги это АдЪ...
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 12:26 #17
Цитата Сообщение от tramp_1-3 Посмотреть сообщение
Вы прочли его книгу? Она стоит потраченных на неё усилий? После Праты подобные листниги это АдЪ...
Лично мне - стоило. Это была моя первая книга. И сейчас почитываю временами. Это не АдЪ, просто он пытается все объяснить на реальных примерах и ход мыслей реального программиста, показать, как от быдлоидеи придти к нормальной и работающей идее, на всех этапах.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 13:11  [ТС] #18
Dani, функция expr () вызывается в программе первой? Ей передается все введенное выражение? Как происходит приращение (и чего?), чтобы программа достигла блока default: return left;? Чем больше спрашиваю, тем больше вопросов..
double expr() // складывает и вычитает
C++
1
2
3
4
5
6
{ 
double left = term(); 
for(;;) // ``вечно'' 
//
} 
}
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 13:27 #19
Да, функция expression вызывается в программе первой, т.к. нам надо посчитать выражение целиком (а не Терм например).
Ей ничего не передается - она берет только нужные токены из ввода. Приращение происходит так: вычисляем первое слагаемое, вызовом ф-ции term (вот эта строчка: double left = term(); ). Затем смотрим: есть ли после этого слагаемого знак "+" или "-"? Если есть, то это значит, что выражение посчитано не до конца, и мы идем дальше (это и есть бесконечный цикл, где мы проверяем полученный токен: если не + и не - , тогда выражение завершено).

Это, кстати, точно написано в книге.

Добавлено через 52 секунды
tramp_1-3, возможно, стоит перечитать главу помедленнее.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 13:30  [ТС] #20
Цитата Сообщение от Dani Посмотреть сообщение
возможно, стоит перечитать главу помедленнее.
Да раза 3-4 перечитывал, но в голове всё смешивается из-за этой сложной цепочки вызовов..
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 13:32 #21
Она не сложная - просто вызывается expression, для каждого слагаемого вызывается term, и для каждого множителя(или делимого) в Терме вызывается primary.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 13:58  [ТС] #22
Dani, в expr () после вызова get_token() функция term () возвращает уже следующий после left терм?
C++
1
2
3
4
5
6
7
8
double left = term(); 
for(;;) // ``вечно'' 
switch(curr_tok) { 
case PLUS: 
get_token(); // случай'+' 
left += term(); 
break;
...
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 14:03 #23
tramp_1-3, ты напутал. Вызов get_token должен быть сразу после for(;;). Т.е. что делает ф-ция (expression (term() ей аналогична практически):
1) Каждое выражение начинается со слагаемого. Считываем его при помощи ф-ции term;
2) Считываем токен в цикле for(;;)
3) Если то токен + или - , то, по правилам математики, дальше должно идти еще одно слагаемое. Вызываем ф-цию term(), чтобы найти следующее слагаемое.
4) Если этот токен не + и не -, это значит, что мы достигли конца выражения.

У тебя же токен считывается и выкидывается. По-моему, ты смотришь нерабочую версию калькулятора (в главе 6, там по-моему только третья функция expression правильная)
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 14:11  [ТС] #24
Цитата Сообщение от Dani Посмотреть сообщение
У тебя же токен считывается и выкидывается. По-моему, ты смотришь нерабочую версию калькулятора (в главе 6, там по-моему только третья функция expression правильная)
Попробую возразить: get_token () пишет в глобальную curr_tok, так что вроде ничего не выкидывается. Возможно, у нас издания разные..
Миниатюры
Калькулятор в книге Страуструпа  
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 14:18 #25
tramp_1-3, да, издания разные. Но смысл тот же, просто в моем издании он описывал поток лексем, со всем наворотами, а тут - все хитрее и непонятнее. Смысл в том, что то, как я написал - в default надо возвращать токен обратно в поток, а тут - токены все хитро используются, потому ничего возвращать не нужно, т.к. в curr_tok уже будет нужная лексема. Об этом не думай пока, сконцентрируйся на вызовах. Потом поймешь.

В моем издании еще было не for(;;), a while(true)
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 14:28  [ТС] #26
Dani, константа с плавающей точкой - просто число, которое ввел в программу пользователь?
NAME - имя чего? В чем вообще смысл блока case NAME: ?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
double number_value; 
char name_string[256]; 
double prim() // обрабатывает первичное
{ 
switch (curr_tok) { 
case NUMBER: // константа с плавающей точкой
get_token(); 
return number_value; 
case NAME: 
if (get_token() == ASSIGN) { 
name* n = insert(name_string); 
get_token(); 
n->value = expr(); 
return n->value; 
} 
return look(name_string)->value;
...
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 15:16 #27
Цитата Сообщение от tramp_1-3 Посмотреть сообщение
константа с плавающей точкой - просто число, которое ввел в программу пользователь?
да, это так.
Цитата Сообщение от tramp_1-3 Посмотреть сообщение
NAME - имя чего?
Это точно должно быть описано в книге. Скорее всего, это константа для обозначения имени. Т.е. для каждой лексемы есть свой тип и свое обозначение. NAME - для обозначения имен переменных.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
29.07.2013, 15:48  [ТС] #28
Цитата Сообщение от Dani Посмотреть сообщение
Это точно должно быть описано в книге. Скорее всего, это константа для обозначения имени. Т.е. для каждой лексемы есть свой тип и свое обозначение. NAME - для обозначения имен переменных.
В вашей реализации такого нет? Везде это просто "имя", это что, переменные в калькуляторе вводить можно?
"Если последнее значениеNUMBER хранится в глобальной переменнойnumber_value, то строковое
представление последнего значенияNAME хранится вname_string. Перед тем, как что-либо делать с
именем, калькулятор должен заглянуть вперед, чтобы выяснить, будет ли ему присваиваться значение,
или же будет только использоваться существующее его значение. В обоих случаях надо обратиться к
таблице имен. Эта таблица рассматривается в$$3.1.3; а здесь достаточно только знать, что она
состоит из записей, имеющих вид:
C++
1
2
3
4
5
struct name { 
char* string; 
name* next; 
double value; 
};
Бьерн Страуструп. Язык программирования С++
74
Членnext используется только служебными функциями, работающими с таблицей:
C++
1
2
name* look(const char*); 
name* insert(const char*);
Обе функции возвращают указатель на ту записьname, которая соответствует их параметру-строке.
Функцияlook() "ругается", если имя не было занесено в таблицу. Это означает, что в калькуляторе
можно использовать имя без предварительного описания, но в первый раз оно может появиться только
в левой части присваивания."
Dani
1393 / 637 / 57
Регистрация: 11.08.2011
Сообщений: 2,282
Записей в блоге: 2
Завершенные тесты: 1
29.07.2013, 15:54 #29
tramp_1-3, да, т.к. здесь указывается реализация списка структур name, которая хранит: string - имя, value - значение и указатель на следующий объект переменной.
tramp_1-3
14 / 14 / 1
Регистрация: 13.10.2012
Сообщений: 428
30.07.2013, 13:43  [ТС] #30
Dani, настало время функции ввода (а т.к. в плюсах ввод буферизуется, это делает её самой сложной)
Ввод всего всего выражения целиком (например,2 + 4 * 8 происходит в if(!cin.get(ch)) return curr_tok = END;?
Если да, то ведь в плюсах буферизованное выражения после прочтения (while (ch!='\n' && isspace(ch))) выкидывается и нигде не хранится, тогда как происходит дальнейшее обращение к ch?
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
token_value get_token() 
{ 
char ch; 
do { // пропускает обобщенные пробелы за исключением'\n' 
if(!cin.get(ch)) return curr_tok = END; 
} while (ch!='\n' && isspace(ch)); 
switch (ch) { 
case ';': 
case '\n': 
cin >> ws;  // пропуск обобщенного пробела
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 '.': 
cin.putback(ch); 
cin >> number_value; 
return curr_tok=NUMBER; 
default: // NAME, NAME= или ошибка
if (isalpha(ch)) { 
char* p = name_string; 
*p++ = ch; 
while (cin.get(ch) && isalnum(ch)) *p++ = ch; 
cin.putback(ch); 
*p = 0; 
return curr_tok=NAME; 
} 
error("недопустимая лексема");
return curr_tok=PRINT; 
} 
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.07.2013, 13:43
Привет! Вот еще темы с ответами:

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

Упражнение из книги Страуструпа. Программа мини-калькулятор. Цифры записанные в строковом формате - C++
Привет всем. Не могу понять, как необходимо изменить программу исходя из условия упражнения. Упражнение сформулировано так: ...

Обучение по книге Страуструпа "принципы и практика C++". Не выводится "Hello, World" - C++
Ребят, помогите пожалуйста, пропал на первом же примере из книги, автор даёт код для вывода Hello world!#include "std_lib_facilities.h" ...

задачки Страуструпа - C++
Сижу в обнимку с талмудом Страуструпа, изучаю С++ самостоятельно. Просить код писать не буду, разберусь. Некоторые терминологические вещи...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
30.07.2013, 13:43
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru