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");
var_table.push_back(Variable(var,val));
return val;
}
Добавить новый объект класса
Variable
в вектор типа
vector<Variable>
легко; эту операцию выполняет функция-член вектора
push_back()
.
var_table.push_back(Variable(var,val));
Вызов конструктора
Variable(var,val)
создает соответствующий объект класса
Variable
, а затем функция
push_back()
добавляет этот объект в конец вектора
var_table
. В этих условиях и с учетом лексем
let
и
name
функция
declaration()
становится вполне очевидной.