Hlavní navigace

TeX pro každého - TeX jako jazyk

21. 10. 2002
Doba čtení: 6 minut

Sdílet

Čím jiným bychom měli začít popis TeXového systému, nežli samotným TeXem. A protože čtenářům Roota není většinou programování cizí, začneme poněkud neobvykle – podíváme se na TeX jako na programovací jazyk.

TEXový začátečník si často vůbec neuvědomuje, že TEX je nejenom sázecí systém, ale i programovací ja­zyk.

Patří do kategorie makrojazyků a jedná se o velmi silný makrojazyk. Holý TEX tak, jak ho nabízí initex při svém startu, v sobě obsahuje interpretr makrojazyka a pak něco přes tři sta základních příkazů, zvaných primitiva. Primitiva jsou základní typografické příkazy, nástroje pro práci s vlastním makrojazykem a řídící příkazy.

To, co si nyní probereme, je tedy chování samotného TEXu, nikoliv jeho nadstaveb. Místy však pro jednoduchost výkladu předpokládám, že bylo provedeno i základní nastavení, použité v těchto nadstavbách.

Práce TEXu

Základní filozofií TEXu je výrazné oddělení části zpracovávající makra a části provádějící sazbu. Obrazně lze říci, že TEX nejdříve vstupní text „přežvýká“ (provede analýzu souboru a expanduje makra) a poté „spolkne“ (předá k typografickému zpracování).

Makrojazyk TEXu

Podobně jako u ostatních makrojazyků i činnost TEXu spočívá v postupném procházení souboru, zpracovávání definic maker a expanzi maker. TEX prochází soubor znak po znaku a interpretuje jejich význam.

Makra

Makra jsou základní programovací strukturou TEXu.

Ve standardním nastavení TEXu začínají makra znakem \ a jejich názvy končí před prvním nepísmenným znakem (názvy maker však obsahují vždy alespoň jeden znak). Zvláštní význam dále mají závorky { a } – ohraničují oblast platnosti lokálních definic, definici a argumenty makra, znak# – označuje číslo argumentu, % pro započetí komentáře a & – znak pro tabulátor. Existují ještě další speciální znaky (NUL a EOL) a znaky, které mají význam pro matematický režim, o němž se zmíníme později.

Expanze maker

Pokud TEX narazí na sekvenci začínající \, předpokládá, že jde o makro a snaží se jej expandovat, a to až do konečné podoby primitiv. Pokud se jedná o řídící primitivum, interpretuje jej.

Jedno primitivum slouží k definování maker – \def a další pro vzájemné přiřazování –\let. Do souboru test.tex si napíšeme:

% definice makra se dvěma parametry
\def\test#1#2{===#1***#2===}

% ukázka lokální a globální platnosti
% definice
\def\makro{bbbb}
{\def\makro{aaaa}
  \global\let\glmakro\makro
% a použití
  1) \makro
}
2) \makro\ 3) \glmakro

% prvním argument: "p"
% druhým argument: "a"
\test parametr

% prvním argument: "para"
% druhým argument: "metr"
\test {para}{metr}

\end

Pozorní čtenáři si ještě mohli všimnout dvou primitiv \  (lomítko a mezera – vysadí mezeru) a\end (ukončí práci).

Příkazem tex test si test zpracujeme a poté třeba pomocí xdvi test zobrazíme.

Uvidíme stránku s texty:

1) aaaa 2) bbbb 3) aaaa
===pa===rametr
===para
metr===

K čemu se taková expanze dá použít? Podívejme se do souboru plain.tex na jednu z nejjednodušších definic – vysazení úzké mezery:

\def\thinspace{\kern .16667em }

Složitější TEXová makra se mohou bez problémů expandovat i na tisíce primitiv.

Ve většině maker si vystačíme s takto jednoduchým schematem expanze, ale TEX má prostředky na ovlivnění pořadí expanze.

Je třeba také vědět, že existují režimy TEXu, kdy expanze probíhá trochu jinak (zápis do souboru).

Pro bystřejší čtenáře poznamenávám, že na obsahu makra vytvořeném pomocí \let se pozdější změny původního makra neprojeví, zatímco při expanzi makra se v ní obsažená makra expandují a vyhodnocují až při použití. Existuje však primitivum \edef, které provede nejdříve expanzi a teprve na výsledku expanze provede definici.

Mezery, řádkování a základní práce s textem

Ve standardně nastaveném TEXu se libovolný počet mezer srazí vždy na jedinou.

Znak konce řádku se převádí na mezeru. Dva znaky konce řádku za sebou vygenerují primitivum \par, které slouží pro přechod na nový odstavec.

