$ make -n
С другой стороны, если необходимо установить временную согласованность файлов, с помощью флага
-t
(touch исправить) вы можете как бы модифицировать файлы, не производя перетрансляции.
Обратите внимание на то, что мы ввели не только множество зависимостей между исходными файлами, но и несколько полезных процедур, сконцентрировав их в одном файле. По умолчанию программа
make
выполняет первое действие, указанное в файле
makefile
. Однако если на первом месте окажется элемент, помечающий правило зависимости, такой, как
symbol.o
или
pr
, то выполняться будет он. Считается, что в случае "пустой" зависимости элемент всегда берется не из последней версии, поэтому при запросе он обязательно должен изменяться. Итак,
$ make pr | lpr
инициирует распечатку зависимостей файлов на принтере. (Появление символа
@
в
"@pr"
подавляет эхо выполняемой команды, запущенной с помощью
make
.) Команда же
make clean
удаляет выходные файлы
yacc
, а также файлы
.o
.
Такой механизм пустых зависимостей в файле
makefile
часто оказывается более предпочтительным по сравнению с командным файлом как средство для концентрации в одном файле всех связанных операций. Область применения команды
make
не ограничивается только разработкой программ, она позволяет сгруппировать в единый набор все операции, имеющие временные зависимости.
Несколько замечаний относительно
lex
Программа
lex
порождает лексические анализаторы аналогично тому, как
yacc
генерирует программы грамматического разбора: вы создаете описание лексических правил вашего языка с помощью регулярных выражений и фрагментов Си программ, которые будут выполняться при обнаружении строки, соответствующей шаблону. Программа
lex
строит по этой информации распознаватель. Программы
lex
и
yacc
взаимодействуют таким же образом, как и описанные выше лексические анализаторы. Мы не собираемся здесь детально рассматривать
lex
; наша цель — заинтересовать вас, а подробности вы найдете в справочном руководстве по UNIX (том 2B).
Вначале приведем
lex
-программу из файла
lex.l
, которая заменяет применявшуюся до сих пор функцию
yylex
:
$ cat lex.l
%{
#include "hoc.h"
#include "y.tab.h"
extern int lineno;
%}
%%
[ \t] { ; } /* skip blanks and tabs */
[0-9]+\.?][0-9]*\.[0-9]+ {
sscanf(yytext, "%lf", &yylval.val);
return NUMBER;
}
[a-zA-Z][a-zA-Z0-9]* {
Symbol *s;
if ((s=lookup(yytext)) == 0)
s = install(yytext, UNDEF, 0.0);
yylval.sym = s;
return s->type == UNDEF ? VAR : s->type;
}
\n { lineno++; return '\n'; }
/* everything else */
. { return yytext[0]; }
$
Каждое "правило" является регулярным выражением, как и те, что использовались в
egrep
или
awk
, однако в отличие от них
lex
распознает комбинации в стиле Си типа
\t
и
\n
. Действие заключено в фигурные скобки. Правила проверяются по порядку, а конструкции с символами
*
и
+
задают сколь угодно длинную строку. Если правило применимо к текущей части входного потока, то выполняется действие. Совпавшая с правилом входная строка доступна в
lex
-программе под именем
yytext
. Чтобы работать в
lex
, нужно изменить файл
makefile
: Программа
make
$ cat makefile
YFLAGS = -d
OBJS = hoc.o lex.o init.o math.o symbol.o
hoc3: $(OBJS)
cc $(OBJS) -lm -ll -o hoc3
hoc.o: hoc.h
lex.o init.o symbol.o: hoc.h y.tab.h
...
$
"знает", как получить из файла
.l
настоящий файл
.o
; все, что требуется от нас, дать ей сведения о зависимостях. (Нужно добавить библиотеку
lex -ll
к списку каталогов, в которых ведет поиск команда сс, поскольку распознаватель, создаваемый
lex
, нуждается в дополнительных функциях.) Эффект получается весьма ощутимым, причем совершенно автоматически:
$ make
yacc -d hoc.y
conflicts: 1 shift/reduce
сс -с y.tab.c
rm y.tab.c
mv y.tab.o hoc.o
lex lex.l
сс -с lex.yy.c
rm lex.yy.c
mv lex.yy.o lex.o
сс -c init.c
сс -c math.c
сс -c symbol.c
cc hoc.o lex.o init.o math.o symbol.o -lm -ll -o hoc3