Категории
Самые читаемые
💎Читать книги // БЕСПЛАТНО // 📱Online » Компьютеры и Интернет » Программное обеспечение » UNIX — универсальная среда программирования - Брайан Керниган

Читаем без скачивания UNIX — универсальная среда программирования - Брайан Керниган

Читать онлайн UNIX — универсальная среда программирования - Брайан Керниган

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 62 63 64 65 66 67 68 69 70 ... 103
Перейти на страницу:

Продемонстрируем новые возможности 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 так, чтобы можно было использовать символ ';' как разделитель выражений наравне с символом перевода строки.

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

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

sin cos atan exp log log10 sqrt int abs

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

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

PI 3.14159265358979323846 Число π E 2.71828182845904523536 Основание натурального логарифма GAMMA 0.57721566490153286060 Константа Эйлера-Маскерони DEG 57.2957795130823208768 Отношение градуса к радиану PHI 1.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 строк текста), что для простоты редактирования и ускорения компиляции лучше разбить ее на отдельные файлы. Итак, теперь мы имеем пять файлов вместо одного:

hoc.y грамматика, main, yylex (как и прежде); hoc.h глобальные структуры данных для включения в другие файлы; symbol.c функции, работающие с таблицей имен: lookup, install; unit.c встроенные функции и константы; init; math.c функции для вызова стандартных математических функций: Sqrt, Log и т.д.

Необходимо более детально познакомиться с работой Си программы, состоящей из нескольких файлов, и программы make, чтобы переложить на нее часть своих обязанностей.

Вернемся снова к программе make и рассмотрим вначале структуру таблицы имен. Поименованный объект имеет имя, тип (VAR или BLTIN) и значение. Так, объект типа VAR имеет значение double; если объект является встроенным, то его значением служит указатель на функцию, возвращающую double. Данная информация используется в hoc.y, symbol.c и init.c. Ее можно размножить в трех экземплярах, но тогда легко ошибиться или забыть исправить один из экземпляров при внесении изменений. Вместо этого мы поместили общую информацию в файл макроопределений hoc.h, который можно включить при необходимости в любой файл. (Окончание .h традиционно, но не контролируется никакими программами.) В файл makefile также добавлены сведения о зависимости исходных файлов от hoc.h, чтобы при изменении hoc.h была проведена требуемая перекомпиляция.

$ cat hoc.h

typedef struct Symbol { /* symbol table entry */

 char *name;

 short type; /* VAR, BLTIN, UNDEF */

 union {

  double val; /* if VAR */

  double (*ptr)(); /* if BLTIN */

 } u;

 struct Symbol *next; /* to link to another */

} Symbol;

Symbol *install(), *lookup();

$

Тип UNDEF обозначает VAR, которой пока не присвоили значения. Объекты связаны в список с помощью элемента next в записи Symbol. Сам список является локальным для symbol.c, доступ к нему возможен только посредством функций lookup и install. Это позволяет в случае необходимости легко менять структуру таблицы имен (что мы уже сделали однажды). Функция lookup отыскивает в списке заданное имя и возвращает указатель на Symbol, если имя найдено, и 0 в противном случае. Таблица имен рассчитана на линейный поиск, что вполне допустимо для диалогового калькулятора, поскольку поиск имен выполняется не во время его работы, а в процессе разбора. Функция install вносит переменную и связанные с ней тип и значение в начало списка. Функция emalloc обращается к стандартной функции размещения malloc (см. справочное руководство по malloc(3)) и проверяет результат. Указанные три функции составляют содержимое файла symbol.c. Файл y.tab.h создается при выполнении команды yacc -d; он содержит операторы #define, порождаемые yacc для лексем NUMBER, VAR, BLTIN и т.д.

$ cat symbol.c

#include "hoc.h"

#include "y.tab.h"

static Symbol *symlist = 0; /* symbol table: linked list */

Symbol *lookup(s) /* find s in symbol table */

 char *s;

{

 Symbol *sp;

 for (sp = symlist; sp != (Symbol*)0; sp = sp->next)

  if (strcmp(sp->name, s) == 0)

   return sp;

 return 0; /* 0 ==> not found */

}

Symbol *install(s, t, d) /* install s in symbol table */

 char *s;

 int t;

 double d;

{

 Symbol *sp;

 char *emalloc();

 sp = (Symbol*)emalloc(sizeof(Symbol));

 sp->name = emalloc(strlen(s)+1); /* +1 for '' */

 strcpy(sp->name, s);

 sp->type = t;

 sp->u.val = d;

 sp->next = symlist; /* put at front of list */

 symlist = sp;

 return sp;

}

char *emalloc(n) /* check return from malloc */

 unsigned n;

{

 char *p, *malloc();

 p = malloc(n);

 if (p == 0)

  execerror("out of memory", (char*)0);

 return p;

}

$

Файл init.c содержит определения констант (PI и т.п.) и указатели на встроенные функции; они заносятся в таблицу имен функцией init, находящейся в main.

$ cat init.c

#include "hoc.h"

#include "y.tab.h"

#include <math.h>

extern double Log(), Log10(), Exp(), Sqrt(), integer();

static struct { /* Constants */

 char *name;

 double cval;

} consts[] = {

 "PI",   3.14159265358979323846,

 "E",     2.71828182845904523536,

 "GAMMA", 0.57721566490153286060, /* Euler */

 "DEG",  57.29577951308232087680, /* deg/radian */

 "PHI",   1.61803398874989484820, /* golden ratio */

 0,       0

};

static struct { /* Built-ins */

1 ... 62 63 64 65 66 67 68 69 70 ... 103
Перейти на страницу:
На этой странице вы можете бесплатно скачать UNIX — универсальная среда программирования - Брайан Керниган торрент бесплатно.
Комментарии