Читаем UNIX полностью

В целях отладки мы сочли удобным, чтобы функция execerror вызывала abort (см. справочное руководство по abort(3)), что приведет к распечатке содержимого памяти, которую затем смогут использовать программы adb и sdb. Когда разработка программы полностью завершится, обращение к abort будет заменено на longjmp.

В программе hoc2 лексический анализатор несколько иной. В нем учтено различие строчных и прописных букв, а поскольку теперь yyval является объединением, нужно выбрать подходящий элемент перед выходом из yylex. Ниже показаны измененные фрагменты:

yylex() /* hoc2 */

{

 ...

 if (с == '.' || isdigit(c)) { /* number */

  ungetc(c, stdin);

  scanf("%lf", &yylval.val);

  return NUMBER;

 }

 if (islower(c)) {

  yylval.index = с - 'a'; /* ASCII only */

  return VAR;

 }

...

Еще раз отметим, что тип лексемы (т.е. NUMBER) не совпадает с ее значением (например, 3.1416).

Продемонстрируем новые возможности hoc2 переменные и способность восстановления после ошибки:

$ hoc2

x = 355

355

y = 113

113

p = x/z                            z не определено, а значит, равно 0

hoc2: division by zero near line 4 Восстановление после ошибки

x/y

3.1415929

1е30 * 1е30                        Переполнение

hoc2: floating point exception near line 5

...

В самом деле, для PDP-11 требуются вполне конкретные меры, чтобы обнаружить переполнение вещественного, но на большинстве других машин hoc2 действует так, как показано выше.

Упражнение 8.3

Обеспечьте возможность запоминания последнего вычисленного значения, чтобы его не приходилось вводить снова для последовательности связанных вычислений. Одним из решений может быть использование какой-либо переменной, например 'p', в качестве "предыдущего" (previous) значения.

Упражнение 8.4

Измените программу hoc так, чтобы можно было использовать символ ';' как разделитель выражений наравне с символом перевода строки.

<p>8.3 Этап 3: переменные с произвольными именами; встроенные функции</p>

В версию hoc3 добавлено несколько новых средств, из-за чего увеличился текст программы. Основное нововведение возможность обращения к встроенным функциям:

sin cos atan exp log log10 sqrt int abs

Введена также дополнительно операция возведения в степень '^' (право ассоциативная с наивысшим приоритетом).

Поскольку лексический анализатор должен справляться с встроенными именами длиной более чем в один символ, не так уж много усилий придется приложить, чтобы допустить переменные с именами произвольной длины. Для хранения информации об этих переменных нужна довольно сложная таблица имен, но если мы ее создаем, то можно заранее задать в ней вместе с именами значения некоторых полезных констант:

PI3.14159265358979323846Число π
E2.71828182845904523536Основание натурального логарифма
GAMMA0.57721566490153286060Константа Эйлера-Маскерони
DEG57.2957795130823208768Отношение градуса к радиану
PHI1.61803398874989484820Золотое сечение

В результате получим полезный калькулятор:

$ hoc3

1.5^2.3

 2.5410306

exp(2*3*log(1.5))

 2.5410306

sin(PI/2)

 1

atan(1)*DEG

 45

Несколько улучшилась и работа распознавателя. В hoc2 присваивание x = expr не только вызывало присваивание, но и приводило к печати значения, поскольку все выражения печатаются:

$ hoc2

x=2*3.14159

6.28318 В случае присваивания переменной значение печатается

В программе hoc3 проводится различие между присваиваниями и выражениями; значения печатаются только для выражений:

$ hoc3

x=2*3.14159 Присваивание: значение не печатается

x           Выражение:

6.28318     Значение печатается

Получившаяся в результате всех этих изменений программа настолько велика (около 250 строк текста), что для простоты редактирования и ускорения компиляции лучше разбить ее на отдельные файлы. Итак, теперь мы имеем пять файлов вместо одного:

Перейти на страницу:

Похожие книги