Jinými slovy – text se píše s běžným řádkováním textových souborů a prázdný řádek znamená nový odstavec.

Mezery na začátku a konci odstavce se ignorují. Pro odstavcové zarážky a východové řádky se použije sázecí předpis, definovaný typografickými primitivy.

Objekty a programové konstrukce

TEX disponuje několika typy registrů – jsou to čítače (count), dimenze (dimen), výplňky(glue), registry symbolů (toks), registry boxů (box – grafických objektů). Každých z těchto registrů je k dispozici 256.

Existují primitiva, která umí sčítat (a odčítat), násobit a dělit čítače, dimenze a výplňky. Tím aritmetické schopnosti TEXu končí.

Podobně jednoduchá je i nabídka několika druhů větvení typu \ifporovnání výraz \else výraz \fi (porovnání různých typů objektů). TEX tedy neobsahuje žádné příkazy na smyčky. Přesto si s nimi poradí, jak ukazuje definice makra \loop:

\def\loop#1\repeat{\def\body{#1}\iterate}
\def\iterate{\body \let\next\iterate
  \else\let\next\relax\fi \next}

Kategorie znaků

Důležitou vlastností TEXu jsou kategorie znaků. Při spuštění TEXu má každý znak přidělenu svou kategorii, které určuje jeho chování.

TEX je jazyk variabilní, a proto existuje primitivum, které umožní tuto kategorii změnit – je jím \catcode (jeho parametrem je číslo, proto ve výpisu níže najdete před měněným znakem ještě `). Tím je možné změnit naprostou většinu předdefinovaných vlastností znaků (ve skutečnosti spíš nadefinování – výše uvedené základní nastavení provádí z větší části až základní soubor plain.tex, nikoliv TEX samotný).

Ukážeme si to na jednoduchém příkladu příkladu. Konstrukce {\bf text} je nadefinovaná k vyznačení tučného textu a {\it text} k vyznačení kurzívy. Po následující změně bude možné používat <b>text</b> a <i>text</i>.

% změníme kategorii znaku < na uvození makra
\catcode`\<=0

% Nadefinujeme makra <b resp. <i
% (jinak též \b resp. \i),
% ktera jsou povinně následována znakem >,
% jako začátek skupiny a změnu písma.
\def<b>{\begingroup\bf}
\def<i>{\begingroup\it}

% Nadefinujeme makro </ (jinak též \/ -
% což však zastíní jedno primitivum)
% jako makro s jedním argumentem,
% povinně následovaným znakem >.
% Makro argument zahodí a zavře skupinu
% (tedy ukončí platnost změny písma).
\def</#1>{\endgroup}

O poznání složitější a bezkonfliktní makra dokáží tímto způsobem přímo zpracovávat dokonce i XML a XSLT soubory!

Nyní už si můžeme prozradit, jak funguje vlastní analýza textu a hledání maker. Pokud po znaku „uvození makra“ následuje „písmeno“ (znak s kategorií písmeno), budou se načítat i následující „písmena“, dokud se nenarazí na první „nepísmeno“. Pokud je tento znak„mezera“, spolkne se (toto opatření je užitečné, aby nám v sazbě nevznikaly nechtěné mezery). Takto načtená sekvence písmen pak vytvoří tzv. symbol (token), tedy jméno makra.

Příklady: \line, \bf

Ukázka na spolknuté mezery:

Mějme \def\texta{pes} \def\textb{spí}

\texta \textb dá tentýž špatný výsledek jako \texta\textb – pesspí. Napravíme to pomocí \texta\ \textb nebo \texta\space\textb.

Pokud po znaku „uvození makra“ následuje „nepísmeno“, bude se jednat o makro s jednoznakovým názvem. V tomto případě se již případná následující „mezera“ nespolkne.

Příklady: \!, \%

Zvláštní kategorií je „aktivní znak“ – tvoří název makra sám o sobě. Objeví-li se tento znak kdekoliv v textu, vyvolá makro, které je pod jeho jménem definováno.

V případě definic maker se použije kategorie znaku, platná v době definice.

root_podpora

Jako příklad mimořádně divokého použití změn kategorie znaků jsem připravil ukázku nejkratší implementace Gaussova algoritmu pro výpočet data velikonoc. Vlastní kód i s výpisem výsledku se vejde do 326 bajtů! Ale nelekněte se, takhle se v TEXu běžně nepracuje.

V jediném článku (ba ani v celém seriálu) není možné postihnout všechny aspekty makrojazyka TEXu. Mým cílem proto bylo pouhé seznámení s jeho základními rysy. Příště se podíváme na jeho typografické schopnosti.

Byl pro vás článek přínosný?