// присваивает объекту класса Variable с именем s значение d
{
for (int i = 0; i<var_table.size; ++i)
if (var_table[i].name == s) {
var_table[i].value = d;
return;
}
error("set: неопределенная переменная", s);
}
Теперь можем считать и записывать переменные, представленные в виде объектов
класса
Variable
в векторе
var_table
. Как поместить новый объект класса
Variable
в вектор
var_table
? Как пользователь калькулятора должен сначала записать переменную, а затем присвоить ей значения? Можно сослаться на обозначения, принятые в языке С++.
double var = 7.2;
Это работает, но все переменные в данном калькулятора и так хранят значения типа
double
, поэтому явно указывать этот тип совершенно не обязательно. Можно было бы написать проще.
var = 7.2;
Что ж, возможно, но теперь мы не можем отличить определение новой переменной от синтаксической ошибки.
var1 = 7.2; // определение новой переменной с именем var1
var1 = 3.2; // определение новой переменной с именем var2
Ой! Очевидно, что мы имели в виду
var2 = 3.2;
но не сказали об этом явно (за исключением комментария). Это не катастрофа, но будем следовать традициям языков программирования, в частности языка С++, в которых объявления переменных с их инициализацией отличаются от присваивания. Мы можем использовать ключевое слово
double
, но для калькулятора нужно что-нибудь покороче, поэтому — следуя другой старой традиции — выбрали ключевое слово
let
.
let var = 7.2;
Грамматика принимает следующий вид:
Вычисление:
Инструкция
Печать
Выход
Инструкция вычисления
Инструкция:
Объявление
Выражение
Объявление:
"let" Имя "=" Выражение
Вычисление — это новое правило вывода в грамматике. Оно выражает цикл (в функции
calculate
), который позволяет выполнять несколько вычислений в ходе одного сеанса работы программы. При обработке выражений и объявлений это правило опирается на правило Инструкция. Например, инструкцию можно обработать следующим образом:
double statement
{
Token t = ts.get;
switch (t.kind) {
case let:
return declaration;
default:
ts.putback(t);
return expression;
}
}
Вместо функции
expression
в функции
calculate
можем использовать функцию
statement
.
void calculate
{
while (cin)
try {
cout << prompt;
Token t = ts.get;
while (t.kind == print) t=ts.get; //
игнорируем
"печать"
if (t.kind == quit) return; // выход
ts.putback(t);
cout << result << statement << endl;
}
catch (exception& e) {
cerr << e.what << endl; // выводим сообщение об ошибке
clean_up_mess;
}
}
Теперь необходимо написать функцию
declaration
. Что следует сделать? Нужно убедиться, что после ключевого слова
let
следует Имя, а за ним — символ = и Выражение. Именно это утверждает грамматика. Что делать с членом
name
? Мы должны добавить в вектор
var_table
типа
vector<Variable>
объект класса
Variable
c заданными строкой name и значением выражения. После этого мы сможем извлекать значения с помощью функции
get_value
и изменять их с помощью функции
set_value
. Однако сначала надо решить, что случится, если мы определим переменную дважды. Рассмотрим пример.
let v1 = 7;
let v1 = 8;
Мы решили, что повторное определение является ошибкой. Обычно это просто синтаксическая ошибка. Вероятно, мы имели в виду не то, что написали, а следующие инструкции:
let v1 = 7;
let v2 = 8;
Определение объекта класса
Variable
с именем
var
и значением
val
состоит из двух логических частей.
1. Проверяем, существует ли в векторе
var_table
объект класса
Variable
с именем
var
.
2. Добавляем пару (
var
,
val
) в вектор
var_table
.
Мы не должны использовать неинициализированные переменные, поэтому определили функции
is_declared
и
define_name
, представляющие эти две операции.
bool is_declared(string var)
// есть ли переменная var в векторе var_table?
{
for (int i = 0; i<var_table.size; ++i)
if (var_table[i].name == var) return true;
return false;
}
double define_name(string var, double val)
// добавляем пару (var,val) в вектор var_table
{
if (is_declared(var)) error(var,"declared twice");