$ cat init.с
...
static struct { /* Keywords */
char *name;
int kval;
} keywords [] = {
"if", IF,
"else", ELSE,
"while", WHILE,
"print", PRINT,
0, 0,
};
...
Для занесения в таблицу имен ключевых слов нужно организовать еще один цикл в функции
init
:
...
for (i = 0; keywords[i].name; i++)
install(keywords[i].name, keywords[i].kval, 0.0);
...
Изменения в функциях, управляющих таблицей имен, не требуются; в файле
code.c
есть функция
prexpr
, которая вызывается при выполнении оператора вида
print
выраж.
prexpr() /* print numeric value */
{
Datum d;
d = pop();
printf ('"%.8g\n", d.val);
}
Это не та функция печати, которая автоматически вызывается для вывода окончательного результата вычислений. Здесь выбирается число из стека и добавляется символ перевода строки к выходному потоку.
Теперь
hoc5
представляет собой вполне полезный калькулятор, хотя для серьезного программирования необходимы дополнительные средства. В приведенных ниже упражнениях предлагаются возможные решения.
Упражнение 8.12
Добавьте для отладки к
hoc5
средство печати создаваемых машинных команд в понятной форме.
Упражнение 8.13
Введите в свою программу операции присваивания из языка Си вида
+=
,
*=
и т.п., а также операции инкремента и декремента
++
и
--
. Измените операции
&&
и
||
так, чтобы обеспечить вычисление слева направо и условное вычисление, как в Си программах.
Упражнение 8.14
Введите в
hoc5
оператор
for
, как в Си-программах. Добавьте операторы
break
и
continue
.
Упражнение 8.15
Как бы вы изменили грамматику или лексический анализатор
hoc5
(или и то, и другое), чтобы сделать программу более "терпимой" к использованию символов перевода строки? Каким образом можно ввести символ в качестве синонима символа перевода строки? Как ввести в язык примечания? Какой синтаксис, по вашему мнению, нужно использовать?
Упражнение 8.16
Добавьте к
hoc5
средства обработки прерываний, чтобы некорректные вычисления можно было остановить без потери значений уже вычисленных переменных.
Упражнение 8.17
Неудобно создавать программный файл, запускать его на выполнение, а затем редактировать с целью внесения небольших изменений. Как бы вы изменили
hoc5
, чтобы создать команду редактирования, которая автоматически вызывала бы редактор с уже считанной копией вашей
hoc
-программы?
Подсказка: изучите текст функции.
8.6 Этап 6: функции и процедуры; ввод-вывод
На последнем из описываемых здесь этапе развития программа значительно разрастается: в нее добавляются процедуры и функции, средства печати строк символов наряду с числами и чтения чисел из стандартного входного потока. Кроме того, в язык
hoc6
вводятся аргументы имен файлов, включая имя
"-"
, обозначающее стандартный входной поток. Все эти изменения увеличивают программу на 235 строк, доводя ее общий размер до 810 строк. В результате
hoc
преобразуется из калькулятора в интерпретатор языка программирования. Полностью программа приводится в приложении 3.
В грамматике вызовы функции определяются как выражения, а вызовы процедур как операторы. И то, и другое детально поясняется в приложении 2, где дается еще несколько примеров. Так, определение и использование процедуры печати всех чисел Фибоначчи, меньших заданного параметра, происходят следующим образом:
$ cat fib
proc fib() {
a = 0
b = 1
while (b < $1) {
print b
с = b
b = a+b
a = с
}
print "\n"
}
$ hoc6 fib -
fib(1000)
1 1 2 3 5 8 13 21 34.55 89 144 233 377 610 987
...
Здесь также показано использование файлов: имя файла
"-"
задает стандартный входной поток.
Ниже приведена функция "факториал":
$ cat fac
func fac() {
if ($1 <= 0) return 1 else return $1 * fac($1-1)
}
$ hoc6 fac -
fac(0)
1
fac(7)
5040
fac(10)
3628800
...
Внутри процедуры или функции к параметрам можно обращаться с помощью
$1
и т.д., как в командных файлах, но, кроме того, допустимо присваивание параметрам. Функции и процедуры рекурсивны, но в качестве локальных переменных можно использовать только параметры; остальные переменные являются глобальными, т.е. доступными во всей программе.