Makrá #
Prostredie CircuitMacros je rozšírením programovacieho jazyka dpic určeného pre kreslenie diagramov a grafov (staršia verzia je označovaná ako gpic) pomocou súboru makier pre makroprocesor m4. Makrá môžeme považovať za malé programy alebo skripty, ktorými sú nahradzované ich mená pri ich použití v hlavnom programe. Pomocou rozšírenia jazyka dpic makrami je možné vytvárať elektrické zapojenia a schémy, zároveň je možné v nich používať aj grafické prvky jazyka dpic.
Makroprocesor m4
Makroprocesor je univerzálny program pre spracovanie makier široko využívaný v programátorskej praxi najmä pri jazykoch nižšej úrovne a assembleroch. Makrá nachádzajú uplatnenie v rôznych implementáciách aj v textových a tabulkových procesoroch. Makroprocesor kopíruje vstupný text zo vstupu na výstup a popritom prí nájdení mena vopred definovaného makra
nahrádza meno makra textom z definície makra
nahrádza parametre makra ich hodnotami
vkladá súbory
prevádza manipulácie s textovými reťazcami
vyhodnocuje podmienky
vyhodnocuje aritmetické výrazy
Referenčnou implementáciou makroprocesora m4 je GNU M4.
Makrá definované v knižniciach CircuitMacros expandujú značky elektronických prvkov do množiny príkazov jazyka dpic, z vytvoreného programu je pomocou interpreteru príkazov vygenerovaný výsledný obrázok vo zvolenom rastrovom alebo vektorovom formáte.
Obr. 55 Postup generovania obrázkov.#
Warning
Kódy makier sú v podstate pomenované textové reťazce, ktorými nahrádza makrorocesor pred samotným spracovaním zdrojového kódu všetky časti zdrojového kódu zhodné s menom makra. Táto substitúcia je čisto mechanická, bez ohľadu na kontext v ktorom sa text zhodný s menom makra vyskytuje. Toto môže spôsobiť pri interpretácii kódu chybu, ktorá je spôsobená substitúciou makra na nevhodnom mieste a to aj napriek tomu, že kód programu je formálne syntakticky správny.
R1: resistor;
"terminal resistor" at R1.c above; # chyba, substitucia v texte
Pre odstránenie tejto chyby je potrebné vhodným spôsobom pozmeniť text tak, aby makroprocesor text nenahrádzal, napríklad
"terminal res\\istor" at R1.c above; # dve lomítka \\ sú pri zobrazení ignorované
Inou možnosťou je vložiť konfliktný text do úvodzoviek makra m4, ktoré makroprocesor ignoruje
"terminal `resistor' " at R1.c above; # `text' je ignorovaný
Použitie makier #
Makrá sa definujú podľa syntaxe makroprocesora m4. Všeobecný tvar makra je
define (name, [expansion])
Reťazec name je nahradený reťazcom expansion, typ úvodzoviek v makre je dôležitý. Príklad vytvorenia makra a jeho použitia
define(`foo', `Hello world.')
Obr. 56 Vytvorenie a použitie makra.#
Makro môže mať argumenty, tieto sú označované ako $1, $2 … , špeciálny význam má argument označený ako $0, ktorý obsahuje meno makra. Príklady použitia jednoduchých makier s argumentami
define(`exr', `$2, $1') # zamena poradia argumentov
exr(abc, 123) # --> 123, abc
define(`exc', `$1.y, $1.x') # vymena zložiek súradnice
P: (3,1)
sprintf("(%2.0f, %2.0f)", exc(P)) # --> (1,3)
Vytvorenie makra #
Pri tvorbe makier pre kreslenie vlastných prvkov zapojenia môžeme využiť nasledujúci vzor, v ktorom sú v makre vyhodnotené dva parametre. Ako substitučný reťazec použijeme kód uzatvorený v bloku [...], čo nám umožní reprezentovať makro ako zložený objekt a v makre pre kreslenie používať absolútne súradnice.
#----------------------------------------------
# vzor(n, c) - template pre makro
# n - numericky parameter
# c - znakovy parameter L|R|U|P
#----------------------------------------------
define(`vzor',`[
# kontrola existencie numerickeho parametra
# pri chybajucom parametri nahradenie default hodnotou
ifelse(defn(`par1'), $1, par1=1, par1=$1)
# vyber indexu 0...3 z preddefinovanej množiny parametrov L R U P
# pri neexistujucej ma index hodnotu -1
par2 = index(`LRUD', $2)
# vyhodnotenie pre hodnoty parametra podla hodnoty indexu
if par2 <= 0 then { line -> left_ par1; }
if par2 == 1 then { line -> right_ par1; }
if par2 == 2 then { line -> up_ par1; }
if par2 == 3 then { line -> down_ par1; }
]')
Makro defn() v predlohe vytvorí premennú par1 a skontroluje existenciu argumentu $1, ak tento neexistuje, ifelse priradí par1=1, ak existuje, tak potom jej priradí hodnotu par1=$1. Premenná par2 je inicializovaná hodnotou indexu z poľa dovolených parametrov. Makro pri použití pokrýva nasledujúce prípady
vzor; -> vzor(1,L)
vzor(); -> vzor(1,L)
vzor(2); -> vzor(2,L)
vzor(3,R); -> vzor(3,R)
vzor(,X); -> vzor(1,L)
vzor(,); -> vzor(1,L)
Nižšie je uvedené makro pre zobrazenie spínača s parametrami dĺžka spínača a ‘stav (ON, OFF) spínača. Aby bol komponent presne umiestnený v mriežke bez ohľadu na jeho aktuálne grafické zobrazenie, je vhodné ho umiestniť do neviditeľného boxu s fixnými rozmermi. Pre vonkajší box potom platia štandardné atribúty w,e,s,n,nw ….
Implementácie makra #
Nasledujúci príklad implementuje zobrazenie spínača s dvoma parametrami - dĺžka spínača a stavu zopnutia (ON, OFF) spínača. Aby bol komponent presne umiestnený v mriežke bez ohľadu na jeho aktuálne grafické zobrazenie, je vhodné ho umiestniť do neviditeľného boxu s fixnými rozmermi. Pre vonkajší box potom platia štandardné atribúty w,e,s,n,nw ….
Pre ilustráciu je zobrazený vonkajší box, ktorý umožňuje ukladanie komponentu v rastri, parameter invis spôsobi skrytie obrysu.
# horizontal switch
# usage:
# swh(length, ON | OFF );
define(`swh',`[
B: box ht 1 wid $1 dotted 0.04 #invis; # vonkajsi okraj pola 1. parametra
rr = 0.15;
p = 1.5;
C1: circle diameter rr at B.c + (rr/2 - p/4, 0)
C2: circle diameter rr at B.c + (-rr/2 + p/4, 0) fill 0;
line from C1.w to B.w
line from C2.e to B.e
ifinstr($2,OFF, # kontrola hodnoty 2. parametra
{ # stav OFF
line from C2.c to C1.c + (0, p/4)
},
{ # stav ON
line from C2.c to C1.c
}
);
]')
Vytvorené makro požívame ako akýkoľvek iný príkaz pre kreslenie prvkov zapojenia. Príklad použitia implmentovaného spínača je v nasledujúcom kóde, pre názornosť je ponechané zobrazenie vonkajšieho obrysu prvku.
move to (0.5, 2); right_;
swh(1, OFF);
line 0.5;
swh(1, ON);
line 0.5;
swh(2, OFF);
dot;
{ line up_ 1; right_; S1: swh(2, ON); "$S_1$" at S1.n; }
{ line down_ 1; right_; S2: swh(2, OFF); "$S_2$" at S2.n; }
Obr. 57 Implementácia makra pre zobrazenie spínača a jeho použitie#
Konflikt mien
Používanie makrier spoločne s interpreterom môže byť niekedy zdrojom chýb. Problémom môže byť hlavne to, že o chybe spôsobenej nesprávnym použitím makie sa dozvieme až pri interpretácii kódu s expandovanými makrami, pričom sa zvyčajne nedozvieme, z ktorého makra a na ktorom riadku zdrojového kódu k chybe došlo.
Niektoré makrá definujú premenné a konštanty, ktoré môžu byť príčinou konfliktov. Napríklad makro setrgb() používa premenné r_ , g_, b_, kde prvá premenná vytvorí konflikt s menom, ak potrebujeme napríklad označiť rezistor pomocou syntaxe v LaTex-u napr. r_1. V takomto prípade je potrebné v reťazci pre LaTeX použiť formálne prerušenie reťazca r\_1.
Nie je možné priamo v zobrazovanom texte použiť mená makrier, napríklad “toto je resistor R1”, pretože pri substitúcii dôjde k nahradeniu textu resistor kódom definovanom v makre a následnej chybe pri interpretácii zdrojového kódu. Text musíme upraviť podobne ako v predchádzajúcom prípade.
Modifikácia makra #
V niektorých prípadoch nepotrebujeme vytvárať nové makro, ale len rozšíriť existujúce makro o ďalši popis alebo grafiku. V niektoých zapojeniach napríklad je značka rezistora doplnená o označenie jeho výkonovej straty, ktorá môže súvisieť s jeho typom púzdra.
define(`res_025w', `[
R: resistor($1,$2,$3);
dx = 0.065*linewid;
line from R.c+(dx,-dx) to R.c+(-dx,dx);
]')