Литмир - Электронная Библиотека
Содержание  
A
A

 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)

106
{"b":"248117","o":1}