Препроцесори tbl і eqn

Програма troff велика і складна як усередині, так і зовні, тому змінювати її для того, щоб вона могла виконати якусь нову роботу, дуже непросто Ось чому у розробці програм для набору математичних текстів і таблиць був обраний інший підхід, були створені спеціальні мови, реалізовані програмами eqn і tbl, які діють стосовно troff як процесори поперед-

рительное обробки Насправді troff є мовою Асемблера для складальної машини, а eqn і tbl компілюють в нього

Першою зявилася eqn Тоді yacc був вперше використаний не для мови программірованія1 Потім прийшов час tbl, по суті своїй вона схожа на eqn, а ось синтаксиси у них не споріднені один одному Програма tbl не використовує yacc, так як її граматика настільки проста, що це не має сенсу

Можливість створення каналів в UNIX підводить до думки про розумність створення окремих програм Завдяки каналам відбувається не тільки розбиття задач на частини (що необхідно в кожному разі – розмір самої troff практично дорівнює максимально допустимому для програми на PDP-11), скорочується обмін даними між частинами, а також між програмістами Останнє дуже важливо, адже це означає, що для «Виготовлення» препроцесора не треба мати доступ до вихідних текстів Крім того, застосування каналів позбавляє від величезних проміжних файлів, якщо тільки компоненти не запускаються окремо спеціально, для налагодження

Коли окремі програми повідомляються через канали, виникають проблеми Через дуже великої кількості вхідних і вихідних даних декілька погіршується продуктивність: обидві програми – і eqn і tbl – зазвичай викликають збільшення обсягу даних від входу до виходу в 8 разів Ще важливіше, що інформація рухається тільки в одному напрямку Наприклад, не існує способу, яким eqn могла б висунути поточний кегль, що призводить до певної громіздкість мови І нарешті, повідомлення про помилки: часто буває нелегко както звязати діагностику, отриману в troff, з ситуацією, що виникла в eqn або tbl і викликала поява цього повідомлення

Але незважаючи на все це, переваги розподілу переважують недоліки, тому було написано кілька інших процесорів попередньої обробки, що використовують таку ж модель

Таблиці

Почнемо з короткого опису tbl, оскільки перше, що буде перед Подано у даному розділі, – це таблиця з документа про hoc Програма tbl зчитує файли введення або стандартний ввід і конвертує текст між командами TS (table start – початок таблиці) і TE (table end – кінець таблиці) в команди troff для виведення таблиці, вирівнюючи стовпці і піклуючись про всі типографських деталях Рядки TS і

. TE також копіюються, тому макропакет може дати їм відповідні визначення, наприклад зберігати таблицю на одній сторінці і відключити опцію обтікання тексту

1 Малоймовірно, що eqn зявилася б на світ, якби в потрібний момент під рукою не виявилося yacc

Для того щоб створювати складні таблиці, треба звернутися до керів ництва по tbl, а поки наведемо один приклад, якого буде цілком достатньо, щоб пояснити основні властивості Таблиця взята з документа по hoc:

.TS

center, box c s

lfCW  l

\fBTable  1:\fP Operators,  in  decreasing order  of  precedence

.sp  5

^             exponentiation (\s–1FORTRAN\s0  **), right  associative

! \–          (unary) logical  and arithmetic negation

* /      multiplication,  division

+ \–          addition,  subtraction

&gt &gt=        relational  operators: greater,  greater or  equal,

&lt &lt=        less, less or  equal,

\&amp== =   equal, not  equal  (all same precedence)

&amp&amp                     logical AND  (both  operands  always  evaluated)

||     logical OR  (both  operands  always  evaluated)

\&amp=          assignment,  right associative

.TE

так створюється таблиця, представлена ​​нижче

Table 1: Operators, in decreasing order of precedence

^             exponentiation (FORTRAN **), right associative

! –           (unary) logical and arithmetic negation

* /      multiplication, division

+ –           addition, subtraction

&gt &gt=        relational operators: greater, greater or equal,

&lt &lt=           less, less or equal,

== =          equal, not  equal (all same precedence)

&amp&amp                     logical AND (both operands always evaluated)

||     logical OR (both operands always evaluated)

=              assignment, right associative

Слова перед крапкою з комою (center, box) описують глобальні властивості таблиці: горизонтально центрировать її на сторінці і намалювати рамку навколо неї Також можливі doublebox (подвійна рамка), allbox (сітка, кожен елемент в рамці) і expand (розтягнути по ширині сторінки)

Наступні рядки (до точки) описують формат частин таблиці, якими в даному випадку є рядок назви і тіло таблиці Перша специфікація відноситься до першої рядку таблиці, друга –

до другої, а остання застосовується до всіх залишилися рядках Для Table 1 є тільки два рядки специфікації, тому друга з них застосовується до всіх рядків таблиці, крім першої Форматування позначається наступними символами: c – для елементів, зосереджених в стовпці, r і l – для вирівнювання по правому і лівому краю відповідно і n – для числового вирівнювання по десятковій крапці Символ s задає «стягання» стовпців, в даному випадку «c s» означає, що треба центрувати назву щодо всієї таблиці, обєднавши другий і перший стовпці

Шрифт можна вказувати для стовпчика визначення lfCW виводить стовпець, вирівняний по лівому краю, шрифтом CW

За інформацією про формат слід власне текст таблиці Стовпці розділені символами табуляції Деякі команди troff, наприклад Sp, сприймаються і всередині таблиць (Зверніть увагу на використану двічі послідовність \ &: незахищені початкові знаки – і = в шпальтах повідомляють tbl, що в цьому місці слід провести лінії через таблицю)

Програма tbl створює безліч різних таблиць, що відрізняються від представленої в цьому простому прикладі: вона вставляє текст в рамки, вертикально вирівнює заголовки стовпців і т д Найпростіший спосіб використовувати цю програму для складних таблиць – пошукати схожий приклад в томі 2А довідкового керівництва по UNIX та адаптувати його до ситуації

Математичні вирази

Другий препроцесор troff – це програма eqn, перетворююча мова, що описує математичні вирази, в команди troff для виво так Вона автоматично обробляє зміни шрифту і розміру, а також надає назви стандартних математичних симво лов Вхідні дані eqn зазвичай знаходяться між рядками EQ і EN, аналогічно рядкам TS і TE програми tbl Наприклад,

.EQ

x sub  i

.EN

виводить xi Якщо використовується макропакет ms, то вираз виводиться як вимкнена формула, 1 при цьому необовязковий аргумент EQ вказує номер вираження Наприклад, формула інтеграла Коші

1 виключення, тобто набраними з розривом тексту У математичній літературі набирають зазвичай великі, складні математичні вирази, які через їх фізичного розміру незручно поміщати прямо в тексті Іноді вимкненим може виявитися і простий вислів, якщо йому надається важливе значення Такі вирази зазвичай нумерують по краю смуги набору – Прямуючи науч ред

f(ζ)  =

1&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp -∫ f(z) dz

(91)

——–

i

C

———–

z – ζ

записується як

.EQ  (91)

f( zeta   ) ~=~ 1  over  {2 pi  i}  int  from  C f(z) over  {z – zeta}  dz

.EN

Мова eqn грунтується на записі озвучування математичних виразів Відмінність вимовленого вголос математичного виразу від введення eqn полягає в тому, що фігурні дужки {} використовуються в eqn як круглі дужки – вони анулюють правила, що визначають пріоритетність за замовчуванням, а ось звичайні дужки не мають спеціального значення Зате у прогалин воно є Зверніть увагу на те,

що в прикладі, наведеному вище, перший ζ (дзета) оточена пробілу-

ми: справа в тому, що такі ключові слова, як zeta і over розпізнають-

ся, тільки якщо вони укладені в прогалини або фігурні дужки (при цьому ні прогалини, ні фігурні дужки у виведенні не присутні) Якщо потрібно, щоб у виведенні був пробіл, використовуйте символ тильди

~, Як у виразі ~ = ~ Фігурні дужки можна отримати за допомогою { і }.

Існує декілька класів ключових слів eqn Назви гречес ких букв записуються в нижньому або верхньому регістрі, наприклад

lambda і LAMBDA (λ і Λ) Іншим математичним символам дано назва-

ня, такі як sum (сума), int (інтеграл), infinity (нескінченність) і

grad (градієнт): Σ, ∫, ∞, ∇ Існують позиційні оператори, такі

як sub, sup, from, to і over:

i = 0

1

2&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp ——

записується як

sum from i=0  to  infinity  x sub  i sup  2 ~–&gt~ 1 over  {2  pi}

Є такі оператори, як sqrt і змінювані по висоті дужки і т д Також eqn вміє створювати стовпці і матриці обєктів Існують і команди для управління розмірами, шрифтами і позиціями, на той випадок, якщо встановлені за замовчуванням не підходять

Невеликі математичні вирази, такі як log10 (x), Часто поміщають прямо в текст, а не в вимкнену формулу У eqn є ключове слово delim, яке задає пару символів, що укладають Вира-

ються, що знаходиться усередині рядка, в дужки Зазвичай для правого і

лівого обмежувачів використовується один і той же символ, в більшості випадків це знак долара $ Але в hoc символ $ застосовується для ар-

аргументів, тому для прикладів цієї книги як обмежувача був обраний символ @ Підходить і%, але уникайте інших символів: справа в тому, що дуже багато з них мають спеціальне значення в величезній кількості програм, і при їх використанні поведінка програми може стати абсолютно незясовним (Автори зіткнулися з цим, коли писали цю главу)

Отже, після того як задано

.EQ

delim  @@

.EN

що знаходиться усередині рядка вираз, таке як Σ ∞, Може бути

виведено таким чином:

i = 0

in–line expression

таке як @ sum from i = 0 to infinity x sub i @ може бути виведено:

Цей прийом використовують для виведення математичних виразів всередині таблиці, так, наприклад, зроблено в документації по hoc:

.TS

center, box c s  s

lfCW  n l

\fBTable  3:\fP   Built–in  Constants

.sp  5

DEG

5729577951308232087680

180/  pi@,  degrees  per  radian

E

271828182845904523536

@e@,  base  of  natural  logarithms

GAMMA

057721566490153286060

@gamma@,  Euler–Mascheroni  constant

PHI

161803398874989484820

@(  sqrt  5  +1)/2@,  the  golden  ratio

PI

314159265358979323846

@pi@,  circular  transcendental  number

TE

Зовнішній вигляд вихідних даних представлений нижче Видно, як tbl вирівнює числовий стовпець по десятковій крапці

Table 3: Built-in Constants

DEG

5729577951308232087680

180/π, degrees per radian

E

271828182845904523536

e, base of natural logarithms

GAMMA

057721566490153286060

γ, Euler-Mascheroni constant

PHI

161803398874989484820

(   5 +1)/2, the golden ratio

PI

314159265358979323846

π, circular transcendental number

І останнє Оскільки eqn виводить курсивом будь-яку буквенную рядок, яку він не розпізнає, її прийнято використовувати для друку курсивом звичайних слів @ Слово @, наприклад, виводиться як Слово Але

будьте уважні: деякі загальновживані слова (такі як from і to) eqn розпізнає і обробляє їх спеціальним чином, до того ж вона знищує прогалини, так що цей прийом слід застосовувати з обережністю

Отримання вихідних даних

Підготувавши документ, треба організувати все препроцесори і саму програму troff так, щоб отримати вихідні дані Якщо застосовувалася тільки troff, введіть

$ troff-ms імена5файлов(Або-mm)

Якщо ж використовувався препроцесор, вкажіть імена файлів як аргументи для першої команди в конвеєрі, а інші команди мають отримувати дані зі свого стандартного введення, як в

$ eqn імена5файлов | troff-ms

або

$ tbl імена5файлов | eqn | troff-ms

Незручно весь час відстежувати, який з препроцесорів необхідний для виведення кожного конкретного документа Автори вирішили, що буде корисно написати програму (її назвали doctype), яка трасували б відповідну послідовність команд:

$ doctype  ch9*

cat  ch91  ch92  ch93  ch94  | pic  | tbl  | eqn | troff  –ms

$ doctype  hocms

cat  hocms | tbl | eqn | troff –ms

$

Програма doctype реалізована засобами, детально описаними в розділі 4 зокрема програма awk шукає послідовності команд препроцесорів і виводить командний рядок для виклику тих з них, які потрібні для форматування документа Вона також шукає команду PP (абзац) макропакет ms

$ cat  doctype

# Doctype: синтезує командний рядок для 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 &gt 0)  printf &quotrefer | &quot

if (pic &gt 0)      printf &quotpic  | &quot

if  (ideal  &gt  0)  printf  &quotideal  |  &quot if  (tbl &gt  0)      printf  &quottbl |  &quot

if  (eqn  &gt  0)      printf  &quoteqn  |  &quot printf  &quottroff  &quot

if  (ms  &gt  0)  printf  &quot–ms&quot printf  &quot\n&quot

}

$

(Параметр-h команди egrep викликає знищення заголовків з іменами файлів на кожному рядку) На жаль, цей параметр доступний не у всіх версіях системи Вхідні дані скануються, збирається інформація про те, які компоненти задіяні Після того як все введення переглянутий, він в належному порядку обробляється для підготовки до виведення Подробиці обробки визначаються препроцесорів, форматує troff-документи, користувачеві же залишається тільки перекласти роботу на машину, вона сама про все подбає

Програма doctype – це ще один приклад (вже була розглянута програма bundle) програми, що створює іншу програму Одне заме чание: користувачеві доводиться заново вводити рядок для оболонки в одному з вправ буде запропоновано виправити цю ситуацію

Коли справа доходить до виконання справжньої команди troff, памятайте, що поведінка troff визначається конкретною системою: у деяких випадках вона безпосередньо управляє складальної машиною, тоді як в інших системах програма виводить інформацію на пристрій стандартного виведення, а потім інша спеціальна програма посилає дані на складальну машину

Між іншим, перша версія представленої програми не використовувала ні egrep, ні sort awk сама переглядала всі вхідні дані Але з великими документами така програма працювала дуже повільно, тому для швидкості пошуку була додана egrep, а для позбавлення від повторень (дублікатів) – sort-u У разі типового документа витрати на створення двох додаткових процесів для «просіювання» даних менше, ніж на виконання awk для великого обсягу вхідних даних Щоб проілюструвати це твердження, прове дено порівняння між doctype і версією, яка використовує тільки awk в якості документа для обробки було вибрано вміст цієї глави (оригінал), що містить близько 52 000 символів:

$ time  awk … doctype  without egrep  ..’ ch9*

cat  ch91  ch92  ch93  ch94  |  pic  | tbl  | eqn | troff –ms real             310

user               89 sys                 28

$ time  doctype  ch9*

cat  ch91  ch92  ch93  ch94  | pic  | tbl  | eqn | troff  –ms

real

70

user

10

sys

$

23

Перевага версії з трьома процесами очевидно (Порівняння було проведено на машині, де працював всього один користувач, при великій завантаженості системи перевага версії, що містить eg-rep, було б ще наочніше) Зверніть увагу, що спочатку була створена проста працююча версія, а потім вже вона оптимізувалася

Вправа 92 Як форматувалася ця глава ~

Вправа 93Якщо в якості символу обмежувача в eqn використовується знак долара, як отримати цей символ у виведенні Підказка: досліджуйте лапки і зумовлені (зарезервовані) слова eqn ~

Вправа 94 Чому

$ `Doctype імена5файлов`

не працює Змініть doctype так, щоб отримана команда не виводилася, а виконувалася ~

Вправа 95Значні чи витрати на додаткову команду cat в doctype Перепишіть doctype так, щоб виключити додатковий процес Яка з версій простіше ~

Вправа 96Що краще: використовувати doctype або записати командний файл, що містить команди для форматування конкретного документа ~

Вправа 97 Експериментуйте з різними комбінаціями grep, egrep, fgrep, sed, awk і sort і створіть максимально швидку версію doctype ~

Джерело: Керниган Б, Пайк Р, UNIX Програмне оточення – Пер з англ – СПб: Символ-Плюс, 2003 – 416 с, Мул

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*