Hlavní navigace

Makro procesor GNU m4 (8)

12. 11. 2001
Doba čtení: 4 minuty

Sdílet

V dnešním dílu se naučíme vkládat soubory, pracovat s komentáři, zacvičit s uvozovkami a taky odstranit nežádoucí zařádkování při definicích maker.

m4 poznámky

V textu zpracovávaném procesorem m4 se mohou vyskytnout posloupnosti znaků, se kterými m4 zachází speciálně. Konkrétně mám na mysli token poznámka, což je jakýkoliv řetězec ohraničený znakem # a novým řádkem. Název poznámka plně nevystihuje to, co se s takovým textem dělá. Nicméně v manuálech jej takto nazývají, proto já sám nebudu vymýšlet nové názvy. Všechno mezi hraničním znakem # a odřádkováním (včetně) je procesorem ignorováno, ale celá poznámka včetně oddělovačů je poslána na výstup.

Poznámky nemohou být vnořovány, tedy první výskyt konce řádku poznámku ukončí. Chcete-li na výstup dostat znak # bez toho, aby jej m4 pochopil jako začátek poznámky, vložte ho do uvozovek:

   define(`makro', `ahoj')
=>
   toto je poznámka: # makro makro makro
=> toto je poznámka: # makro makro makro
   ale tohle ne: `#' makro makro makro
=> ale tohle ne: # ahoj ahoj ahoj

Příjemné je, že znaky určující počátek a konec poznámek mohou být změněny použitím vestavěného makra changecom:

changecom([počátek][, konec])

Při psaní HTML stránek se mi osvědčilo nastavení hranic poznámek na tagy <pre> a </pre>:

   changecom(`<pre>', `</pre>')
=>
   Nové makro se definuje takto:
=> Nové makro se definuje takto:
   <pre>
=> <pre>
   define(`makro', `ahoj světe')
=> define(`makro', `ahoj světe')
   </pre>
=> </pre>

Pokud v makru changecom neuvedete ukončovací sekvenci, použije se standardně konec řádku. Volání changecom bez parametrů zapříčiní úplné potlačení rozpoznávání poznámek.

Vynechávání konce řádku

V m4 existuje ještě jedna konstrukce, která se zpracovává nestandardním způsobem. Je to makro

dnl

Expanze makra dnl způsobí, že všechny následující znaky až do konce řádku (včetně znaku nového řádku) budou vypuštěny. V podobě makra dnl získáváte další způsob, jak psát do zdrojového textu m4 skutečné poznámky. dnl se také často používá právě pro potlačení znaku nového řádku.

   ahoj, dnl pozdrav
   jak se máš?
=> ahoj, jak se máš?

Volání makra dnl s argumenty popudí m4 natolik, že vydá varovnou hlášku, všechny parametry přečte, ale neudělá s nimi nic a klasicky vynechá vše až do konce řádku:

   tohle se nemá: dnl(arg1, arg2) tohle se vynechá
   ...pokračování prvního řádku
=> tohle se nemá: ...pokračování prvního řádku
E> stdin:1: m4: Warning: Excess arguments to built-in `dnl' ignored

Změna typu uvozovek

Pokud vám z jakéhokoliv důvodu nevyhovují jako uvozovky jednoduché anglické uvozovky „`“ a „'“, můžete si pomocí vestavěného makra changequote jako uvozovací znaky zvolit něco jiného:

changequote([levá uvozovka][, pravá uvozovka])

Vynecháte-li v makru changequote jakýkoliv argument, použijí se na jeho místě standardní uvozovky „`“ a „'“. Volání changequote bez parametrů proto obnoví původní nastavení.

   changequote([, ])
=>
   define([makro], [ahoj])
=>
   `makro' [makro]
=> `ahoj' makro
   changequote
=>
   `makro' [makro]
=> makro [ahoj]

Uvozovací řetězce mohou být i víceznakové:

   changequote(\[, \])
=>
   define(\[makro\], \[ahoj\])
=>
   `makro' \[makro\]
=> `ahoj' makro

Jediné omezení, které se na uvozovací řetězce klade, je, že nesmí začínat písmenem nebo znakem podtržítka (_), protože by se pletly s názvy maker. Pokud tak přesto učiníte, mechanizmus uvozování si zablokujete.

Trochu divoce působí třeba následující „uvozovky“:

   changequote(\lq, \rq)
=>
   define(\lqmakro\rq, \lqahoj\rq)
=>
   `makro' \lqmakro\rq
=> `ahoj' makro

S uvozováním jsou v m4 velké problémy. Dovolil bych si tvrdit, že to je nejslabší místo celého systému. Například jediný způsob, jak uvodit řetězec obsahující samotnou levou uvozovku, je použít makro changequote.

Makro changequote přiřadí nějakým znakům význam uvozovek. Problém ale nastane, pokud changequote použijete až po definici nějakých složitějších maker, ve kterých používáte jiný pár uvozovek. Zavoláním těchto maker začnete rázem dostávat zmatené výstupy a chybová hlášení.

Definice makra je v paměti uložena jako text. Makro procesor neví nic o tom, že na některých místech používáte uvozovky. Význam makra se interpretuje až v okamžiku jeho použití, tzn. že když jste při vytváření makra počítali s uvozovkami ve tvaru `' a pak za uvozovky prohlásíte třeba [], se všemi výskyty jednoduchých anglických uvozovek (narozdíl od hranatých závorek) se začne zacházet jako s obyčejnými znaky…

Vkládání souborů

Ve zdrojovém souboru m4 máte možnost procesor požádat, aby v určitém okamžiku zpracoval nějaký další soubor. Dělá se to vestavěnými makry:

include(název souboru)
sinclude(název souboru)

Oba makra způsobí, že m4 začne číst soubor, jehož název jste uvedli v parametru. Po skončení se procesor vrátí zpět ke zpracovávání původního vstupu.

Rozdíl mezi uvedenými dvěma makry je v tom, že include při neexistenci souboru zahlásí chybu, kdežto sinclude jednoduše expanduje na prázdný řetězec:

   include(`nic.txt')
=>
E> stdin:1: m4: Cannot open nic.txt: No such file or directory
   sinclude(`nic.txt')
=>

Čtení souboru pochopitelně podléhá expanzi maker. Předpokládejme, že máme soubor incl.m4 s tímto obsahem:

Začátek souboru
makro
Konec souboru

Použijeme include…:

   define(`makro', `ahoj')
=>
   include(`incl.m4')
=> Začátek souboru
   ahoj
   Konec souboru

Výhodné je umístit do zvláštních souborů definice maker nebo společné části (např. hlavičky) a tento soubor ve všech zdrojích jenom includovat. (Později se dovíme, že „knihovny“ maker lze do m4 nahrávat efektivněji.)

Kde se vkládané soubory hledají

Zavoláte-li jedno z maker pro vložení souboru a název souboru není absolutní (tedy i s cestou), makro procesor m4 se nejprve podívá do aktuálního adresáře. Jestliže tam soubor nenajde, projde adresáře specifikované pomocí volby -I makro procesoru. Pokud ani tam neuspěje, začne prohledávat adresáře určené proměnnou prostředí M4PATH. Tato proměnná by měla obsahovat dvojtečkou oddělovaný seznam adresářů (podobně jako PATH). Selže-li i tato možnost, v případě makra include se zahlásí chyba.

Pokračování příště.

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.