16 / 16 / 1
Регистрация: 13.10.2012
Сообщений: 454
1

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

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

Author24 — интернет-сервис помощи студентам
Я знал, что это довольно тяжелая книга, поэтому начал читать ее после другой о С++, но пример "элементарного" калькулятора поставил меня в тупик с первых же строк. В этой теме я буду задавать вопросы относительно него по частям. Вот с самого начала: это всё вообще что? Даже не псевдокод, почему END в начале? Что за выражения? Что за термы? Первичное? Выражения? Прочитал весь пример, и так вопросов куча.
(стр. 70)
Грамматика языка калькулятора определяется следующими правилами:
программа:
END // END - это конец ввода
список-выраженийEND
список-выражений:
выражение PRINT // PRINT - это'\n' или';'
выражение PRINT список-выражений
выражение:
выражение+ терм
выражение - терм
терм
терм:
терм/ первичное
терм* первичное
первичное
первичное:
NUMBER // число с плавающей запятой в С++
NAME // имя в языке С++ за исключением'_'
NAME = выражение
- первичное
( выражение)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.07.2013, 14:48
Ответы с готовыми решениями:

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

Непонятный код в книге Страуструпа
Периодически встречаются ошибки. Это тоже, или какой-то синтаксис (Скачал бесплатную VS - не...

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

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

29
1405 / 647 / 135
Регистрация: 11.08.2011
Сообщений: 2,299
Записей в блоге: 2
29.07.2013, 13:32 21
Author24 — интернет-сервис помощи студентам
Она не сложная - просто вызывается expression, для каждого слагаемого вызывается term, и для каждого множителя(или делимого) в Терме вызывается primary.
1
16 / 16 / 1
Регистрация: 13.10.2012
Сообщений: 454
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;
...
0
1405 / 647 / 135
Регистрация: 11.08.2011
Сообщений: 2,299
Записей в блоге: 2
29.07.2013, 14:03 23
tramp_1-3, ты напутал. Вызов get_token должен быть сразу после for(;;). Т.е. что делает ф-ция (expression (term() ей аналогична практически):
1) Каждое выражение начинается со слагаемого. Считываем его при помощи ф-ции term;
2) Считываем токен в цикле for(;;)
3) Если то токен + или - , то, по правилам математики, дальше должно идти еще одно слагаемое. Вызываем ф-цию term(), чтобы найти следующее слагаемое.
4) Если этот токен не + и не -, это значит, что мы достигли конца выражения.

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

В моем издании еще было не for(;;), a while(true)
1
16 / 16 / 1
Регистрация: 13.10.2012
Сообщений: 454
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;
...
0
1405 / 647 / 135
Регистрация: 11.08.2011
Сообщений: 2,299
Записей в блоге: 2
29.07.2013, 15:16 27
Цитата Сообщение от tramp_1-3 Посмотреть сообщение
константа с плавающей точкой - просто число, которое ввел в программу пользователь?
да, это так.
Цитата Сообщение от tramp_1-3 Посмотреть сообщение
NAME - имя чего?
Это точно должно быть описано в книге. Скорее всего, это константа для обозначения имени. Т.е. для каждой лексемы есть свой тип и свое обозначение. NAME - для обозначения имен переменных.
1
16 / 16 / 1
Регистрация: 13.10.2012
Сообщений: 454
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() "ругается", если имя не было занесено в таблицу. Это означает, что в калькуляторе
можно использовать имя без предварительного описания, но в первый раз оно может появиться только
в левой части присваивания."
0
1405 / 647 / 135
Регистрация: 11.08.2011
Сообщений: 2,299
Записей в блоге: 2
29.07.2013, 15:54 29
tramp_1-3, да, т.к. здесь указывается реализация списка структур name, которая хранит: string - имя, value - значение и указатель на следующий объект переменной.
1
16 / 16 / 1
Регистрация: 13.10.2012
Сообщений: 454
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; 
} 
}
0
30.07.2013, 13:43
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.07.2013, 13:43
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru