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++)
Поделиться с друзьями: