Средства редактирования и форматирования документации стали одним из ранних приложений системы UNIX. Администрация Bell Labs, приобретая первую установку PDP-11, хотела иметь систему подготовки документации, а не операционную систему. (К счастью, заказчики получили больше, чем ожидали.)
Первая форматирующая программа roff — небольшая, быстрая программа, с которой легко было работать до тех пор, пока выпускались простые документы с помощью печатающего устройства. Следующая форматирующая программа nroff обладала большими возможностями. Ее автор Дж. Осанна вместо того, чтобы обеспечивать каждый вид документации по желанию пользователя, сделал свою программу программируемой, т.е. многие задачи форматирования решались путем программирования на языке nroff.
После приобретения в 1973 г. небольшого наборного устройства nroff была расширена и смогла поддерживать множество символов, а также шрифты разных кеглей и гарнитур. Новая программа получила название troff (по аналогии с "en-roff', а произносили это как "tee-roff".) Программы nroff и troff имели одну и ту же основу и один и тот же входной язык; nroff игнорировала команды типа смены размера шрифта, которые она не могла выполнить. В настоящей главе речь пойдет главным образом о troff, но большинство наших пояснений можно отнести и к nroff с учетом ограничений, налагаемых выводными устройствами.
Самое большое достоинство troff гибкость базового языка и ее возможности программирования. Она может выполнить почти любую задачу форматирования. Но гибкость обходится недешево, использовать troff часто бывает весьма трудно. Следует отметить, что почти все программное обеспечение UNIX для подготовки документации сконструировано таким образом, чтобы заместить некоторые фрагменты "чистой troff". Одним из примеров может служить разметка страницы: общий вид документа, как выглядят названия, заголовки и абзацы, где появляются номера страниц, как велики размеры страницы и т.д. Все соответствующие средства не встроены и должны программироваться. Однако пользователю не нужно специфицировать перечисленные выше детали для каждого документа, так как есть стандартный пакет форматирующих команд. Пользователь пакета не говорит: "Следующая строка должна центрироваться, состоять из прописных букв, выделенных жирным шрифтом". Вместо этого он должен сказать: "Следующая строка — заголовок", и тогда используется определение вида названия из пакета. Пользователи имеют дело с логическими компонентами документа названиями, заголовками, абзацами, сносками и т.п., а не с размерами, шрифтами и позициями.
К сожалению, планируемый как "стандартный" пакет команд форматирования не является более стандартным: распространение получили несколько пакетов плюс многие их варианты. Мы рассмотрим здесь два пакета общего назначения: ms, первоначальный "стандарт", и mm, более новую версию, стандартную в System V, а также пакет man для печати справочников. Основной акцент сделан на ms как на стандарт в седьмой версии; он может служить хорошим примером и является достаточно мощным для выполнения работы (с его помощью подготовлена наша книга, правда, пришлось добавить команду для задания требуемого нам шрифта).
Этот опыт типичен — пакеты макроопределений подходят для выполнения многих задач форматирования, но иногда необходимо вернуться к основным командам troff. В данной главе мы опишем лишь небольшую часть troff.
Хотя troff обеспечивает возможность полностью управлять выходным форматом, ее непросто использовать для набора более сложного материала, такого, как формулы, таблицы и рисунки. Их разметка так же трудна, как разметка страницы. Решить упомянутые выше проблемы можно по-разному. Существуют языки специального назначения для формул, таблиц и рисунков, которые заменяют пакеты команд форматирования. Каждый язык поддерживается отдельной программой, транслирующей его в команды troff. Программы взаимодействуют через программные каналы. Эти препроцессоры служат хорошим примером подхода к проблемам в UNIX: вместо расширения и усложнения troff с ней взаимодействуют отдельные программы. (Конечно, средства развития языка, описанные в гл. 8, были использованы для облегчения реализации.) Ниже описываются две программы: tbl, форматирующая таблицы, и eqn, форматирующая математические выражения.
Мы постараемся дать вам советы по подготовке документации и применению поддерживающих инструментов. Приводимые здесь примеры войдут в документ, описывающий язык hoc, из гл. 8 и справочного руководства. Сам документ приведен в приложении 2.
9.1 Пакет макроопределений
ms
Основная идея, заложенная в пакет макроопределений, состоит в том, что документ описывается в терминах его логических частей названия, заголовков разделов, абзацев, а не в деталях: расстановка пробелов, выбор шрифтов, определение размеров букв. Это спасает вас от рутинной работы и освобождает документ от несущественных подробностей. Фактически вы можете сделать свой документ совершенно иным, использовав другое множество макроопределений с теми же логическими именами. Так, один и тот же документ мог бы последовательно превращаться в технический отчет, доклад на конференции, журнальную статью и главу из книги с помощью одинаковых команд форматирования, интерпретируемых четырьмя разными пакетами макроопределений.
Входной поток troff представляет собой обычный текст, размеченный командами форматирования, независимо от использования пакета макроопределений. Существуют два вида команд. Команда первого вида состоит из точки в начале строки и следующей за ней одной (двух) буквы либо цифры и, возможно, параметра, как показано ниже:
.PP
.ft В
Это небольшой абзац, выделенный жирным шрифтом.
Все встроенные команды troff имеют имена, образованные строчными буквами, поэтому по соглашению командам в пакетах даются имена из прописных букв. В нашем примере .PP есть команда ms для абзаца, a .ff — команда troff, вызывающая замену обычного шрифта жирным. (Имена команд, управляющих шрифтами, состоят из прописных букв; шрифты могут быть разными на разных наборных устройствах.)
Команда второго вида это последовательность символов, начинающаяся с обратной дробной черты \, которая может оказаться в любом месте входного потока. Например, команда \fB также вызывает переключение на жирный шрифт. Она является примером чистой troff; ниже мы коротко ее рассмотрим.
Для форматирования достаточно вводить команду .PP перед каждым абзацем. В принципе при подготовке большинства документов можно обойтись дюжиной разных команд ms. Так, приложение 2, описывающее hoc, имеет название, имена авторов, резюме, автоматически нумеруемые заголовки разделов и абзацы. Здесь используется всего 14 различных команд, причем некоторые из них парами. В ms документ принимает следующую общую форму:
.TL
Название документа (одна или более строк)
.AU
Имена авторов, одно на строке
.AB
Резюме, оканчивающееся .AE
.AE
.NH
Нумеруемые заголовки (автоматически)
.PP
Абзац...
.PP
Другой абзац...
.SH
Подзаголовок (нет нумерации)
.PP
...
Команды форматирования могут появиться в начале строки. Входной текст между командами размещается в произвольной форме: расположение концов строк в нем не существенно, так как troff переносит слова с одной строки на другую, чтобы сделать строки более полными (процесс, называемый заполнением), и расставляет дополнительные пробелы между словами, чтобы выровнять границы (выравнивание). Тем не менее начинать каждое предложение с новой строки считается хорошим стилем; это облегчает последующее редактирование.
Ниже показано начало непосредственного документа hoc:
.TL
Hoc - диалоговый язык для арифметики с плавающей точкой
.AU
Брайан Керниган
Роб Пайк
.AB
.I Hoc
это простой программируемый интерпретатор
для выражений с плавающей точкой.
Он обеспечивает поток управления в стиле Си,
определения функций и обычные
числовые встроенные функции,
такие как косинус и логарифм.
.AE
.NH
Выражения
.PP
.I Hoc
Это язык выражений, во многом подобный Си:
хотя он содержит несколько управляющих операторов,
большинство операторов, таких как присваивания,
это выражения, чьи значения не принимаются
во внимание.
...
Команда .I выделяет свой аргумент курсивом или переключает шрифт на курсив, если аргумента нет.
При использовании пакета макроопределений он специфицируется как аргумент troff:
$ troff -ms hoc.ms
Символы после -m определяют пакет макроопределений. После форматирования с помощью ms документ hoc выглядит так:
Hoc — диалоговый язык для арифметики с плавающей точкой
Брайан Керниган
Роб Пайк
РЕЗЮМЕ
Hoc — это простой программируемый интерпретатор для выражений с плавающей точкой. Он обеспечивает поток управления в стиле Си, определения функций и обычные числовые встроенные функции, такие как косинус и логарифм.
1. Выражения
Hoc — это язык выражений, во многом подобный Си; хотя он содержит несколько управляющих операторов, большинство операторов, таких как присваивания, это выражения, чьи значения не принимаются во внимание.
Отображения
Хотя нам и удобно, что troff осуществляет заполнение и выравнивание текста, иногда нежелательно, в частности для программ, выравнивать их границы. Такое форматированное представление называется отображением текста. Команды ms .DS (начало отображения) и .DE (конец отображения) ограничивают текст, благодаря чему он выводится с отступами, но без реорганизации. Посмотрите на следующий фрагмент руководства по hoc, включающий короткое отображение:
.PP
.I Hoc
Это язык выражений,
во многом подобный Си:
хотя он содержит несколько управляющих операторов,
большинство операторов, таких как присваивания,
это выражения, чьи значения не принимаются во внимание.
Например, оператор присваивания
= присваивает значение его правой части
его левому операнду и вырабатывает значение,
используемое в многократном присваивании.
Грамматика выражений такова:
.DS
.I
выражение: число
| переменная
| (выражение)
| выражение бинарная-операция выражение
| унарная-операция выражение
| функция(аргументы)
.R
.DE
Числа представляются с плавающей точкой.
Данный фрагмент печатается так:
Hoc — это язык выражений, во многом подобный Си; хотя он содержит несколько управляющих операторов, большинство операторов, таких как присваивания, — это выражения, чьи значения не принимаются во внимание. Например, оператор присваивания = присваивает значение своей правой части левому операнду и вырабатывает значение, используемое в многократном присваивании. Грамматика выражений такова:
выражение: число
| переменная
| (выражение)
| выражение бинарная_операция выражение
| унарная_операция выражение
| функция (аргументы)
Числа представляются с плавающей точкой.
Текст внутри отображения не является ни нормально заполненным, ни выравненным. Далее, если места на текущей странице не хватает, отображаемый материал (и все, что за ним следует) переносится на следующую страницу. Команда .DS обеспечивает несколько флагов, включая L для левого выравнивания, С для индивидуальной центровки каждой строки и В для центровки всего отображения.
Фрагменты текста в приведенном выше отображении разделены символами табуляции. По умолчанию символы табуляции troff ставятся через каждые полдюйма, а не через восемь пробелов, как обычно. Даже если бы эти символы вставлялись через каждые восемь пробелов, символы табуляции, обрабатываемые troff, не всегда бы появлялись там, где нужно из-за их переменной ширины.
Смена шрифта
Макроопределения ms обеспечивают три команды смены шрифта. Команда .R меняет шрифт на латинский (обычный), .I устанавливает курсив, а .B — жирный шрифт:
Этот текст обычный,
.I
это курсив
.R
это снова обычный, а
.B
это жирный шрифт.
При выполнении команд приведенный выше текст превращается в следующий:
Этот текст обычный, это курсив , это снова обычный, а это жирный шрифт .
Команды .I и .В воспринимают возможные аргументы, причем смена шрифта относится только к аргументу. В troff аргументы, содержащие пробелы, должны быть экранированы, и единственным символом для такой операции служит двойная кавычка ".
Это обычный текст, но
.I - это
курсив, а
.В "эти слова"
напечатаны жирным шрифтом.
Данный текст печатается так:
Это обычный текст, но — это курсив, а эти слова напечатаны жирным шрифтом.
В конечном счете второй аргумент для .I или .B, напечатанный обычным шрифтом, добавляется без пробелов к первому аргументу. Это средство широко используется при выборе шрифта для пунктуации. Обратите внимание на последнюю скобку фразы
(взятые в скобки
.I "слова курсивом)"
которая печатается неверно в виде
(взятые в скобки слова курсивом)
и сравните ее с фразой
(взятые в скобки
.I "слова курсивом")
которая печатается верно как
(взятые в скобки слова курсивом )
Различные шрифты распознаются программой nroff, но результат оставляет желать лучшего. Символы курсива подчеркнуты и нет жирных литер, хотя некоторые версии nroff изображают жирный шрифт двойной печатью.
Смешанные команды
Сноски вводятся с помощью .FS и заканчиваются .FE. Ваше дело определить метку (сноску) в виде звездочки * или крестика †. Такая сноска создается следующим образом:
определяющая метка типа звездочки или крестика. \(dg
.FS
\(dg подобно этому .FE
Эта сноска была создана с помощью ...
Выделенные отступом абзацы, возможно с использованием номера или другой пометки на границе, создаются командой .IP. Сделаем следующее:
1. Первый небольшой абзац.
2. Второй абзац, который мы удлиняем, чтобы показать, что отступ во второй строке будет таким же, как в первой.
Для этого нужен такой входной текст:
.IP(1)
Первый небольшой абзац.
.IP(2)
Второй абзац ...
Команды .PP или .LP (выравненный слева абзац) завершают дело, начатое командой .IP. Аргументом .IP может быть любая строка: введите кавычки, а при необходимости и пробелы. Второй аргумент можно использовать, чтобы определить значение отступа.
Когда вы работаете с парой команд .KS и .KE, текст должен быть размещен в одном месте; текст, заключенный между этими командами, будет перенесен на новую страницу, если он не разместится весь на текущей странице. Заменив .KS на .KF, вы можете передвинуть текст за последующий текст в верхнюю часть следующей страницы (если его необходимо поместить на одной странице). Все таблицы в книге построены с помощью .KF.
Можно изменить большинство значений ms, принятых по умолчанию, путем установки некоторого числа регистров, являющихся переменными troff и используемых ms. Наиболее часто применяются регистры, управляющие размером текста и интервалом между строками. Нормальным размером текста считается размер в "10 точек", где точка составляет 1/72 дюйма (единица, заимствованная из полиграфии). Обычно строки печатаются с 12-точечным разделением (интервалом). Чтобы изменить интервал, например на 9 или 11 точек (как сделано в наших отображениях), присвойте указанные числа регистрам PS и VS:
.nr PS 9
.nr VS 11
Другие числовые регистры включают LL для установки длины строки, PI — для определения отступов абзацев и PD — для отделения последних. Это влияет на следующие .PP или .LP.
Пакет макроопределений mm
Мы не будем подробно рассматривать этот пакет макроопределений, поскольку в целом, а зачастую и в деталях он похож на ms. Пакет mm обеспечивает контроль параметров в расширенном по сравнению с ms диапазоне, обладает большими возможностями (например, автоматически нумеруемые списки) и выдает лучшие сообщения об ошибках. В табл. 9.2 показаны команды mm, эквивалентные командам ms из табл. 9.1.
.AB | Печатать резюме; оканчивается .AE |
.AU | Ввести в следующей строке имя автора; разрешены многократные .AU |
.B | Начать печатать "жирный" текст либо выделить жирным шрифтом аргумент, если он есть |
.DS t | Начать отображать (незаполненный) текст, оканчивающийся .DE t = L (выравнивание по левому краю), С (центрирование), В (центрирование блока) |
.EQ s | Начать выравнивание s (входной поток eqn ); оканчивается .EN |
.FS | Начать печатать сноску; оканчивается .FE |
Л | Начать печатать текст, выделенный курсивом, или выделить курсивом аргумент, если он есть |
.IP s | Сделать абзац с отступом, помеченный s |
.KF | Печатать слитно часть текста, если необходимо целиком передвинуть на следующую страницу; конец ее .KE |
.KS | Печатать статно часть текста на странице; заканчивается .KE |
.LP | Печатать новый выравненный слева абзац |
.NH n | Ввести чистовой заголовок n -го уровня; затем сам заголовок до .PP или .LP |
.PP | Сделать новый абзац |
.R | Вернуться к обычному шрифту |
.SH | Ввести подзаголовок; заголовок следует далее до .PP |
.TL | Далее печатать название до следующей команды ms |
.TS | Начать печатать таблицу (входной поток tbl ); оканчивается .ТЕ |
Таблица 9.1: Распространенные команды форматирования ms (см. также справочное руководство по ms(7) )
.AS | Начать печатать резюме; оканчивается .AE |
.AU | Задать имя автора |
.B | Начать печатать "жирный" текст либо выделить жирным шрифтом аргумент, если он есть |
.DF | Задать слитную часть текста, если необходимо ее целиком передвинуть на следующую страницу; оканчивается .DE |
.DS | Начать отображать текст; оканчивается .DE |
.EQ | Начать выравнивание (входной поток eqn ); оканчивается .EN |
.FS | Начать печатать сноску; оканчивается .FE |
.I | Начать печатать текст, выделенный курсивом, или выделить курсивом аргумент, если он есть |
.Hn "..." | Задать нумерованный заголовок n-го уровня "…" |
.HU "..." | Задать ненумерованный заголовок "…" |
.P | Сделать абзац. Используйте .nr Pt 1 один раз для создания абзаца с отступом |
.R | Вернуться к обычному шрифту |
.TL | Задать заголовок до следующей команды mm |
.TS | Начать печатать таблицу ( tbl входной поток); оканчивается . ТЕ |
Таблица 9.2: Распространенные команды форматирования mm
Упражнение 9.1
Пропуск завершающей команды типа .AE или .DE обычно ведет к неприятностям. Напишите программу mscheck для обнаружения ошибок во входном потоке ms (или в предпочитаемом вами пакете). Совет : воспользуйтесь awk .
9.2 Уровень
troff
На практике приходится иногда выходить за пределы возможностей ms, mm или других пакетов, чтобы реализовать некоторые свойства "чистой" troff. Однако, как и к программированию на языке Ассемблера, прибегать к этому следует в крайних случаях.
Вероятны три ситуации: доступ к специальным символам, использование встроенных команд замены шрифта и введение нескольких базовых функций форматирования.
Имена символов
Доступ к необходимым символам (греческим буквам, например, π, графике вида • и †, разнообразным штрихам и пробелам) несложен, хотя и не вполне систематизирован. Каждый такой символ имеет имя \ c , где с — одиночный символ, или \( cd , где cd — пара символов.
Программа troff печатает минус в коде ASCII как дефис, а не как '—'. Настоящий минус должен обозначаться через \-, а тире через \(em, называемое "em пунктир", символ "тире".
В табл. 9.3 перечислены наиболее часто используемые специальные символы; в справочном руководстве по troff их число намного больше (в вашей системе перечень специальных символов может быть иным).
- | - | Дефис |
\(hy | - | Дефис, аналогичный предыдущему |
\- | – | Знак "минус", набираемый текущим шрифтом |
\(mi | – | Знак "минус", набираемый математическим шрифтом |
\(em | — | em тире |
\& | Ничего; защищает точку в начале строки | |
\blank | Неразмножаемый пробел | |
\| | Неразмножаемый полупробел | |
\е | Символ экранирования, обычно \ | |
\(bu | Жирная точка | |
\(dg | Крестик † | |
\(*a | α, \(*b =β, \(*с =ξ, \(*p =π и т.д. | |
\fX | Символ смены шрифта на X ; Х = Р — предыдущий (шрифт) | |
\f(XX | Символ смены шрифта на XX | |
\sn | Символ смены размера шрифта на n ; n =0 — предыдущий | |
\s+-n | Относительная замена размера шрифта |
Таблица 9.3: Некоторые последовательности специальных символов troff
В ряде случаев требуется, чтобы troff не интерпретировала символ, особенно обратную дробную черту или точку в начале строки. Два наиболее часто применяемых "отменяющих" символа — \e и \&. Последовательность \е гарантированно печатается как обратная дробная черта, не интерпретируется и используется для получения такого символа в выходном потоке. С другой стороны, \& не несет никакой смысловой нагрузки: это пробел нулевой ширины. Главное назначение этой комбинации — заставить troff не интерпретировать точки в начале строк. Мы задействовали \е и \& здесь несколько раз. Например, фрагмент ms в начале главы был напечатан как
\&.TL
.I "Название документа"
\&.AU
.I "Имя автора"
\&.AB
\&...
...
Конечно, этот фрагмент был напечатан следующим образом:
\e&.TL
\&.I "Название документа"
\е& .AU
...
и вы можете себе представить, как в свою очередь был напечатан последний фрагмент.
Другой специальный символ, "неразмножаемый" пробел, появляется изредка: это символ \, за которым следует пробел. Как правило, troff размножает обычный пробел, чтобы выровнять границы, но неразмножаемый пробел не позволяет "растягивать" строку. Он подобен любому другому символу и имеет фиксированную ширину. Его также можно использовать для передачи нескольких слов единым аргументом:
.I Название\ документа
Смена шрифта и размера символов текста
В большинстве случаев замена шрифтов и форматов может быть сделана с помощью начинающей строку макрокоманды типа .I, но иногда их замена должна осуществляться и в строке. В частности, символ конца строки разделяет слова, поэтому если требуется сменить шрифт в середине слова, макрокоманду нельзя использовать. С помощью troff можно решить эту проблему (отметим, что именно troff, а не пакет ms обеспечивает такую возможность).
Встроенные (in-line) команды troff вводит с использованием символа \. Наиболее часто применяются команды \f для смены шрифта и \s для смены формата.
Шрифт, заменяемый командой \f, определяется символом, следующим непосредственно за f:
a\fBпро\fIизвольное \fR \fI мно\fBжество \fIшрифтов\fP
Это выводится как
про извольное мно жество шрифтов
При смене шрифта \fP возвращает нас к предыдущему шрифту — тому, который был до последнего переключения. (Есть только один предыдущий шрифт, т.е. стека нет.)
Некоторые шрифты имеют двухсимвольные имена. Они специфицируются форматом \f(XX, где XX — имя шрифта. Например, шрифт, которым напечатаны программы в нашей книге, называется CW (курьер постоянной ширины), поэтому keyword пишется так:
\f\(CWkeyword \fP
Очевидно, печатать это довольно неудобно, поэтому мы ввели расширение ms макрокоманду .CW, так что теперь нет необходимости печатать или читать символы \.
Воспользуемся указанным расширением, чтобы набирать слова внутри строки, такие, как troff, следующим образом:
The
.CW troff
formatter ...
Решения о форматировании, определяемые макрокомандами, также легко потом поменять.
Смена размера шрифта осуществляется последовательностью \sn, где n — одна или две цифры, определяющие новый размер: \s8 переключает на восьмиточечный размер. В принципе можно выполнять относительные замены, предпосылая размеру плюс или минус. Например, слова можно напечатать в SMALL CAPS, введя
\s-2SMALL CAPS\s0
Комбинация \s0 предписывает возвратить размер к его предыдущему значению. Это аналог \fP, но, следуя традиции troff, она не записывается как \sP. Наши расширения ms включают макрокоманду .UC (прописные буквы) для такого рода работы.
Основные команды troff
Даже располагая хорошим пакетом макрокоманд, мы должны знать достаточно много команд troff для управления пробелами и заполнением, для установки позиций табуляции и т.п. Команда .br вызывает "обрыв", т.е. следующий вводимый за .br текст окажется на новой выходной строке. Это явление можно использовать, например, чтобы расщепить длинное название в подходящем месте:
.TL
Hoc - Диалоговый язык
.BR
для арифметики с плавающей точкой
...
Команда .nf отключает нормальное заполнение выходных строк; каждая строка ввода переходит непосредственно в одну выходную строку. Команда .fi снова включает процедуру заполнения. Команда .се центрирует следующую строку.
Команда .bp начинает новую страницу. Команда .sp вызывает появление на выходе одной пустой строки. За командой .sp может следовать аргумент, чтобы задать число пустых строк или число пробелов:
.sp 3 Оставить 3 пустых строки
.sp .5 Оставить пустые полстроки
.sp 1.51 Отступить на 1,5 дюйма
.sp 3p Вставить 3 позиции
.sp 3.1с Оставить 3,1 сантиметра
Лишнее пространство в нижней части страницы не играет роли, поэтому .sp с большим аргументом эквивалентно bp.
Команда .ta устанавливает позиции табуляции (которые инициализируются каждые полдюйма). Команда
.ta n n n ...
расставляет позиции табуляции на определяемых расстояниях от левой границы. Как и для .sp, каждое число n измеряется в дюймах, если за ним следует 'i'. Позиция табуляции с суффиксом R вызывает правое выравнивание текста на очередной позиции табуляции, С вызывает центрированную табуляцию.
Команда .ps n устанавливает значение n размера шрифта; команда .ft X устанавливает шрифт X. Правила для увеличения размеров и возвращения к предыдущему значению те же самые, что и для \s и \f.
Определение макрокоманд
Определение макрокоманд во всей полноте потребовало бы от нас более детального изучения troff, чем это необходимо. Поэтому мы ограничимся здесь рассмотрением нескольких примеров. В частности, определение для .CW имеет вид
.de CW Начать определение
\&\f (CW\\$1\fP\\$2 Смена шрифта для первого аргумента
... Конец определения
Комбинация \$ n дает значение n-го аргумента при вызове макрокоманды: оно пусто в случае отсутствия n-го аргумента. Двойной символ \\ откладывает вычисление \$ n на время определения макрокоманды. Комбинация \& не позволяет интерпретировать аргумент как команду troff в том случае, если он начинается с точки, как показано ниже:
.CW .sp
9.3 Препроцессоры
tbl
и
eqn
Программа troff — большая и сложная, и поэтому модифицировать ее для того, чтобы она выполняла новую задачу, нелегко. Соответственно разработка программ для набора математических выражений и таблиц требует другого подхода, а именно создания специальных языков, реализованных отдельными программами eqn и tbl, действующих как процессоры для troff. Программа troff по существу представляет язык Ассемблера для наборной машины, a eqn и tbl компилируют для нее код.
Вначале появилась eqn. Это было первое применение yacc не для целей программирования. Программа tbl, разработанная позднее, аналогична eqn, хотя и имеет независимый синтаксис; tbl не использует yacc, так как ее грамматика достаточно проста.
Средства программных каналов UNIX предполагают строгое разделение на отдельные программы. Кроме разбиения на части (что так или иначе необходимо, поскольку troff уже достигла максимального размера для PDP-11), программные каналы сужают круг взаимодействия между частями программы и между разрабатывающими их программистами. Последнее особенно важно: чтобы сделать препроцессор, не нужно "залезать" в исходную программу. Далее программные каналы позволяют не создавать большие промежуточные файлы при условии, что компоненты намеренно запускаются отдельно с целью отладки.
Однако организация взаимодействия программ через конвейеры связана с некоторыми проблемами. Отчасти снижается быстродействие, поскольку увеличивается объем ввода и вывода: обычно и eqn, и tbl дают расширение выходного потока по отношению к входному в отношении 8:1. Еще более существенно, что информация идет только в одном направлении. Например, нет способа определения текущего размера шрифта, что создаст неудобства в пользовании языком. И, наконец, трудно обеспечить сообщения об ошибках, так как иногда трудно связать диагностику из troff с eqn и tbl. Тем не менее преимущества разделения значительно перекрывают недостатки, поэтому было написано несколько препроцессоров, основанных на этой модели.
Таблицы
Обсудим кратко работу tbl и прежде всего таблицу операций по документации к hoc. tbl читает свои входные файлы или стандартный входной поток и преобразует текст между командами .TS (начало таблицы) и .ТЕ (конец таблицы) в команды troff, печатающие таблицу, выравнивающие столбцы и обеспечивающие все типографские атрибуты. Строки .TS и .ТЕ тоже копируются, поэтому пакет макроопределений выдает для них подходящие определения с тем, например, чтобы можно было помещать таблицу на одной странице и отделять ее от окружающего текста.
При формировании сложных таблиц вам, конечно, придется обращаться к справочному руководству по tbl. Хотя для уяснения основных принципов работы вполне достаточно приведенного ниже примера (из документации по hoc).
.TS
center, box;
с s
lfCW 1
\fВТаблица 1:\fP Операции по порядку уменьшения приоритета
.sp.5
^ возведение в степень (\s-1FORTRAN\s0 **) правоассоциативна
!\- одноместные логическое и арифметическое отрицания
* / умножение, деление
+\- сложение, вычитание
> >= операции отношения: больше, больше или равно < <= меньше, меньше или равно
\&== != равно, не равно (все отношения одинакового приоритета)
&& логическое И (оба операнда всегда вычисляются)
|| логическое ИЛИ (оба операнда всегда вычисляются)
\&= присваивание, правоассоциативна
.ТЕ
В результате мы получаем следующую таблицу:
Таблица 1: Операции по порядку уменьшения приоритета
FB2Library.Elements.Table.TableItem
Слова перед точкой с запятой описывают глобальные свойства таблицы: центрировать по горизонтали на странице и заключить в рамку. Другие средства включают doublebox (сделать двойную рамку), allbox (включить каждый элемент в рамку) и expand (расширить таблицу на формат страницы).
Следующие строки до точки описывают формат различных секций таблицы. Первая спецификация служит для первой строки таблицы, вторая для второй, последняя для всех остальных строк. В табл. 1 вы видите только две строки спецификаций, поэтому вторая спецификация применяется к каждой строке таблицы посте первой. Символы формата для элементов центрированных в столбце, с, r и l для правого и левого выравнивания и n — для выравнивания чисел по десятичной точке. Символ S определяет столбец с промежутком; в нашем случае 'c s' означает центровку названия над всей таблицей путем задания размера второго столбца так же, как и первого. Для столбца можно определить шрифт. Спецификация tbl lfCW позволяет печатать выравненный по левому краю столбец шрифтом CW.
Текст таблицы следует за информацией для форматирования. Символы табуляции разделяют столбцы и некоторые команды troff, например .sp, которые уместны внутри таблиц. (Отметим пару вхождений \&: незащищенный передний символ - и знак = в столбцах указывают tbl на необходимость располагать строки таблицы в этой точке.)
Программа tbl строит более широкий набор таблиц, чем показано в примере: текст может помещаться в рамки, могут вертикально выравниваться заголовки столбцов и т.д. Самый легкий способ использовать tbl для создания сложных таблиц обратиться к справочному руководству по UNIX (том 2A) и применить перечисленные в нем команды.
Математические выражения
Второй препроцессор eqn превращает язык, описывающий математические выражения, в команды troff, чтобы эти выражения печатать. Препроцессор автоматически обрабатывает смены шрифта и формата и, кроме того, предоставляет имена для стандартных математических символов. Входной текст для eqn обычно находится между строками .EQ и .EN, аналогично командам tbl .TS и .ТЕ. Например,
.EQ
x sub i
.EN
выдаёт xi . Если используется пакет ms, уравнение печатается как "отображение", а возможный аргумент .EQ определяет номер уравнения. Например, формула интеграла Коши
записывается как
.EQ (9.1)
f( zeta ) ~=~ 1 over {2 pi i} int from С
f(z) over {z - zeta} dz
.EN
В основу языка eqn и положен способ чтения вслух математических формул. Единственное различие между "разговорной" математикой и входным текстом eqn состоит в том, что скобки { } отменяют заданные по умолчанию правила предшествования языка, однако обычные скобки специального смысла не имеют. Пробелы тем не менее важны. Заметим, что первое вхождение zeta в примере, приведенном выше, окружено пробелами: ключевые слова, такие, как zeta и over, распознаются только тогда, когда они окружены пробелами или скобками, но ни те, ни другие в выходной текст не попадают. Чтобы обеспечить пробелы в выходном потоке, используйте символ ~, как показано в примере (~=~). Для получения скобок используйте "{" и "}".
Существует несколько классов ключевых слов eqn. Греческие буквы записываются прописными и строчными: lambda и LAMBDA (λ и Λ). Другие математические символы имеют имена, такие как sum, int, infty, grad: Σ, ∫, ∞, ∇. Есть знаки позиции, например sub, sup, from, to, and, over:
Эта формула выводится так:
sum from i=0 to infinity x sub i sup 2~→~1 over {2pi}
Существуют знаки операций типа sqrt, расширяющие скобки, фигурные скобки и т.д. Программа eqn, кроме того, позволяет создавать из объектов столбцы и матрицы. Предусмотрены команды для управления шрифтами и позициями, если те, которые установлены по умолчанию, не подходят.
Часто приходится помещать небольшие математические выражения, такие, как log10(x), в тело текста, а не в отображение. Ключевое слово eqn delim определяет пару символов для выделения подобных выстроенных выражений. Символы, задаваемые в качестве левого и правого ограничителей, обычно одинаковы: часто применяется знак доллара $. Но поскольку hoc использует $ для аргументов, в нашем примере мы употребили @. Символ % тоже удобен как ограничитель, но других символов избегайте: многие из них имеют специальные назначения в различных программах, поэтому вы можете спровоцировать непредсказуемое поведение eqn (именно так у нас и получилось с этим разделом).
Итак, после обозначения
.EQ
delim @ @
.EN
можно напечатать встроенное выражение
в виде
@ sum from i == 0 to infinity x sub i @ can be printed.
Встроенные выражения используются для вывода формул в таблице (см. пример из документации по hoc):
.TS
center,box
css
lfCWn1.
\fВТаблица 3:\fР Встроенные константы
.sp.5
DEG 57.29577951308232087680 @180/pi@, градусы и радианы
E 2.71828182845904523536 @e@, основание натурального логарифма
GAMMA 0.57721566490153286060 @gamma@, константа Эйлера-Масчерони
PHI 1.61803398874989484820 @(sqrt5+1)/2@, золотое сечение
PI 3.14159265358979323846 @pi@, круговое трансцендентное число
.ТЕ
Из этой таблицы, кроме того, видно, как строки tbl помещают десятичные точки в числовых (n) столбцах. Результат показан ниже.
Таблица 3: Встроенные константы
FB2Library.Elements.Table.TableItem
И, наконец, поскольку eqn выделяет курсивом любую строку букв, которые она не распознает, довольно просто выделять обычные слова курсивом. Последовательность @Word@ например, печатается как Word. Но будьте внимательны: eqn распознает некоторые обычные символы (такие, как from и to) и специальным образом их рассматривает: она "глотает" пробелы, поэтому указанный прием следует применять с осторожностью.
Получение выходного потока
Как только ваш документ готов, вы должны соединить все препроцессоры и troff в цепочку, чтобы получить выходной поток. Порядок команд следующий: tbl, eqn, troff. Если вы просто используете troff, то печатайте
$ troff -ms имена_файлов (или -mm)
Иначе вам придется задать аргумент имена_файлов первой команде в цепочке и дать остальным командам читать их стандартный входной поток, как показано ниже:
$ eqn имена_файлов | troff -ms
или
$ tbl имена_файлов | eqn | troff -ms
Неудобно следить за тем из препроцессоров, который действительно должен печатать какой-то отдельный документ. Мы сочли уместным написать программу doctype, обеспечивающую вывод соответствующей последовательности команд:
$ doctype ch9.*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
$ doctype hoc.ms
cat hoc.ms | tbl | eqn | troff -ms
$
Программа doctype реализована с помощью инструментов, рассмотренных в гл. 4. В частности, программа awk отыскивает последовательность команд, используемую препроцессорами, и печатает строку команд, которые нужно вызвать, чтобы отформатировать документ. Она также находит команду .PP (абзац) для форматирования пакетом запросов ms.
$ cat doctype
# doctype: synthesize proper command line for troff
echo -n "cat $* | "
egrep -h (EQ|TS|\[|PS|IS|PP)' $* |
sort -u |
awk '
/^\.PP/ { ms++ }
/^\.EQ/ { eqn++ }
/^\.TS/ { tbl++ }
/^\.PS/ { pic++ }
/^\.IS/ { ideal++ }
/^\.\[/ { refer++ }
END {
if (refer > 0) printf "refer | "
if (pic > 0) printf "pic | "
if (ideal > 0) printf "ideal | "
if (tbl > 0) printf "tbl | "
if (eqn > 0) printf "eqn | "
printf "troff "
if (ms > 0) printf "-ms"
printf "\n"
} '
$
(Флаг -h заставляет ее подавлять заголовки имен файлов на каждой строке: к сожалению, этот аргумент есть не во всех версиях системы.) При сканировании входного потока собирается информация о том, какие компоненты используются. После просмотра входной поток обрабатывается в требуемой последовательности для печати выходного текста. В формировании документов troff со стандартными препроцессорами есть специфика, и главная задача состоит в том, чтобы заставить "думать" об этом саму машину.
Программа doctype в нашем примере подобна bundle-программе, которая создает программу. Однако в таком виде она требует от пользователя вновь вводить строку для shell. В одном из приводимых ниже упражнений вам предлагается это исправить.
Когда дело дойдет до запуска реальных команд troff, не забывайте, что поведение программы зависит от системы: на некоторых установках она управляет наборным устройством непосредственно, в то время как на других выдает в стандартный выходной поток информацию, которая должна быть послана на наборное устройство отдельной программой.
Между прочим, в новой версии этой программы не предусмотрена программа egrep или sort; awk сама просматривает весь входной поток. Для больших документов такой вариант оказывается слишком медленным, поэтому для ускорения поиска мы добавили egrep и затем sort -u, чтобы избавиться от дублирования. При построении типичных документов накладные расходы по созданию двух дополнительных разбирающих данные процессов меньше, чем запуск awk в тех же целях с большим объемом входного текста.
В качестве иллюстрации сравним doctype с версией, только запускающей awk применительно к содержимому данной главы (около 52 000 символов):
$ time awk '... doctype without egrep ...' ch9.*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
real 31.0
user 8.9
sys 2.8
$ time doctype ch9*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
real 7.0
user 1.0
sys 2.3
$
Сравнение, очевидно, в пользу версии с тремя процессами. (Работа была выполнена в однопользовательском режиме; соотношение значений времени показало бы даже более значительное преимущество версии egrep и при повышенной нагрузке на систему.) Отметим, что, прежде чем начать оптимизацию, мы получили сначала простую работающую версию.
Упражнение 9.2
Как мы сформатировали эту главу?
Упражнение 9.3
Если вашим ограничителем для eqn является знак доллара, то как вы получите этот знак в выходном потоке? Подсказка: исследуйте кавычки и предопределенные слова eqn .
Упражнение 9.4
Почему команда
$ doctype имена_файлов
не выполняется? Модифицируйте doctype так, чтобы запускать команду, полученную в результате, вместо того, чтобы ее печатать.
Упражнение 9.5
Важны ли накладные расходы на добавочную команду cat в doctype ? Перепишите doctype , чтобы избавиться от дополнительного процесса. Какая версия проще?
Упражнение 9.6
Что лучше: использовать doctype или писать файл shell , содержащий команды, для форматирования конкретного документа?
Упражнение 9.7
Поэкспериментируйте с различными комбинациями grep , egrep , fgrep , sed , awk и sort , чтобы повысить быстродействие doctype.
9.4 Справочник
Основной документацией для команды является обычно справочная страничка (называемая далее справочником) одностраничное описание в справочном руководстве по UNIX (см. рис. 9.2). Справочник хранится в стандартном каталоге, как правило, в /usr/man, в подкаталоге, нумерованном в соответствии с разделом руководства. Например, наш справочник для hoc хранится в /usr/man/man1/hoc.1.
Справочники печатаются с помощью команды man(1), т.е. файла shell, который запускает nroff -man, поэтому man hoc печатает справочник hoc. Если одно и то же имя появляется в нескольких разделах, как само man (раздел 1 описывает команду, тогда как раздел 7 описывает макрокоманды), то раздел можно определить для man как
$ man 7 man
В результате печатается только описание макрокоманд пакета man. По умолчанию принято печатать все справочники с определенным именем, использующим nroff, но man -t порождает справочники для наборного устройства с помощью troff.
Автор справочника создает файл в соответствующем подкаталоге /usr/man. Чтобы печатать справочник, команда man вызывает nroff или troff с пакетом макроопределений; это можно увидеть, отыскав команду man для вызовов форматирующей программы. Мы получили бы такой результат:
$ grep roff `which man`
nroff $opt -man $all ;;
neqn $all | nroff $opt -man ;;
troff $opt -man $all ;;
troff -t $opt -man $all | tc ;;
eqn $all troff $opt -man ;;
eqn $all troff -t $opt -man | tc ;;
$
Разнообразие достигается применением флагов: nroff или troff, запускается или нет eqn и т.д. Справочник по макрокомандам, вызываемый troff -man, определяет команды troff, форматирующие в стиле данного руководства. В принципе они аналогичны макрокомандам ms, но есть и различия, особенно в установке названия и командах смены шрифта. Макрокоманды кратко документированы в man(7), но основные из них легко запоминаются. Разметка справочника такова:
.TH COMMAND номер раздела
.SH NAME
команда \- краткое описание функций
.В команда возможные аргументы
.SH DESCRIPTION
Подробное объяснение команд и флагов.
Абзацы вводятся .PP.
.PP
Это новый абзац.
.SH FILES
Файлы, используемые командой, например, passwd(1)
упоминает /etc/passwd
.SH "SEE ALSO."
Ссылки к связанным документам, включая другие справочники
.SH DIAGNOSTICS
Описание некоторого необычного выходного потока
(например, см. cmp(1))
.SH BUGS
Неожиданные черты (не всегда ошибки; см. ниже)
Если какой-то раздел пуст, его заголовок опускается. Строка. .TH и разделы NAME, SYNOPSIS, DESCRIPTION не обязательны. Строка
.TH COMMAND номер раздела
называет команду и определяет номер раздела. Различные строки .SH идентифицируют разделы справочника. Разделы NAME и SYNOPSIS являются специальными; остальные содержат обычный текст. Раздел NAME называет команду (на этот раз строчными буквами) и дает ее описание в одной строке, а раздел SYNOPSIS называет флаги, но не описывает их. Как и в любом разделе, входной текст имеет произвольную форму, поэтому смену шрифта можно определять с помощью макрокоманд .B, .I, .R. В разделе SYNOPSIS и имя, и флаги выделены жирным шрифтом; прочая информация печатается обычным шрифтом. Разделы ed(1) NAME и SYNOPSIS, например, имеют вид и выводятся как
.SH NAME
ed \- text editor
.SH SYNOPSIS
.В ed
[
.B \-
][
.B \-x
][ name ]
NAME
ed - text editor
SYNOPSIS
ed [ - ][ -x ][ name ]
Заметьте, что используется \-, а не просто -.
Раздел DESCRIPTION описывает команду и ее флаги. В большинстве случаев это описание команды, а не языка, определяемого командой. Справочник сс(1) не определяет язык Си: он указывает, как запустить команду ее, чтобы компилировать программы на Си, как вызвать оптимизатор, где оставлен результат и т.п. Язык описывается в руководстве для пользователя по Си, на которое есть ссылки в разделе сс(1) SEE ALSO. С другой стороны, разделение не абсолютно: man(7) есть описание языка макрокоманд руководства.
По соглашению имена команд и метки флагов (такие, как "name" в справочнике ed) печатаются курсивом с помощью макрокоманды .I (первый аргумент печатается курсивом, второй обычным шрифтом). Макрокоманда .IR используется здесь потому, что макрокоманда .I в пакете не обеспечивает недокументированного, но удобного применения второго флага в ms.
Раздел FILES упоминает любые файлы, неявно используемые командой. DIAGNOSTICS следует включать только в том случае, если команда вырабатывает необычный выходной поток. Это могут быть диагностические сообщения, сведения о состоянии выхода или информация о неожиданных отклонениях от стандартного выполнения команды. Раздел BUGS тоже назван отчасти неверно. Дефекты, о которых здесь сообщается, представляют собой не столько ошибки, сколько недостатки - просто ошибки должны быть исправлены прежде, чем команда будет введена в систему. Чтобы понять, для чего нужны разделы DIAGNOSTICS и BUGS, вам следует пролистать стандартное руководство.
Поясним на примере, как писать справочник. Источник для hoc(1), /usr/man/man1/hoc.1, показан на рис. 9.1, а на рис. 9.2 представлен выходной текст после вызова.
$ man -t hoc
.TH HOC 1
.SH NAME
hoc \- диалоговый язык для арифметики с плавающей точкой
.SH SYNOPSYS
.В hoc
[ файл ... ]
.SH DESCRIPTION
.I Hoc
интерпретирует простой язык для арифметики с плавающей
точкой, примерно уровня Бейсика, с синтаксисом, подобным
Си, и с процедурами и функциями с аргументами, а также
с рекурсией.
.PP
Поименованные
.IR файлы
читаются и интерпретируются по порядку. Если
.I файл
не указан или если
.I файл это '\-'
.I hoc
интерпретирует стандартный входной поток.
.PP
Входной поток
.I Hoc состоит из
.I выражений и
.IR операторов.
Выражения вычисляются и их результаты печатаются.
Операторы,обычно присваивания и определения функций
или процедур, не вырабатывают выходного результата,
если они явно не вызывают
.IR print.
.SH "SEE ALSO"
.I
Hoc \- Диалоговый язык для арифметики с плавающей точкой
Брайана Кернигана и
Роба Пайка.
.br
.IR bas(1),
.IR bc(1)
and
.IR dc(1).
.SH BUGS
Восстановление после ошибок в определениях функции
и процедур несовершенно.
.br
Обработка концов строк не совсем удобна для пользователя.
Рис. 9.1. /usr/man/man1/hoc.1
HOC(1) HOC(1)
NAME
hoc – диалоговый язык для арифметики с плавающей точкой
SYNOPSYS
hoc [ файл … ]
DESCRIPTION
Hoc интерпретирует простой язык для арифметики с плавающей точкой, примерно уровня Бейсика, с синтаксисом, подобным Си, и с процедурами и функциями с аргументами, а также с рекурсией.
Поименованные файлы читаются и интерпретируются по порядку. Если файл не указан или если файл — это '-' hoc интерпретирует стандартный входной поток.
Входной поток Hoc состоит из выражений и операторов . Выражения вычисляются и их результаты печатаются. Операторы, обычно присваивания и определения функций, или процедур, не вырабатывают выходного результата, если они явно не вызывают print .
"SEE ALSO"
Hoc – Диалоговый язык для арифметики с плавающей точкой Брайана Кернигана и Роба Пайка.
bas(1) , bc(1) and dc(1) .
BUGS
Восстановление после ошибок в определениях функции и процедур несовершенно. Обработка концов строк не совсем удобна для пользователя.
8-я версия 1
Рис. 9.2. hoc(1)
Упражнение 9.8.
Напишите справочник для doctype . Напишите версию команды man, которая отыскивает документацию по вашим личным программам в вашем собственном каталоге man .
9.5 Дополнительные средства для подготовки документации
Для подготовки документации существует несколько дополнительных программ. Команда refer(1) отыскивает ссылки на ключевые слова, вставляет эти ссылки в строки вашего документа и помещает раздел ссылок в его конце. Определив соответствующую макрокоманду, вы можете добиться, чтобы refer печатала ссылки в том виде, в каком они вам нужны. Имеются определения для многих журналов по вычислительным наукам. Команда refer является частью седьмой версии, но не включена в некоторые другие версии.
Программы pic(1) и ideal(1) предназначены для подготовки рисунков, так же как eqn для уравнений. Подготовить рисунки значительно сложнее, чем уравнения (по крайней мере для набора), а поскольку традиции здесь отсутствуют, оба языка отчасти облегчают знакомство с этой техникой и ее использование. В качестве иллюстрации приведем простой рисунок и его выражение на pic.
.PS
.ps -1
box invis "document"; arrow
box dashed "pie"; arrow
box dashed "tbl";
arrow box dashed "eqn"; arrow
box "troff"; arrow
box invis "typesetter"
[ box invis "macro" "package"
spline right then up -> ] with .ne at 2nd last box.s
.ps +1
.PE
+-----+ +-----+ +-----+ +-------+
| | | | | | | |
документ->| pic |->| tbl |->| eqn |->| troff |->наборн. устр-во
| | | | | | | |
+-----+ +-----+ +-----+ +-------+
^
|
пакет макрокоманд ------+
Все рисунки в книге сделаны с помощью pic. Программы pic и ideal не являются частью седьмой версии, но сейчас они в нее включены.
Программы refer, pic и ideal представляют собой препроцессоры troff. Кроме того, в вашей документации есть программы для просмотра и комментирования текста. Наилучшая из известных программ — spell(1), которая выдает сообщения о возможных ошибках написания в файлах; мы ее здесь применяли. Программы style(1) и diction(1) анализируют пунктуацию, грамматику и использование языка. Со временем все они были превращены в "Рабочее место писателя" набор программ, помогающих улучшить стиль изложения. Эти программы полезны для обнаружения клише и слов, не являющихся необходимыми, а также некорректных фраз.
Программа spell считается стандартной. В вашей системе могут быть и другие программы, вы легко обнаружите их с помощью man:
$ man style diction wwb
или путем просмотра /bin и /usr/bin.
Историческая и библиографическая справка
Программа troff (ее автор — Дж. Осанна), предназначенная для графических систем CAT-4, имеет свою историю, восходя к RUNOFF , созданной Д. E. Зальтцером для CTSS в MIT в начале 60-х годов. Обе программы имеют общие цели и основной синтаксис команд, хотя troff , конечно, более сложная и мощная программа, а наличие eqn и других препроцессоров значительно повышает ее эффективность. Существует несколько новых программ для наборных устройств с более "цивилизованным" форматом входного текста; наиболее известны из них ТЕХ Д. Кнута ("ТЕХ and Metafont: New Direction in Typesetting", Digital Press, 1979) и Scribe Б. Рейда ("Scribe: a high level approach to computer document formatting". 7th Symposium on the Principles of Programming Languages, 1980).
Статья Фурута, Дж. Скофилда и А. Шоу "Document Formatting Systems: Survey, Concepts and Issues" (Computing Surveys, 1982) дает хороший обзор таких систем.
Представляет интерес оригинальная работа по eqn Б. Кернигана и Л. Черри "A system for typesetting mathematics" (CACM, March 1975). Пакеты макрокоманд ms , tbl и refer принадлежат M. Леску; они документированы только в справочном руководстве по UNIX (том 2А).
Препроцессор pic описан в статье Б. Кернигана "PIC a language for typesetting graphics" (Software Practice and Experience, January, 1982), препроцессор ideal в статье К Ван Вика "A high level language for describing pictures" (ACM Translation on Graphics, April, 1982).
Команда spell из файла shell , написанного С. Джонсоном, превратилась в Си-программу Д. МакИлроя. Программа spell из седьмого издания для быстрого поиска использует механизм хеширования и правила для автоматического отделения суффиксов и префиксов, чтобы уменьшить занимаемое словарем место. (См.: McIlroy. М. D. "Development of a spelling list". IEEE Transaction on Communications, January, 1982).
Программы style и diction описаны в работе Л. Черри "Computer aids for writers" (SYGPLAN Symposium on Text Manipulation, Portland, Oregon, June, 1981).