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"
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии