Чтение онлайн

ЖАНРЫ

UNIX — универсальная среда программирования
Шрифт:
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 '\0' */

 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 */

 char *name;

 double (*func);

} builtins[] = {

 "sin", sin,

 "cos", cos,

 "atan", atan,

 "log", Log, /* checks argument */

 "log10", Log10, /* checks argument */

 "exp", Exp, /* checks argument */

 "sqrt", Sqrt, /* checks argument */

 "int", integer,

 "abs", fabs,

 0, 0

};

init /* install constants and built-ins in table */

{

 int i;

 Symbol *s;

 for (i = 0; consts[i].name; i++)

Поделиться с друзьями: