Книга: Искусство программирования для Unix

8.2.6. Учебный пример: инструментарий Documenter's Workbench

8.2.6. Учебный пример: инструментарий Documenter's Workbench

Программа troff(1), средство форматирования текстов, была, как отмечалось в главе 2, первоначальным главным приложением операционной системы Unix. Программа troff является наиболее важной в наборе форматирующих средств (получивших коллективное название DWB, (Documenter's Workbench — автоматизированное рабочее место документатора), каждое из которых является отдельным узкоспециальным мини-языком. Большинство из них являются либо препроцессорами, либо постпроцессорами для troff-разметки. В Unix-системах с открытыми исходными кодами используется расширенная реализация DWB (которая называется groff(1)), созданная Фондом свободного программного обеспечения.

Подробнее программа troff рассматривается в главе 18. Здесь достаточно отметить, что она представляет собой хороший пример императивного мини-языка, граничащего с полностью проработанным интерпретатором (в troff поддерживаются условные операции и рекурсия, но нет циклов; troff — отчасти язык Тьюринга).

Постпроцессоры ("драйверы" в терминологии DWB) обычно невидимы для пользователей troff. Первоначально созданные troff-коды для отдельных наборных машин были доступны группе разработки Unix в 1970 году. Позднее они были улучшены до аппаратно-независимого мини-языка для размещения текста и простой графики на страницах. Постпроцессоры преобразовывают данный язык (получивший название "ditroff от device-independent troff — аппаратно-независимый troff) в некоторые данные, которые фактически могут принимать современные графические принтеры — наиболее важным из них (и современным стандартом) является PostScript.

Препроцессоры более интересны, поскольку они фактически расширяют возможности языка troff. Существует 3 распространенных препроцессора: tbl(1) для создания таблиц, eqn(1) для текстового представления математических уравнений и pic(1) для создания диаграмм. Реже используются, но до сих пор сохранились gm(1) для графики, refer(1) и bib(1) для форматирования библиографий. Эквиваленты данных программ с открытыми исходными кодами поставляются с пакетом groff. Препроцессор grap(1) предоставлял довольно гибкое средство для построения графиков; отдельно от groff существует его реализация с открытым исходным кодом.

Некоторые другие препроцессоры не имеют реализации с открытым исходным кодом и в настоящее время широко не используются. Наиболее известным из них была программа ideal(1) для форматирования графики. Более новый член данного семейства, chem(1) отображает формулы химических структур; программа доступна в репозитории netlib Bell Labs[83].

Каждый из описанных препроцессоров представляет собой небольшую программу, которая принимает мини-язык и компилирует его в troff-запросы. Каждый препроцессор распознает разметку, которую необходимо интерпретировать, путем поиска уникального начального и конечного запроса, а любую разметку за пределами таких запросов оставляет неизменной (программа tbl ищет строки TS/.TE, pic — .PS/.РЕ и т.п.). Таким образом, большинство препроцессоров обычно могут работать в любом порядке, не влияя на другую разметку. Существует несколько исключений: в частности, программы chem и grap используют команды программы pic, и поэтому в конвейерах она должна следовать после них.

cat thesis.ms | chem | tbl | refer | grap | pic | eqn
 | groff -Tps >thesis.ps

Выше приведен подробный пример конвейера DWB-обработки для гипотетических тезисов, включающих в себя химические формулы, математические уравнения, таблицы, библиографию, графики и диаграммы. (Команда cat(1) просто копирует свой ввод или содержимое указанного файла на свой вывод; здесь она используется для подчеркивания порядка операций.) На практике современные реализации troff часто поддерживают параметры командной строки, которые способны вызвать, по крайней мере, такие программы, как tbl(1), eqn(1) и pic(1), а поэтому писать такие сложные конвейеры не обязательно. Но даже если бы это понадобилось, такие инструкции для сборки обычно создаются один раз и сохраняются в make-файле или в shell-сценарии для повторного использования.

Разметка документов средствами Documenter's Workbench несколько устарела, однако диапазон проблем, которые решаются препроцессорами, является некоторым показателем мощности модели мини-языков — было бы чрезвычайно трудно встроить эквивалентные знания в текстовые процессоры класса WYSIWYG. Существует несколько областей, где современные инструментальные связки и способы разметки документов на основе XML, в 2003 году лишь приближаются к возможностям, которыми инструментарий DWB обладал в 1979 году. Эти вопросы подробнее освещаются в главе 18.

Конструктивные идеи, которые дали инструментарию DWB такую мощь, в настоящее время должны быть очевидны. Все инструменты совместно используют общее представление документов в виде текстовых потоков, а система форматирования разбита на независимые компоненты, которые можно отлаживать и совершенствовать по отдельности. Структура конвейеров поддерживает интеграцию с новыми, экспериментальными препроцессорами и постпроцессорами без нарушения работы старых. DWB — модульная и расширяемая конструкция.

Структура инструментария Documenter's Workbench в целом преподносит некоторые уроки того, как связывать несколько специальных языков во взаимодействующую систему. Один препроцессор может быть надстройкой доя другого. Действительно, инструментальные средства DWB были ранними примерами, демонстрирующими мощность каналов, фильтров и мини-языков, которые в дальнейшем во многом повлияли на конструкцию Unix. Конструкции отдельных препроцессоров способны предоставить еще больше примеров того, как выглядит конструкция эффективного мини-языка.

Один из этих уроков отрицательный. Иногда пользователи, пишущие описание в мини-языке, допускают некорректные действия с низкоуровневой troff-разметкой, вставленной вручную. Это может повлечь за собой последствия и ошибки, которые трудно диагностировать, поскольку данные, сгенерированные troff и выходящие из конвейера, не видны, а если бы были видны, то были бы нечитаемыми. Такие ошибки аналогичны ошибкам, которые возникают в коде, когда C-код смешан с фрагментами ассемблера. Было бы лучше, если бы уровни языков были разделены более основательно, если бы это было возможно. Разработчикам мини-языков следует учесть эти проблемы.

Все языки препроцессоров (кроме самой troff-разметки) имеют сравнительно четкий, shell-подобный синтаксис, которые соответствует многим описанным в главе 5 соглашениям о конструкции форматов файлов данных. Существует несколько затруднительных исключений. Особенно выделяется среди них программа tbl(1), по умолчанию использующая символ табуляции как разделитель полей между столбцами таблицы, дублирующая неприятные недоработки в конструкции make(1) и вызывающая досадные ошибки, когда редакторы или другие средства невидимо изменяют состав разделителей.

Хотя troff сам по себе представляет собой специализированный императивный мини-язык, одной из идей, которая "проходит" как минимум через 3 мини-языка в DWB, является декларативная семантика: компоновка документа на основе ограничивающих условий. Данная идея также характерна для современных GUI-инструментариев. Вместо того чтобы указывать координаты пикселей для графических объектов, единственное, что действительно требуется сделать — это объявить пространственные взаимозависимости между ними ("элемент управления А расположен выше элемента В, который находится слева от элемента С"), а затем заставить программное обеспечение вычислить наилучшее расположение элементов А, В и С, соответствующее заданным ограничивающим условиям.

В программе pic(1) данный подход используется для компоновки элементов диаграмм. Диаграмма классификации языков на рис. 8.1 была создана на основе приведенного в примере 8.4[84] исходного pic-кода, обработанного с помощью команды pic2graph, которая рассматривалась в одном из учебных примеров главы 7.

Это весьма типичная для Unix конструкция мини-языка, и как таковая она имеет несколько интересных моментов даже на уровне синтаксиса. Следует отметить ее сходство с shell-программой: комментарии начинаются с символа #, а синтаксис, очевидно, организован на основе лексем и имеет простейшее возможное соглашение для строк. Разработчик pic(1) знал, что Unix-программисты ожидают подобный этому синтаксис мини-языков, если не существует значительной и специфической причины не делать этого. В данном случае в полной мере выполняется правило наименьшей неожиданности.

Оглавление книги


Генерация: 1.631. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз