> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/fi/syvalliset-artikkelit/09-an-introduction-to-luatex-part-2-understanding-directlua.md).

# Johdanto LuaTeXiin (osa 2): \directlua:n ymmärtäminen

## Tämän artikkelin tavoitteena on

Tämän artikkelin ensimmäisessä osassa, [Johdatus LuaTeXiin (osa 1): Mikä se on — ja mikä tekee siitä niin erilaisen?](/latex/fi/syvalliset-artikkelit/07-an-introduction-to-luatex-part-1-what-is-it-and-what-makes-it-so-different.md), tarkastelimme lyhyesti LuaTeXia äärimmäisen monipuolisena TeX-moottorina: kehittyneenä, ohjelmoitavana ladontajärjestelmänä, joka tarjoaa laajan valikoiman työkaluja dokumenttien suunnittelu- ja tuotantoratkaisujen rakentamiseen.

Tässä päätösosassa tarkastelemme läheltä LuaTeX-työkalupakin tärkeintä osaa: `\directlua` komentoa, joka tarjoaa “portin” LuaTeXin ladonnan ohjelmalliseen hallintaan Lua-skriptauskielen avulla.

Kuitenkin LuaTeXin täysimääräinen hyödyntäminen käyttäen `\directlua` edellyttää taustatietoja useista TeX-aiheista: TeXin tokeneista, token-listoista ja laajennusmekanismista. Tämän artikkelin tavoitteena on tarkastella ja selittää näitä TeXin peruskäsitteitä: koota yhteen TeXiin liittyvät prosessit, jotka ovat `\directlua` takana, jotta ymmärtäisit, miten se toimii, ja jotta saisit perustan, jonka varaan voit rakentaa omat ladontaratkaisusi LuaTeXin avulla.

Tämä artikkeli sisältää lukuisia lyhyitä esimerkkejä, joiden avulla havainnollistetaan ja selitetään `\directlua`sen toimintaa koskevia keskeisiä näkökohtia, vältellen tarkoituksella liian monimutkaista koodia lyhyiden koodifragmenttien hyväksi. Tarvittaessa esimerkit käyttävät perus- (raaka-/plain-) TeXiä — vaikka useimmat käyttävät ja suosivat LaTeXia (makroja), perus-TeX-komentojen etuna on yksinkertaisuus.

## Johdatus Luaan LuaTeXissä

[Lua](https://www.lua.org/about.html) on skriptauskieli, jonka [lähdekoodi](https://www.lua.org/download.html) on erittäin siirrettävää ja helppo upottaa ohjelmistosovelluksiin, minkä ansiosta kehittäjät voivat sisällyttää ohjelmiinsa skriptitoiminnallisuuksia. Lua on upotettu [moniin sovelluksiin](https://en.wikipedia.org/wiki/List_of_applications_using_Lua) ja se on suosittu valinta ohjelmistopelialalla — ehkä tunnetuin esimerkki on [World of Warcraft](https://wowwiki.fandom.com/wiki/Lua_functions).

LuaTeX, kuten nimikin vihjaa, on TeX-moottori, joka upottaa Lua-skriptauskielen ja antaa käyttäjille mahdollisuuden hallita LuaTeXin ladonnan toimintaa sisällyttämällä Lua-ohjelmia (skriptejä) asiakirjoihinsa. LuaTeXin suoran hallinnan lisäksi käyttäjät voivat hyödyntää Luaa puhtaasti erittäin tehokkaana ohjelmointikielenä sellaisten tehtävien suorittamiseen, joita voi olla äärimmäisen vaikea toteuttaa TeX-kielellä — joka on rehellisesti sanottuna haastava oppia ja hallita. Luan lisäämisen ja integroinnin myötä LuaTeXistä tulee hyvin monipuolinen ja tehokas TeX-moottori, joka tukee suoraan kahta ohjelmointikieltä.

### Luan ja TeXin käyttäminen asiakirjassasi: syötä \directlua

Lua ja TeX ovat kaksi *hyvin erilaista* ohjelmointikieltä: Lua muistuttaa paljon enemmän sitä, mitä useimmat pitävät ohjelmointikielenä, mutta TeX kategoriakoodeineen, tokeneineen, makroineen ja laajennusmekanismeineen on kaukana useimpien ihmisten kokemuksesta/odotuksista kielestä, jolla ohjelmia kirjoitetaan. Kuitenkin historia on osoittanut, että TeX-kieli on säilynyt, koska se on hyvä siinä, mihin se on suunniteltu: ladonnan hallinnassa, vaikka sen toimintatapa onkin jokseenkin arvoituksellinen.

Haasteeseen, joka liittyy Luan ja TeXin kielten sekoittamiseen yhteen TeX-asiakirjaan, LuaTeXin kehittäjät esittelivät uuden komennon nimeltä `\directlua` joka on reitti Luan käyttämiseen — sekä itsenäisenä ohjelmointikielenä että LuaTeXin ladonnan toimintatavan hallintaan.

Se `\directlua` komennon avulla käyttäjät voivat upottaa Lua-koodia TeX-asiakirjoihinsa; kyseinen koodi välitetään sittemmin LuaTeXin sisäänrakennetulle Lua-kielen tulkille. Kuitenkin, `\directlua` myös antaa sinun *yhdistää* Lua- ja (La)TeX-koodin samaan `\directlua` komentoon — vaikka tämä tuo mukanaan lisämonimutkaisuutta Lua- ja TeX-pohjaisten ohjelmointikielten perustavanlaatuisten erojen vuoksi. Keskeinen haaste (La)TeX- ja Lua-koodia yhdistettäessä on varmistaa, että nämä kaksi kieltä elävät sovussa eivätkä “tule toistensa tielle”.

`\directlua` soveltuu parhaiten lyhyiden asiakirjan sisäisten Lua-koodifragmenttien käyttöön, mutta voit halutessasi käyttää sitä myös laajempien Lua-ohjelmien kanssa. Yleensä laajemmat Lua-ohjelmat ja Lua-koodikirjastot tallennetaan ulkoisiin tiedostoihin, jotka voidaan ladata käyttämällä Luan `dofile()` funktiota `\directlua` komennon sisällä. TeX-prosessoinnin näkökulmasta merkittävä etu ulkoisten Lua-kooditiedostojen käytössä on TeXin kategoriakoodimekanismista aiheutuvien monimutkaisuuksien välttäminen — aihe, jota tässä artikkelissa tarkastellaan perusteellisesti.

### Muodollisempi kuvaus \directlua-komennosta

Se [LuaTeX-viiteopas](http://www.pragma-ade.com/general/manuals/luatex.pdf) kuvaa `\directlua` seuraavasti (hieman muokattuna):

> Jotta Lua-koodi voitaisiin yhdistää TeX-syötteeseen, tarvitaan muutamia uusia primitiivejä. Primitiivi `\directlua` sitä käytetään Lua-koodin suorittamiseen välittömästi. Perussyntaksi on `\directlua{⟨koodi⟩}`. Se `⟨koodi⟩` laajennetaan täysin ja syötetään sitten Lua-tulkille. Kun lukeminen ja laajennus on suoritettu `⟨koodi⟩`, tuloksena oleva token-lista muunnetaan merkkijonoksi ikään kuin se näytettäisiin käyttämällä `\the\toks`.

Tämä on tietysti teknisesti tarkka kuvaus, mutta ehkä ei kovin helppo ymmärtää ilman tietoa TeXin alemman tason prosesseista — kuten tokeneista ja laajennuksesta.

## \directlua:n ymmärtäminen: mitä aiheita käsittelemme?

Tässä artikkelissa tarkastelemme lähempää joitakin keskeisiä taustateemoja ja tarjoamme useita esimerkkejä, joiden tarkoituksena on havainnollistaa, miten `\directlua` toimii ja missä (tai miksi) sinun on oltava varovainen yhdistäessäsi TeXin ja Luan omassa `⟨koodi⟩`.

Tutkimme seuraavat aiheet riittävän yksityiskohtaisesti, jotta saamme perustan ymmärtää `\directlua` ja sen koodin “esikäsittelyä”, jota käytät siinä:

* kategoriakoodit ja TeX-tokenit: tekstin muuntaminen tokeneiksi ja tokenien muuntaminen tekstiksi;
* TeXin laajennusprosessi (ja laajennuksen estäminen);
* Luan pakomerkintäjärjestelmät/ -mekanismit merkeille ja merkkijonoille;
* Lua-tyylisen kommentoinnin käyttäminen;
* Lyhyt johdatus LuaTeXin Lua-API:in.

Jos ymmärrät, miten TeX-moottorit luovat ja käyttävät tokeneita sekä kehität käsityksen TeXin laajennusmekanismista, sinulla on perustat, joita tarvitaan LuaTeXin `\directlua` komento.

## Perustat: tekstistä tokeneiksi ja tokeneista tekstiksi

Overleaf on julkaissut useita artikkeleita, joissa tarkastellaan perusteellisesti TeX-tokeneita ja niihin liittyviä käsitteitä, joten emme toista kaikkea sitä aineistoa tässä; sen sijaan hahmottelemme niitä alueita/aiheita, jotka ovat olennaisia paremman ymmärryksen kehittämiseksi `\directlua`.

Tässä on luettelo aiemmin julkaistuista artikkeleista, joista saattaa olla hyötyä:

* [Mikä on TeX-token?](/latex/fi/syvalliset-artikkelit/53-what-is-a-tex-token.md)
* [Mikä on TeX-tokenlista?](/latex/fi/syvalliset-artikkelit/54-what-is-a-tex-token-list.md)
* [Miten \expandafter toimii: Johdatus TeX-tokeneihin](/latex/fi/syvalliset-artikkelit/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md)
* [Kuusiosainen sarja: Miten TeX-makrot oikeastaan toimivat?](/latex/fi/lisaa-aiheita/01-a-six-part-series-how-do-tex-macros-actually-work.md)

### Merkkitokenien ymmärtäminen

Jokainen merkki, jonka TeX-moottori voi lukea tekstitiedostosta, esitetään kahdella numeerisella arvolla:

* sen *merkkikoodi* (ASCII-arvo tai nykyään sen Unicode-koodipiste);
* toinen, TeX-keskeinen, arvo nimeltä sen *kategoriakoodi*.

Lukijat, jotka haluavat tietää lisää kategoriakoodeista, saattavat olla kiinnostuneita lukemaan tämän Overleafin julkaiseman johdannon: [Mistä siis aloitamme? Kategoriakoodeista](/latex/fi/lisaa-aiheita/19-how-tex-macros-actually-work-part-1.md#so2c-where-do-we-start3f-with-category-codes).

Esimerkiksi, jos TeX-moottori lukee merkkiä `Yksi` sillä on käytössään kaksi tietoa: `Yksi`merkkikoodi (65) ja kategoriakoodi (yleensä 11). Kun TeX on vastaanottanut tuon merkin `Yksi`, sen kategoriakoodi ei muutu, mutta käyttäjän makrot voivat tehdä kategoriakoodiin muutoksia, jotka saattavat vaikuttaa mihin tahansa *myöhempään* merkkiä `Yksi` jota *ei ole vielä luettu* TeXissä. Siksi TeXin on kirjattava, että *tämä* merkkiä `Yksi`, *juuri luettu*, kategoriakoodi on 11. TeX käyttää tätä varten kokonaislukuparia (65,11) laskeakseen toisen kokonaislukuarvon, jota se kutsuu *merkkitokeniksi*Raja on `Yksi` ja sen kategoriakoodi ovat *sidoksissa toisiinsa*; käytännössä tuo merkkitoken *sisältää* ne tiedot, jotka TeXin on tiedettävä kyseisestä merkistä käytettäväksi kaikessa myöhemmässä ladontatoiminnassa syvemmällä TeX-moottorin sisällä.

#### Miten merkkitokenit lasketaan?

Ensinnäkin meidän on muistettava, että TeX-moottorit käyttävät kategoriakoodia 13 niin sanottujen *aktiivimerkkien*: luomisessa: jokainen merkki, jolla on kategoriakoodi 13, käyttäytyy kuin pienoismakro; siksi, kuten alla näemme, aktiivimerkkien tokenit lasketaan eri tavalla kuin tavallisten merkkien, joilla on muita kategoriakoodeja kuten 10, 11 tai 12.

Tiedostoissa *ei-aktiiviset* merkit:

* vanhemmat 8-bittiset moottorit (Knuthin TeX, e-TeX, pdfTeX) laskevat merkkitokenit *ei-aktiiviset* merkeille käyttäen

$$\text{(non-active) character token} = (256 \times \text{category code}) + (\text{ASCII character code})$$

* LuaTeXin kohdalla, jonka on käsiteltävä Unicode-merkkien arvoja, laskenta *ei-aktiiviset* merkeille on samankaltainen, mutta tuottaa paljon suurempia kokonaislukuarvoja:

$$\text{(non-active) character token} = (2^{21} \times \text{category code}) + (\text{Unicode value})$$

Palatakseni aiempaan esimerkkiimme kirjaimesta A kategoriakoodilla 11, LuaTeX laskisi merkkitokenin arvoksi $$2^{21} \times 11 + 65 = 23068737$$. Kun tuo merkkitokenin arvo on laskettu, *sitoo* juuri tämän A-kirjaimen kategoriakoodiarvoon 11. Käyttäjän makrot voivat muuttaa minkä tahansa seuraavan A-kirjaimen kategoriakoodia, mutta tämän yhden kategoriakoodi on vakiinnutettu muuntamalla se tokeniksi käytettäväksi sen kulkiessa LuaTeXin sisäisten toimintojen läpi. LuaTeX on säilyttänyt eli kapseloinut tuon merkin aiotun merkityksen sellaisena kuin se määrittyi sitä luettaessa.

TeX-moottorit käyttävät yhteensä [16 eri kategoriakoodia](/latex/fi/lisaa-aiheita/43-table-of-tex-category-codes.md) ja *kaikkia* näistä kategoriakoodeista voidaan antaa, `\catcode` komennon avulla *kaikkia* mille tahansa merkille, jonka TeX-moottori pystyy lukemaan. Kategoriakoodien muutoksia käytetään muuttamaan tapaa, jolla TeX-moottorit käsittelevät tiettyjä syötteen merkkejä, mikä mahdollistaa sen, että TeX-käyttäjät voivat kirjoittaa makroja, jotka tuottavat erityisiä ladontatuloksia tai käyttäytymistä.

**Aktiivimerkit**

Kuten todettu, TeX-moottorit käyttävät kategoriakoodia 13 liittääkseen merkkiin “erityisen merkityksen”, jolloin siitä tulee niin kutsuttu *aktiivimerkki* joka käyttäytyy kuin pienoismakro: eteen ei tarvita `\` , vaan irrallinen merkki riittää kategoriakoodinsa vuoksi käynnistämään makromaisen käyttäytymisensä.

Koska aktiivimerkki toimii pienoismakrona, sitä ei muunneta *merkkitokeniksi* merkkitokeniksi *vaan toiseksi (kokonaisluku-)tokenityypiksi nimeltä*komentotoken. Nämä lasketaan seuraavasti:

* vanhemmissa 8-bittisissä moottoreissa (Knuthin TeX, e-TeX, pdfTeX) aktiivimerkkien tokenit lasketaan seuraavasti:

1. laske väliarvo nimeltä $$\text{curcs}$$ (**nyky**inen **c**ohjaus **jono**) jossa $$\text{curcs} = \text{character code} + 1$$3. laske tokenin arvo, jossa $$\text{active character token} = \text{curcs} + \text{4095}$$

* LuaTeXissa laskenta on hieman monimutkaisempi, koska sen on käsiteltävä koko Unicode-merkkien kirjo, joista mikä tahansa voidaan aktivoida:

1. laske väliarvo $$\text{curcs}$$ soveltamalla niin sanottua *hajautusfunktiota* aktiivimerkin Unicode-koodipistearvoon UTF-8-muodossa: $$\text{curcs}=\texttt{hashfunction}\text{(UTF-8 text for Unicode value of active character)}$$3. laske kokonaislukutokenin arvo: $$\text{active character token} = \text{curcs} + 2^{29} - 1$$

**Esimerkkejä**

* 8-bittiset moottorit: tokenin laskenta aktiivimerkille `~` (merkkikoodi 126) tuottaa $$\text{curcs} = 126 + 1 = 127$$, jolloin tokenin arvoksi saadaan $$4095 + 127 = 4222$$.
* LuaTeX: tokenin laskenta aktiivimerkille `~` tuottaa $$\text{curcs}=3186$$ jolloin tokenin arvoksi saadaan $$3186 + 2^{29} - 1 = 536874097$$LuaTeXin tokenit käyttävät paljon suurempia kokonaislukuarvoja!

### Komentotokenien ymmärtäminen

Käsiteltävien *yksittäisten* merkkien lisäksi TeX-moottorit voivat tietenkin käsitellä *merkkijonoja* jotka kutsutaan *komennot* (tai tarkemmin, *ohjausjonoiksi*). Perinteen mukaan `\` merkkiä käytetään komennon alun merkkinä, mutta se on vain käytäntö—itse asiassa mikä tahansa merkki, jonka kategoriakoodi on 0 (escape-merkki), voisi toimia sen sijaan.

TeX-moottorit tunnistavat kahdenlaisia komentoja, jotka tunnetaan nimillä *ohjaussanat* ja *ohjaussymbolit*:

* **ohjaussanat**: komennot, jotka on muodostettu yhdestä tai useammasta merkistä, joiden kategoriakoodi on 11;
* **ohjaussymbolit**: yksimerkkiset komennot, joissa kyseisen merkin kategoriakoodi *ei* 11: esimerkiksi `\$`, `\#` tai `\\`.

**Huomaa**: TeXin primitiivit `\chardef`, `\mathchardef`, `\countdef`, `\dimendef`, `\skipdef`, `\muskipdef` ja `\toksdef` käytetään myös ohjausjonojen määrittämiseen, mutta toisin kuin tavallisissa makromääritelmissä, tuloksena olevat ohjausjonot (ohjaussanat tai ohjaussymbolit) *eivät ole laajennettavia*—tutkimme näitä tarkemmin alla.

#### Miten komentotokenit lasketaan?

Aivan kuten aktiivimerkit, TeX-moottorit käyttävät toista kokonaislukutokenin tyyppiä edustamaan komentoja: *komentotokenit*—muistathan, että aktiivimerkitkin tuottavat komentotokeneita, koska ne käyttäytyvät kuin pienoismakrot.

8-bittisten moottoreiden komentotokenien luomiseen käyttämät laskelmat löytyvät tästä [Overleafin artikkelista](/latex/fi/syvalliset-artikkelit/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md#how-tex-calculates-token-values). Tässä tiivistämme komentotokenien laskennan keskeiset vaiheet LuaTeXissä — jotka ovat hieman erilaisia, koska LuaTeXin on käsiteltävä Unicode-merkkikoodiarvoja, jotka voivat olla huomattavasti suurempia kuin 8-bittiset arvot; kuitenkin LuaTeXin laskelmat noudattavat samoja yleisiä periaatteita, joita vanhemmat 8-bittiset moottorit käyttävät.

Saatuaan tunnistettua saapuvan komennon TeX-moottorit, mukaan lukien LuaTeX, jättävät huomiotta johtavan `\` merkin: sitä ei käytetä komentotokenin arvon laskennassa, vaan se toimii vain “kytkimenä”, joka ilmoittaa TeX-moottorille, että sen on käsiteltävä komento. Komentotokenin arvo lasketaan käyttäen (yhdestä tai useammasta) merkistä koostuvaa komentoon nimeä — LuaTeX laskee komentotokeneita sekä ohjaussymboleille että ohjaussanoille samalla algoritmilla:

1. laske väliarvo $$\text{curcs}$$ soveltamalla niin sanottua [hajautusfunktiota](https://en.wikipedia.org/wiki/Hash_function) Unicode UTF-8 -merkkijonoon, joka sisältyy komentoon nimeen: $$\text{curcs}=\texttt{hashfunction}\text{(Unicode UTF-8 string of characters in command name)}$$3. laske komentotokenin arvo, jossa $$\text{command token} = \text{curcs} + 2^{29} - 1$$

**Esimerkkejä**

* tyylille `\\` komento (ohjaussymboli), LuaTeX laskee $$\text{curcs}=94$$, jolloin tuloksena on tokenin arvo `\\` kohteelle $$94 + 2^{29} - 1 = 536871005$$.
* tyylille `\vskip` primitiivikomento (ohjaussana) LuaTeX laskee $$\text{curcs}=3560$$, jolloin tuloksena on tokenin arvo `\vskip` kohteelle $$3560 + 2^{29} -1 = 536874471$$.
* käyttäjän määrittämälle makrolle `\mynewmacro` (ohjaussana) LuaTeX laskee $$\text{curcs} = 2971$$, jolloin tuloksena on tokenin arvo `\mynewmacro` kohteelle $$2971 + 2^{29} -1 = 536873882$$.

Kun tokenit on luotu, ne voidaan tallentaa myöhempää käyttöä varten niin sanottuihin *token-listoihin* tai ne voidaan välittömästi välittää eteenpäin TeX-moottorin sisäiseen käsittelyyn. Tokeneita edustavien kokonaislukuarvojen käyttäminen toimii paitsi kaikilla tietokonealustoilla/käyttöjärjestelmillä, myös se on erittäin tehokas tapa TeXin tallentaa/käsitellä tietoa.

### Miten TeX-moottori tunnistaa tokenin tyypin (komento tai merkki)

Kun sille annetaan tietty kokonaislukutokenin arvo, $$T$$, TeX-moottori voi helposti määrittää, onko $$T$$ edustaako se komentoa vai merkkiä testaamalla, ylittääkö $$T$$ tietyn $$\text{threshold value}$$—se $$\text{threshold value}$$ riippuu TeX-moottorista. Jos $$T \geq \text{threshold value}$$ niin $$T$$ on komentotoken muuten $$T$$ on merkkitoken. Raja on $$\text{threshold value}$$ on $$4095$$ 8-bittisille moottoreille ja $$2^{29}-1$$ (536,870,911) LuaTeXille. Knuth suunnitteli tokenilaskentakaavoissa käytetyt menetelmät niin, että hänen TeX-moottorinsa ja kaikki myöhemmät hänen koodiinsa/arkkitehtuuriinsa perustuvat moottorit voivat nopeasti ja helposti testata tokenien arvoja.

## Tokeneita voidaan purkaa (ja muuntaa takaisin tekstiksi)

Tokenit (kokonaisluvut) ovat mekanismi, jonka avulla TeX-moottori “kapseloi” kaiken, mitä sen tarvitsee kirjata syötetystä elementistä (merkistä tai komennosta). On kuitenkin aikoja, jolloin TeX-moottorin on käännettävä tokenisointiprosessi toisinpäin — selvittääkseen, mitä alun perin luettiin tuon token-arvon tuottamiseksi — yksittäinen merkki tai yhden tai useamman merkin jono, joka muodostaa komennon nimen:

* **merkkitokeneille**: Jokainen merkkitoken voidaan jakaa kahteen osaan: merkkikoodiin ja vastaavaan kategoriakoodiin, joka kyseiselle merkille on annettu *siinä vaiheessa, kun se alun perin luettiin*. Kuten kaikki TeX-moottorit, LuaTeX ei muuta tätä alkuperäistä kategoriakoodijakoa, vaan hyödyntää sitä myöhemmässä sisäisessä käsittelyssä.
* **komentotokeneille:** Nämä ovat hieman yksityiskohtaisempia, mutta jos tarkastelet LuaTeXin komentotokenien laskentaa, mukaan lukien aktiivimerkkien tokenit, näet niiden noudattavan kaavaa: $$\text{command token} = \text{curcs} + 2^{29} -1$$

jossa $$\text{curcs}$$ lasketaan luotavan komentotokenin tyypin mukaan: aktiivimerkki, ohjaussymboli tai ohjaussana. Muuttuja $$\text{curcs}$$ on *erittäin* tärkeä osa TeX-moottorin sisäistä toimintaa: minkä tahansa komentotokenin (kokonaisluku) arvosta LuaTeX voi erittäin helposti poimia arvon $$\text{curcs}$$ tuosta komentotokeneesta käyttämällä $$\text{curcs} = \text{token value} - (2^{29} -1)$$.

### Miksi $$\text{curcs}$$ on niin tärkeä?

Sisäinen TeX-muuttuja $$\text{curcs}$$ (**nyky**inen **c**ohjaus **jono**equence) on elintärkeä osa TeX-moottorin sisäisiä “konepellin alla” tapahtuvia toimintoja. Vaikka et voi etkä saa käyttää tai käsitellä sitä suoraan koodissasi, $$\text{curcs}$$ on ratkaisevassa roolissa, koska TeX-moottorit käyttävät $$\text{curcs}$$ nykyistä arvoa $$\text{curcs}$$ indeksinä sisäisiin taulukoihin, jotka tallentavat tietoja jokaisesta komennosta, jonka moottori tällä hetkellä tuntee. Nuo taulukot tallentavat tietoa komennon nykyisestä merkityksestä: mitä se tekee tai edustaa, ja lisäksi ne tallentavat alkuperäisen merkkijonon, jota käytettiin tuon $$\text{curcs}$$ arvon laskemiseen. Poimimalla `\directlua`arvon komentotokeneesta TeX-moottori pystyy määrittämään minkä tahansa (komento-)tokenin vastaavan nimen eli ihmisen luettavissa olevan tekstin, mikä mahdollistaa tokenin ja tekstin väliset muunnokset, jotka ovat keskeinen osa

### Kokonaislukutokenien muuntaminen takaisin merkeiksi tai merkkijonoiksi (komentojen nimiksi)

Olemme nähneet, että TeX-moottorit muuntavat syötemerkkejä tai merkkijonoja kokonaislukutokeniarvoiksi, mutta joskus TeX-moottorin täytyy *kääntää* tuo prosessi päinvastaiseksi — tulostaakseen ihmisen luettavissa olevan tekstin, jota alun perin käytettiin näiden kokonaislukutokeniarvojen luomiseen; esimerkiksi:

* virhe- tai varoitusviestien kirjoittamiseen näytölle tai `.log` tiedostoa;
* TeX/LaTeX-koodin tulostamiseen tekstitiedostoon `\write-komennon` komennolla;
* käyttäen muunnettaessa tokenijonoa tekstiksi `\directlua` (kuten pian näemme!)

#### Merkkitokenien muuntaminen tekstiksi

Kuten todettu, tokenit ei-aktiivisille merkeille lasketaan käyttämällä syötemerkin kategoriakoodia ja merkkikoodia (Unicode-arvoa). LuaTeX käyttää kaavaa:

$$\text{character token} = (2^{21} \times \text{category code}) + (\text{Unicode value})$$

On suoraviivainen ohjelmointitehtävä jakaa kokonaisluku $$\text{character token}$$ arvo saadakseen sen osatekijänä olevan merkkikoodin ($$\text{Unicode value}$$) ja $$\text{category code}$$.

#### Komentotokenien muuntaminen tekstiksi

Kaikki TeX-moottorit tallentavat jokaisen “tuntemansa” komennon nimen (merkkijonon): olipa kyse käyttäjän määrittelemästä makrosta tai sisäänrakennetusta primitiivistä — primitiivisten komentojen nimien tallennus tapahtuu, kun TeX-moottori käynnistyy, paljon ennen kuin se alkaa käsitellä koodiasi. Käyttäjän määrittelemien komentojen (makrojen) tapauksessa tuon makron nimi (ilman johtavaa `\`) tallennetaan osana makron määrityksen prosesseja TeX-moottoreiden sisällä.

Kun TeX-moottorin täytyy hakea tai tulostaa ihmisen luettavissa oleva teksti, josta kokonaislukutoken-komento alun perin laskettiin, se määrittää ensin $$\text{curcs}$$ arvon kyseiselle tokenille; LuaTeXissä $$\text{curcs} = \text{token} - (2^{29} -1$$). Käyttämällä $$\text{curcs}$$ arvoa, joka on poimittu komentotokeneesta, TeX-moottori voi käyttää sisäistä tietorakennetta nimeltä *merkkipooli* määrittääkseen ihmisen luettavissa olevien merkkien jonon, jota käytettiin alun perin tuon tietyn arvon laskemiseen $$\text{curcs}$$ ja siten vastaavan komentotokenin.

Kuten näemme, nämä tokenien käsittelytoiminnot — merkkijonojen muuntaminen kokonaislukutokeniarvoiksi ja kokonaislukutokeniarvojen muuntaminen takaisin merkkijonoiksi (“de-tokenisointi”) — ovat *perusmekanismeja* käytetään `\directlua`.

## Token-listat

Kun TeX-moottori lukee syötettä, luo merkki- ja komentotokeneita (ja käsittelee niitä), se saattaa kohdata tiettyjä komentoja, jotka käskevät moottoria (väliaikaisesti) lopettamaan tokenien välittämisen eteenpäin jatkokäsittelyä varten, mutta sen sijaan tallentamaan ne myöhempää käyttöä varten. Yleisin esimerkki on makron määrittäminen käyttämällä yhtä makronmäärityskomennoista `\def`, `\edef`, `\gdef` tai `\xdef`—LaTeX-komennot kuten `\newcommand` ovat makroja, jotka tarjoavat lisätoiminnallisuutta, joka on rakennettu matalan tason primitiivien ympärille ja jotka lopulta suorittavat varsinaisen makron määritysprosessin. Makroa voidaan pitää tietyn tallennetun tokenijonon nimenä: token-listana.

TeX-moottorit käyttävät *laajalti* token-listoja, erityisesti [väliaikaisia sisäisiä listoita](/latex/fi/syvalliset-artikkelit/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) sisäisiä käsittelytarkoituksia varten. Jokainen TeX-moottori tarjoaa myös käyttäjätason komentoja token-listojen luomiseksi, jotka tallennetaan myöhempää käyttöä varten, kun käyttäjä tai TeX-moottori itse niitä tarvitsee. Token-listojen luontikomentojen määrä (sisäänrakennetut primitiivit) vaihtelee TeX-moottorin mukaan, mutta kaikilla on yhteinen vähimmäisjoukko, jota jokainen moottori tukee, kuten `\toks` primitiivi.

Käytännössä token-lista on vain tallennettu kokonaislukuarvojen jono:

* syöte luetaan yksittäisten tokenien tuottamiseksi (laskemiseksi), jotka edustavat merkkiä tai komentoa;
* jokainen token tallennetaan sitten, säilyttäen järjestyksen, jossa tokenit tuotettiin syötteestä.

TeX-moottorit tallentavat token-listat käyttäen tietorakennetta nimeltä [linkitetty lista](https://en.wikipedia.org/wiki/Linked_list) (yksinkertaisesti linkitettyä lajia). Lukijoita, jotka haluavat tietää lisää token-listoista, kutsutaan lukemaan Overleafin artikkeli [Mikä on TeX-tokenlista?](/latex/fi/syvalliset-artikkelit/54-what-is-a-tex-token-list.md) joka käyttää analogiaa token-listan taustalla olevien käsitteiden/ajatusten rakentamiseen. TeXin token-listojen ja niiden käytön makrokäsittelyssä perusteellinen tarkastelu löytyy Overleafin artikkelisarjasta [Miten TeX-makrot todella toimivat?](/latex/fi/lisaa-aiheita/01-a-six-part-series-how-do-tex-macros-actually-work.md)

#### Token-lista graafisessa muodossa

Seuraava kuva näyttää LuaTeXin tuottaman token-listan ja vastaavat token-arvot, jotka on tuotettu seuraavasta syötteestä

`Hi, \TeX! \hskip 5bp`

Esimerkiksi, jos määrittelemme `\mymacro` as `\def\mymacro{Hi, \TeX! \hskip 5bp}` määritelmä `\mymacro` tallennettaisiin muistiin token-listan avulla, kuten tämä:

![](/files/920afa3beb7fcdafd0a3fac3d9853179bd0fe6b7)

Token-lista on ketjutettujen alkioiden sarja, joita kutsutaan *solmuista*, nimeksi annetulle pienelle osalle LuaTeXin muistia, joka on varattu kunkin listan alkion säilyttämiseen (kuten yksittäiset lenkit ketjussa). Jokainen solmu sisältää kokonaislukutokenin arvon ja *seuraavan* solmun muisti-osoitteen ketjussa, muodostaen tietorakenteen nimeltä [linkitetty lista](https://en.wikipedia.org/wiki/Linked_list). Viimeinen solmu ilmaisee listan lopun käyttämällä seuraavalle solmulle erityistä “nolla-arvoa” — koska sellaista ei ole.

**Huomautuksia:**

* Havainnollistamisen vuoksi olemme sisällyttäneet jokaisen yksittäisen solmun osoitteen, mutta käytännössä tuo tieto ei tallennu token-listan solmuihin; vain *seuraava solmu* osoite
* tarvitaan TeX-moottorin token-listojen rakentamiseen. *eivät* Kuvan toinen sarake, otsikolla “Mitä kukin token tarkoittaa”, näyttää sarjan harmaita laatikoita, jotka sisältävät tietoa kussakin solmussa olevasta tokenista: nämä ovat puhtaasti tiedoksi eivätkä

Tässä on taulukko yllä kuvassa esitetyn token-listan sisältämistä token-arvoista:

|                 |                      |                                                                             |                |
| --------------- | -------------------- | --------------------------------------------------------------------------- | -------------- |
| **Syöte-alkio** | **Syötteen tyyppi**  | <p><strong>Kategoriakoodi</strong><br><br><strong>(jos merkki)</strong></p> | **Token-arvo** |
| H               | merkkiä              | 11                                                                          | 23068744       |
| i               | merkkiä              | 11                                                                          | 23068777       |
| ,               | merkkiä              | 12                                                                          | 25165868       |
|                 | merkkiä              | 10                                                                          | 20971552       |
| \TeX            | komento (makro)      |                                                                             | 536871539      |
| !               | merkkiä              | 12                                                                          | 25165857       |
|                 | merkkiä              | 10                                                                          | 20971552       |
| \hskip          | komento (primitiivi) |                                                                             | 536874247      |
| 5               | merkkiä              | 12                                                                          | 25165877       |
| b               | merkkiä              | 11                                                                          | 23068770       |
| p               | merkkiä              | 11                                                                          | 23068784       |

**Huom:** Alkuperäisessä syöteteksissämme on komennon jälkeen a, mutta token-listassa ei ole tuota merkkiä edustavaa tokenia. LuaTeXin syötteen skannaus- (lukemis-) prosessi nieli tuon merkin, koska sitä käytettiin päättämään LuaTeXin etsintä merkkien osalta, jotka muodostavat `\hskip` Miten \directlua todella toimii `\hskip` komento.

## Miten \directlua todella toimii

Nyt kun olemme tutkineet tokeneita, token-luetteloita ja tokenien muuntamista tekstiksi, seuraava haaste on ymmärtää TeX-moottorin token-käsite *laajennus*.

Kuten todettiin, `\directlua{⟨koodi⟩}` voidaan pyytää käsittelemään `⟨koodi⟩` joka sisältää sekä Lua- että TeX/LaTeX-koodia, mutta LuaTeXin sisäänrakennettu Lua-kielen tulkki ei ymmärrä TeXiä tai LaTeXia: miten tämä voi siis toimia? Miten on mahdollista, että `⟨koodi⟩` sisältää TeX/LaTeX-ohjeita sekoittamatta täysin Lua-tulkkia komentoihin, joita se ei ymmärrä? Esimerkiksi seuraava `\directlua` komento käyttää vain TeX-makroja, mutta se toimii:

```
\def\aa{tex}
\def\bb{.}
\def\cc{print}
\def\dd{("Hello")}
\directlua{
   \aa\bb\cc\dd
}
```

Tämä `\directlua` komento saa LuaTeXin latoamaan `Hello` mutta miksi ja miten tämä toimii, kun Lua-kieli ei ymmärrä TeX-makroja?

Vastaus sisältyy aiempaan kuvaukseen, jonka lainasimme [LuaTeX-viiteopas](http://www.pragma-ade.com/general/manuals/luatex.pdf) mutta voimme ajatella, että `\directlua{⟨koodi⟩}` toimii siten, että LuaTeX 'esikäsittelee' aluksi `⟨koodi⟩` ennen kuin mitään välitetään Lua-tulkille. Tämän 'esikäsittelyn' luonne — eli mitä se todella tarkoittaa ja mitä siitä seuraa sinun `⟨koodi⟩`— on seuraava aihe, jota käsittelemme auttaaksemme lukijoita, jotka haluavat hyödyntää `\directlua`.

### Miten LuaTeX käsittelee \directlua: ensisilmäys

Syventääksemme ymmärrystämme `\directlua`n "esikäsittelytoimista" voimme aloittaa seuraavalla yksinkertaistetulla kaaviolla, joka antaa yleiskuvan siitä, mitä tapahtuu.  `⟨koodi⟩` annettu `\directlua{⟨koodi⟩}` muunnetaan ensin tokeneiksi yllä käsiteltyjen prosessien ja laskelmien avulla; tuo token-jono tallennetaan token-luetteloon. Kun token-luettelo on rakennettu, jokainen siinä oleva token muunnetaan takaisin tekstuaaliseen esitykseensä: jokaisen tokenin tuottama teksti — oli kyseessä merkkitoken tai komentotoken — yhdistetään (ketjutetaan) yhdeksi koodijonoksi, joka välitetään Lua-tulkille suoritettavaksi.

![](/files/7e023f5cab867478cbaeeee5856beabbd8278f53)

Mutta odota, mitä järkeä olisi siirtyä tekstistä tokeneihin ja muuntaa nuo tokenit heti takaisin tekstiksi? Et ehkä ylläty kuullessasi, että kyllä, tässä kaaviossa ei ole mukana yhtä lisättyä ja olennaista prosessia: *tokenien laajennus*. Jokainen tekstistä tuotettu token sinun `⟨koodi⟩` käsitellään eräänlaisessa "tarkastuksessa", jossa LuaTeX tekee testin nähdäkseen, edustaako token komentoa, joka kuuluu alajoukkoon, jota kutsutaan nimellä *laajennettavat komennot*. Jos näin on, LuaTeX suodattaa kyseisen komennon *poistamista* pois sinun `⟨koodi⟩` ja *korvaten sen* prosessin tuloksilla, jota TeX-moottorit kutsuvat nimellä *tokenien laajennus*.

### Miten LuaTeX käsittelee \directlua: toinen tarkastelu (laajennukseen)

TeXin laajennusmekanismi on kaikkien TeX-pohjaisten ladontaohjelmien ydinosa, koska lopulta jokainen niistä on johdettu Knuthin alkuperäisestä TeX-lähdekoodista ja suunnittelusta tai perustuu siihen. Laajennuksen käsitettä on kuitenkin vaikea selittää ytimekkäällä mutta silti helposti lähestyttävällä kielellä, koska käytännössä 'laajennus' on kattotermi, jota käytetään kuvaamaan yhtä prosessia — mutta sellaista, joka tuottaa monenlaisia tuloksia. Nuo vaihtelevat lopputulokset ovat seurausta siitä hieman eklektisestä komentosarjasta, johon laajennusta voidaan soveltaa, joten voit ajatella, että jokaisella laajennettavalla komennolla on tietty "laajennuskäyttäytyminen".

Yksinkertaistettuna *ensimmäisenä approksimaationa* laajennuksen ymmärtämiseksi voimme sanoa, että tokenin (komennon) laajennus tarkoittaa *poistamista* kyseisen komennon (tokenin) poistamista TeXin nykyisestä syötteestä ja *korvaamista* korvaamista token-jaksolla, joka syntyy suorittamalla kyseinen laajennettava komento — alkuperäisen tokenin korvaamista sen laajennuksen tuloksilla/seurauksilla *käyttäytymistä,*. Tämä alustava "määritelmä" laajennuksesta — uusien tokenien tuottamisena TeXin luettavaksi — ei kuitenkaan ole täysin tarkka kaikkien laajennettavien komentojen osalta, mutta se riittää lähtökohdaksi.

Suoran esimerkin antamiseksi: TeXin primitiivi `\jobname` on laajennettava komento ja sen *laajennus* on merkkitokenien jono, joka edustaa pääasiallisen TeX-syötetiedoston nimeä. Jos TeX päättää laajentaa `\jobname` komennon (tokenin), se *poistetaan* TeXin nykyisestä syöttölähteestä ja *korvataan* sen tuottamalla merkkitokenien jonolla — jonka TeX sitten lukee/käsittelee.

Sisällä `\directlua`, kun laajennettava token on käsitelty (poistettu) ja korvattu uusilla tokeneilla, LuaTeX jatkaa juuri paikalle asetettujen uusien tokenien lukemista — mutta jotkut noista uusista tokeneista voivat myös olla laajennettavia. Koska `\directlua` suorittaa niin sanottua *täyttä laajennusta*, LuaTeX lukee nuo uudet tokenit ja käy jälleen laajennusprosessin läpi laajentaakseen (poistaakseen) kaikki uudet (laajennettavat) tokenit — tämä laajennusprosessi jatkuu, kunnes yhtään laajennettavaa tokenia ei ole jäljellä. Tähän "jatka laajentamista" -sääntöön on kuitenkin kaksi tärkeää poikkeusta, joista kumpaakin käsittelemme alla:

* käyttämällä rakennetta `\the\toks`;
* laajennuksen tarkoituksellinen estäminen (suppressio) yhdeltä tai useammalta valitulta tokenilta.

Kuten todettiin, työmääritelmässämme (ensimmäisessä approksimaatiossa) laajennuksen ymmärtämiseksi ei kateta koko sitä laajennuskäyttäytymisten kirjoa, jota laajennettavien komentojen alajoukko osoittaa. Esimerkiksi jotkin laajennettavat komennot eivät tuota tokeneita samalla tavalla kuin `\jobname` tekee, mutta ne voivat:

* "suodattaa" tokeneita syötteestä: TeX-moottorin ehtokomennot (`\if`, `\ifcat`, `\ifnum`, `\ifdim`, `\ifodd`, `\ifvmode` , …) ovat laajennettavia. Niiden laajentumiskäyttäytyminen on eräänlaista "tokenien suodatusta" — ehtolauseita voidaan käyttää `\directlua`.
* "jongleeraamaan" tokeneita syötteessä: [`\expandafter` komento](/latex/fi/syvalliset-artikkelit/03-a-six-part-article-series-on-expandafter-tex-tokens-and-expansion.md) on laajennettava ja muuttaa kahden tokenin laajentumisjärjestystä.
* estävät laajennuksen: laajennettavat komennot `\noexpand` ja `\unexpanded` estävät komentotokenien laajennuksen syötteessä.
* muuntavat syötteen merkkijonot komentotokeneiksi: `\csname … \endcsname.`
* muuntavat sisäiset suureet merkkitokenien jonoksi: `\number` ja `\the` ovat laajennettavia komentoja, jotka tuottavat merkkitokenien jonon, joka edustaa sisäisen suureen arvoa.
* muuntavat komentotokenit merkkitokeneiksi: `\string` ja `\detokenize` ovat laajennettavia komentoja, jotka muuntavat argumenttinsa merkkitokenien jonoksi, jonka kategoriakoodi on 12. Huomaa, että `\detokenize` eroaa komennosta `\string`: `\detokenize` voi käsitellä useita tokeneita ja lisää välilyöntimerkin, jonka kategoriakoodi on 10, käsiteltyään komennosta luodut komentotokenit *ohjaussanat*. Käytännössä `\detokenize` lisää komennon nimen perään loppuun välilyöntimerkin — näemme myöhemmin artikkelissa joitakin esimerkkejä.

#### Laajennuksen "määritelmän" tarkentaminen

Voimme nyt yleistää määritelmäämme siten, että komennon (tokenin) laajennus sisältää *poistamisen* kyseisen komennon (tokenin) TeXin nykyisestä syöttölähteestä ja *korvaten sen* sen korvaamisen *token-operaation/-operaatioiden* kyseisen komennon suorittamalla. Pohjimmiltaan laajennusprosessi saa laajennettavan komennon suorittamaan jonkinlaisen "operaation" TeXin nykyisessä syötteessä oleville tokeneille, mikä vaikuttaa niiden tokenien määrään tai käyttäytymiseen, joita TeX myöhemmin lukee — tuon "operaation" tarkka luonne riippuu siitä, mikä komento on laajennettavana. Kaikki makrot ja aktiiviset merkit ovat laajennettavia, mutta vain pieni määrä TeX-moottorin sisäänrakennettuja komentoja (primitiivejä) luokitellaan laajennettaviksi — laajennettavien komentojen luettelo riippuu käyttämästäsi TeX-moottorista.

Jokainen uusi TeX-moottori perii esi-isiinsä sisältyneet primitiivikomennot — ne aiemman sukupolven TeX-moottorit, joista se on johdettu — ja osa näistä perityistä primitiiveistä on laajennettavia. Toki uusi TeX-moottori voi päättää olla toteuttamatta joitakin aiemmissa moottoreissa olevia primitiivikomentoja tai muokata niiden käyttäytymistä uuden moottorin tarpeisiin. Lisäksi uudet TeX-moottorit toteuttavat yleensä lisäprimitiivejä oman laajennetun toiminnallisuutensa tueksi — jotkut niistäkin voivat olla laajennettavia. Siksi käytettävissäsi olevien laajennettavien komentojen määrä vaihtelee sen mukaan, mitä TeX-moottoria käytät — LuaTeXissa niitä on varsin suuri kokoelma.

Toinen vaikeus laajennuksen selittämisessä/ymmärtämisessä, ja ehkä varsinainen haaste, on tietää täsmälleen *milloin* TeX-moottori todella suorittaa laajennusprosessin tai ei suorita sitä. Se on laaja ja monimutkainen aihe, koska laajennus on syvälle kietoutunut TeX-moottoreiden sisäiseen toimintaan: meillä ei ole tilaa käsitellä tätä yksityiskohtaisesti muualla kuin laajennuksen käytössä `\directlua`.

### Miten LuaTeX käsittelee \directlua: viimeinen tarkastelu

Seuraava kaavio tiivistää `\directlua` LuaTeX-moottorin sisällä tapahtuvat esikäsittelytoimet. Tässä kaaviossa näytämme myös kaksi matalan tason (sisäistä) LuaTeX-funktiota, jotka todella tekevät työn: `scan_toks()` ja `tokenlist_to_cstring()`. Nuo funktiot on kirjoitettu C-kielellä ja ne sijaitsevat syvällä suoritettavassa LuaTeX-ohjelmistossa: ne ovat osa LuaTeXin sisäistä koneistoa eivätkä *suoraan* ole käytettävissä TeX/LaTeX-koodistasi.

![](/files/3dd99bab236df0f5f6044d552a12f458ddd53520)

Seuraava kuvaus `\directlua ⟨code⟩`n esikäsittelytoiminnasta tiivistää yllä olevan kaavion.

1. Merkkijono sinun ⟨code⟩:ssasi käsitellään `scan_toks()`. Sen tarkoitus on lukea ⟨code⟩ merkkikohtaisesti merkkitokenien ja komentotokenien luomiseksi. Koska se luo tokeneita, jokaiselle ⟨code⟩:n merkille luettuessa annettu kategoriakoodi on erittäin tärkeä.
2. Kun `scan_toks()`n tokenien käsittelyn (luonnin) aikana mikä tahansa laajennettava komento (tokeni) laajennetaan *ellei* ellet sitä estä komennolla kuten `\protected` (makromäärittelyt), `\noexpand`, `\unexpanded` jne. Aktiiviset merkit (kategoriakoodi 13) myös laajennetaan (ellei niitä estetä).
3. Luotujen tokenien virta `scan_toks()` rakennetaan yhdeksi pitkäksi token-luetteloksi — luettelossa oleviin tokeneihin sisältyvät myös ne, jotka on tuotettu soveltamalla laajennusta laajennettaviin komentoihin (kuten makroihin), jotka ovat sinun `⟨koodi⟩`. Huomaa myös, että `scan_toks()` *ei* laukaise tai aiheuta minkä tahansa laajentumattoman komennon edustaman tokenin suorittamista: tällaiset laajentumattomat tokenit vain välitetään sellaisenaan sisällytettäviksi rakennettavaan token-luetteloon.
4. Kun token-luettelo on valmis ja kaikki laajennustoiminta on päättynyt, toinen funktio nimeltä `tokenlist_to_cstring()` muuntaa jokaisen lopullisen token-luettelon tokenin takaisin tekstuaaliseen esitykseensä. Tämä tuottaa tekstijonon, joka on Lua-koodi Lua-tulkille välitettäväksi. Onnistuneen suorituksen kannalta tuon merkkijonon on sisällettävä syntaktisesti oikeaa Lua-koodia.
5. Luan käsittely tuolle koodille tapahtuu kahdessa vaiheessa:
6. LuaTeXin sisäänrakennettu Lua-tulkki jäsentää ja "kääntää" aiemmissa vaiheissa tuotetun Lua-koodin. Jos tuo jäsennys/käännös epäonnistuu, Lua-tulkki tuottaa virheitä (kuten syntaksivirheitä) — nuo virheet voivat aiheuttaa LuaTeX-ajon epäonnistumisen, ellet ole valinnut käyttää `--interaction=nonstopmode` komentorivillä.
7. Jos jäsentäminen/kääntäminen onnistuu, Lua-tulkki suorittaa vaiheessa (5a) käännetyn koodin.

Pohjimmiltaan `scan_toks()` funktio on LuaTeXin esikäsittelytoimien ydin: sen päätehtävä on laajentaa kaikki laajennettavat TeX/LaTeX-komennot, jotka sisältyvät sinun `⟨koodi⟩` ja rakentaa token-luettelo kaikesta, mitä se on käsitellyt. Korostamme jälleen, että `scan_toks()` *ei suorita laajentumattomia komentoja* (tokeneita): se vain *tallentaa* ne tokenit rakentamaansa token-luetteloon. Kun se on valmis, kyseinen token-luettelo muunnetaan myöhemmin *takaisin tekstuaaliseen esitykseensä* funktiolla `tokenlist_to_cstring()`— token-luettelo on puhtaasti TeX-käsite, joka on täysin vieras Lua-tulkkille, joten se on muunnettava tekstiksi, jolloin siitä tulee Lua-koodia Lua-tulkille välitettäväksi.

## Laajennus ohjelmointikielen 'rajapintana'

Voit ajatella, että `\directlua`n laajennusprosessia käytetään mekanismina tai rajapintana tietojen/informaation siirtämiseen 'TeX-maailmasta' 'Lua-maailmaan': se tarjoaa TeX-kielelle tavan viestiä dataa Lua-kielelle. Esimerkiksi TeX-koodi kuten `\number\count75` voidaan käyttää siirtämään "TeX-maailmassa" count-rekisteriin 75 tallennettu arvo "Lua-maailman" kokonaislukumuuttujaan x:

```
\count75=1564  % Data existing in the "TeX World"
\directlua{
   local x=\number\count75 \space  % Transfer TeX data to the "Lua World"
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" and y = "..y)
}
```

Tämä tuottaa Lua-koodin

```
 local x=1564 tex.print("x= "..x) local y = (2*x-65)/5 tex.print(" and y = "..y)
```

**Huomaa**: Lisäsimme `<space>\space` jälkeen `\number\count75` varmistaaksemme, että välilyöntimerkki säilyi välillä `1564` ja `tex.print`—se ei ole tässä välttämätöntä, koska Lua jäsentäisi koodin silti oikein, vaikka jättäisimme sen pois. Heti jälkeen seuraava välilyöntimerkki `\count75` imeytyy prosessissa, jota TeX-moottorit käyttävät numeeristen arvojen etsimiseen — tässä arvo, joka annetaan `\count`. Välilyöntimerkki jälkeen `75` käytetään lopettamaan LuaTeXin numerojonoa koskeva haku `75` ja se imeytyy syötteestä.  `\space` makro laajenee tuottaakseen välilyöntimerkin, jota tarvitaan tekstin erottamiseen `1564` ja `tex.print`.

Kun yllä olevaa koodia käytetään, LuaTeX latoo

`x= 1564 and y = 612.6`

Tässä "datan siirto" -mekanismi toteutuu `\number`: laajennettavan komennon avulla, joka tässä tapauksessa ohjaa TeXiä hakemaan arvon, joka on tallennettu `\count` rekisteriin `75` ja kyseisestä arvosta (`1546`) luomaan sarjan merkkitokeneita, yksi merkkitokeni kutakin numeroa kohti, mikä tuottaa token-jonon numeroille `1`, `5`, `6` ja `4`. Nuo 4 merkkitokenia sisällytetään pääasialliseen token-luetteloon, jota rakentaa `\directlua` ja muunnetaan myöhemmin takaisin tekstuaaliseen esitykseensä, kun token-luettelo muunnetaan tekstiksi. Se on epäilemättä hyvin mutkikas reitti siirryttäessä `\count75` LuaTeXin sisälle tallennetusta rekisteriarvosta Lua-koodille tarkoitetuiksi numeroiksi, mutta lopulta se toimii.

**VINKKI:** Jos haluat tarkastella LuaTeXin laajennustoimien tuloksia, voit kirjoittaa koodin näin:

```
\directlua{
   local foo=[[local x=\number\count75
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" and y = "..y)]]
   print(foo)
}
```

Tässä esimerkissä käytämme pitkien hakasulkeiden menetelmää luodaksemme merkkijonomuuttujan `foo` jonka tarkoituksena on pitää sisällään Lua-koodin merkkijono, joka on luotu laajentamalla kaikki väliltä `[[` ja `]]`. Tuo merkkijono tulostetaan konsoliin Lua-funktiokutsun `print(foo)`.

Overleafissa voit nähdä vastaavia tuloksia kirjoittamalla sisällön `foo` pakettiin `.log` tiedostoon LuaTeXin Lua-funktiolla `texio.write()`:

```
\directlua{
   local foo=[[local x=\number\count75
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" and y = "..y)]]
   texio.write(foo)
}
```

## Tokenit \directlua-token-luettelossa: laajentumattomat tokenit ja laajentamattomat tokenit

Olemme todenneet, että `\directlua{⟨koodi⟩}` suorittaa *täyttä laajennusta* sinun `⟨koodi⟩`: se poistaa ja laajentaa kaikki laajennettavat komennot, kunnes jäljellä on vain laajentumattomia tokeneita. Tokenijono, jonka `\directlua`n käsittely tuottaa ( `scan_toks()` funktiossa), yhdistetään token-luetteloksi, jonka yksittäiset tokenit muunnetaan takaisin tekstiksi Luaan välittämistä varten.

Emme kuitenkaan ole vielä käsitelleet tämän tarinan viimeistä osaa, koska meidän on tarkasteltava kahta komentotokenin "luokkaa", jotka voivat päästä läpi token-luetteloon, jota rakennetaan sisällä `\directlua`: kutsumme niitä nimellä *lyhytkomentotokenit* ja *laajentamattomat* tokenit:

* **lyhytkomentotokenit**: Tämä komentotokenin tyyppi syntyy ohjaussekvensseistä, jotka on määritelty käyttäen jotakin TeXin primitiiveistä `\chardef`, `\mathchardef`, `\countdef`, `\dimendef`, `\skipdef`, `\muskipdef` ja `\toksdef`. Näitä primitiivikomentoja käytetään määrittelemään ohjaussekvenssejä, jotka edustavat numeerista arvoa — tuloksena olevat ohjaussekvenssit ovat *sisällä* laajennettavia.
* **laajentamattomat tokenit**: Tämä tokenityyppi syntyy komennoista, jotka normaalisti laajennettaisiin, mutta `\directlua` has either:
* been explicitly instructed *sisällä* to expand them; for example, suppression of expansion by the commands `\noexpand` tai `\unexpanded`— selitämme pian, miten tämä tehdään;
* ruiskutettuja tokeneita käsittelemällä sekvenssi `\the\toks` (lisää tästä alla).

### Kaksi tokenien "ryhmää" \directlua-token-luettelossa

Keskustelumme perusteella voimme sanoa, että token-luetteloon, jota rakennetaan ensimmäisessä vaiheessa `\directlua`n esikäsittelyä ( `scan_toks()` funktiossa), sisältyvät tokenit jakautuvat kahteen ryhmään:

1. *sisäisesti laajentumattomat* tokenit

* mikä tahansa token, joka edustaa ei-aktiivista *merkkiä*;
* mikä tahansa token, joka edustaa laajentumatonta *primitiiviä* *komento*;
* mikä tahansa token, joka edustaa *lyhytkomentoa* (nämä eivät ole laajennettavia, ks. alla).

3. *laajentamattomat* tokenit:

* mikä tahansa token, joka edustaa laajennettavaa komentoa, jonka laajennus oli *estetty* (tai vältetty) aikana `\directlua`n esikäsittelyä.

#### Lyhytkomentotokenit: laajentumattomien komentojen luominen

Kuten todettiin, TeX-moottorit tarjoavat joukon primitiivejä (sisäänrakennettuja komentoja), joita voidaan käyttää rakentamaan *laajentumattomia* ohjaussekvenssejä (tässä merkittynä `⟨command⟩`). Nämä primitiivit ovat muotoa:

* `\chardef ⟨command⟩ = ⟨numeric value⟩`
* `\mathchardef ⟨command⟩ = ⟨numeric value⟩`
* `\countdef ⟨command⟩ = ⟨numeric value⟩`
* `\dimendef ⟨command⟩ = ⟨numeric value⟩`
* `\skipdef ⟨command⟩ = ⟨numeric value⟩`
* `\muskipdef ⟨command⟩ = ⟨numeric value⟩`
* `\toksdef ⟨command⟩ = ⟨numeric value⟩`

jossa `⟨numeric value⟩` on jokin kullekin komennolle sopiva kokonaislukuarvo.

Tässä tarkastelemme lyhyesti käyttöä `\chardef` havainnollistaaksemme näiden primitiivien keskeistä ominaisuutta — tuottamaan `⟨command⟩` joka on laajentumaton. Voit käyttää ``\chardef\mydollar=`\$`` luodaksesi ohjaussekvenssin `\mydollar` ja käyttää sitä ladotaksesi `$`:

`I paid \mydollar30.`

Tämä latoo `I paid $30.` Ohjaussekvenssi `\mydollar` jonka loi `\chardef` ei ole laajennettava, kuten näemme seuraavasta esimerkistä:

```
\chardef\mydollar=`\$
\directlua{
   local x =[[I paid \mydollar30.]]
   texio.write(x)
}
```

Mikä tuottaa seuraavan tekstin `.log` tiedostoa

`I paid \mydollar 30.`

Tämä osoittaa `\mydollar` oli *sisällä* laajennettiin `\directlua`n esikäsittelyä. Jälkeen näkyvä välilyönti `\mydollar` lisätään, kun komentotoken muunnetaan tekstuaaliseksi esityksekseen.

Kun käytät `\chardef` luodaksesi ohjaussekvenssin, kyseisen ohjaussekvenssin (komennon) sisäinen luokittelu TeXissä johtaa siihen, että se on *laajentumattomia* mikä on hyvin erilaista käyttäytymistä verrattuna ohjaussekvensseihin, jotka on määritelty jollakin makromäärittelykomennoista: \def, \edef, \gdef tai \xdef. Kuten edellä todettiin, token-luetteloaan rakennettaessa `\directlua` tarkastelee jokaista saapuvaa komentotokenia laajennettavuuden tarkistamiseksi. Jos komentotoken ei ole laajennettava, se kulkee suoraan token-luetteloon, ja sen tekstuaalinen esitys ilmestyy myöhemmin uudelleen Lua-koodijonossa, joka syntyy token-luettelon tokenien muuntamisesta takaisin tekstimuotoon.

**Lyhyitä huomioita plain TeXistä ja LaTeXista**

Historiallisesti Knuthin alkuperäinen plain TeX määritteli yleisesti käytetyt ohjaussymbolit `\%`, `\&`, `\#` ja `\$` käyttäen `\chardef`— ei käyttämällä yhtä vakiomakromäärittelykomennoista `\def`, `\edef`, `\gdef` tai `\xdef`. Esimerkiksi:

```
   \chardef\#=`\#
   \chardef\$=`\$
   \chardef\%=`\%
   \chardef\&=`\&
```

Outo `` `\\ `` syntaksi on TeXin tapa saada numeerinen merkkikoodin arvo. Vanhan plain TeX -käytännön mukaan nämä ohjaussymbolit eivät ole laajennettavia (johtuen `\chardef`) mutta LaTeX (tai paketit) voivat määritellä ne uudelleen muodossa *makroja* tarjotakseen laajennettua toiminnallisuutta — mikä tekisi niistä laajennettavia, joten tästä on hyvä olla tietoinen.

**Miten tämä vaikuttaa \directlua:han?**

Verrataan seuraavan koodin tulosta plain TeXissä ja LaTeXissa. Yksinkertaisuuden vuoksi kirjoitamme tulokset `.log` tiedostoon käyttämällä LuaTeXin Lua-API-funktiota `texio.write()`.

```
\directlua{
   local x=[[\$150 for the "\#1" product---20\%! more than its competitor, Widget \& Co.]]
   texio.write(x)
}
```

Kun tämä koodi suoritetaan käyttäen **plain TeX** tuottaa seuraavan tulosteen `.log` tiedostoon, näyttäen mahdollisten laajennusten tuloksen:

```
\$150 for the "\#1" product---20\%! more than its competitor, Widget \& Co.
```

On selvää, että plain TeXissä yksikään ohjaussymboleista`\$`, `\#`, `\%` tai `\&` ei laajennettu — koska ne kaikki on luotu käyttäen `\chardef`.

Kun tuo koodi suoritetaan käyttäen **LaTeX** asiakirjaa:

```
\documentclass{article}
\begin{document}
   \directlua{local x=[[\$150 for the "\#1" product---20\%! more than its competitor, Widget \& Co.]] texio.write(x)}
\end{document}
```

tuottaa seuraavan tulosteen `.log` tiedostoa

```
\protect \TU\textdollar 150 for the "\#1" product---20\%! more than its competitor, Widget \& Co.
```

On selvää, että LaTeXin suorittaminen tuottaa plain TeXistä poikkeavan tuloksen, koska LaTeXissa komento `\$` on laajennettu, mikä osoittaa sen olevan makro.

**Huom:** Sekä plain TeXissä että LaTeXissa `\directlua` ei käsitellyt mitään ohjaussymboleista kokonaan `\%`, `\&`, `\#` ja `\$` vastaavan merkin tuottamiseksi. aikana, kun `\directlua` näitä ohjaussymboleja edustavat tokenit — tai LaTeXissa niiden laajennus — kulkevat suoraan rakenteilla olevaan päätoken-luetteloon.

**Huom:** Ohjaussymbolit muodostuvat yhdestä merkistä, jonka kategoriakoodi ei ole 11, kuten `\#`. Kun ohjaussymbolia edustava token muunnetaan takaisin tekstuaaliseen esitykseensä, TeX-moottorit eivät lisää välilyöntimerkkiä tuon tekstin jälkeen. Tämä ohjaussymbolien erityiskäsittely on sisäänrakennettu sääntö TeX-moottoreiden toiminnassa.

### Laajentamattomat tokenit: laajennuksen estäminen

`\directlua`LuaTeXin esikäsittely on yksi esimerkki siitä, että TeX-moottori suorittaa laajennusta, mutta saatat haluta *estää* laajennusta sovelletaan yhteen tai useampaan tokeniin, jotka muuten laajennettaisiin. Toisena esimerkkinä LuaTeX (ja kaikki TeX-moottorit) suorittavat laajennusprosessin, joka on samankaltainen kuin `\directlua`, kun ne käsittelevät `\write-komennon` komento:

`\write file-number {⟨material⟩}`

\write käskee TeX-moottoria tulostamaan `⟨material⟩`—usein TeX/LaTeX-komentoja sisältävän—tekstitiedostoon (`file-number`); kaikki laajennettavat komennot sisällä `⟨material⟩` laajennetaan, ellei sitä estetä, ennen kuin `⟨material⟩` kirjoitetaan varsinaisesti siihen tiedostoon.

Kuten saatat odottaa, TeX-moottorit tarjoavat komentoja laajennuksen estämiseen tai hallintaan:

* `\noexpand⟨token⟩`: estää yksittäisen `tokenin`;
* `\unexpanded{⟨material⟩}`: estää kaikkien laajennettavien komentojen (tokenien) laajentamisen `⟨material⟩`. Se on käytännössä usean tokenin versio komennosta `\noexpand`;
* `\protected`: makromäärittelyihin lisättävä etuliite, joka estää kyseisen makron laajentamisen tietyissä tilanteissa (kuten aikana `\directlua`, `\write-komennon` tai `\edef`).

Nimistä huolimatta sekä `\noexpand` ja `\unexpanded` olet *laajennettavat komennot* ja tarjoavat hyviä esimerkkejä siitä, että TeX-moottorin laajennusprosessi voidaan nähdä suorittavan “token-operaatioita”: tässä operaationa on estää yhden tai useamman seuraavan tokenin (komennon) laajentaminen. Koska `\noexpand` ja `\unexpanded` ovat molemmat laajennettavia komentoja, ne poistetaan ja käsitellään (suoritetaan) aikana `\directlua`LuaTeXin esikäsittelyssä, kun se rakentaa token-listan sinun `⟨koodi⟩`.

#### \noexpand ⟨token⟩

`\noexpand ⟨token⟩` estää yksittäisen `tokenin`. `\noexpand` sisällä `\directlua` laajennetaan (poistetaan syötteestä) ja korvataan sen “laajennuskäyttäytymisen” tuloksilla. Tuloksena laajentamalla `\noexpand` on luoda erityinen (piilotettu) `⟨merkkitoken⟩` joka sijoitetaan alkuperäisen `tokenin` eteen, jonka laajennus on estettävä: se `⟨merkkitoken⟩` toimii lippuna, joka sanoo “älä laajenna seuraavaa tokenia”. Koska `\directlua` suorittaa täyttä laajennusta, se käsittelee uudelleen kaikki tokenit, jotka syntyvät laajennettavan komennon “laajennuskäyttäytymisestä”. Tämän seurauksena, kun `\noexpand ⟨token⟩` on valmis, LuaTeX palaa lukemaan tulokset ja näkee kahden tokenin sekvenssin `⟨merkkitoken⟩⟨token⟩` mikä saa alkuperäisen `tokenin` kulkemaan läpi laajentamattomana token-listaan, jota rakentaa `\directlua`.

**Esimerkki**

Jos kirjoitamme

```
\directlua{
   local x= "\TeX"
}
```

sivustolta `\TeX` makro laajennetaan sen muodostaviin tokeneihin, mikä plain TeXissä johtaa seuraavan tekstin välittymiseen Lualle (huomaa: Lua ei voi käsitellä tätä koodia, se on vain esimerkki prosessin havainnollistamiseksi):

`local x = "T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX"`

Jos *estämme* laajennuksen `\TeX` makron käyttäen `\noexpand`

`\directlua{local x= "\noexpand\TeX"}`

tuotetaan seuraava Lua-koodi (taas, Lua ei voi ajaa tätä koodia; se on yksinkertaisesti esimerkki osoittamaan `\noexpand`):

`local x= "\TeX "`

Koska `\noexpand`, `\directlua` ei laajene `\TeX` vaan sallii yksinkertaisesti token-arvon, joka edustaa `\TeX` komentoa kulkea vahingoittumattomana läpi token-listaan, jota rakennetaan ensimmäisessä vaiheessa `\directlua`n esikäsittelyä.

**Huom:** Välilyöntimerkki, joka näkyy jälkeen `\TeX` syntyy LuaTeXin myöhemmästä `\TeX` kokonaislukutoken-arvon muuttamisesta takaisin tekstuaaliseen esitykseensä (sisällä `tokenlist_to_cstring()` funktion).

#### \unexpanded{⟨material⟩}

`\unexpanded` on laajennettava komento, joka estää kaikkien tokenien laajenemisen, jotka muodostuvat `⟨material⟩`. Kuten olemme todenneet, kun TeX-moottori suorittaa laajennusta, mikä tahansa laajennettava komento *poistetaan* syötteestä ja *korvataan* korvataan sen “laajennuskäyttäytymisen” tuloksilla; mitä se siis oikeastaan tarkoittaa `\unexpanded`? Yleensä, aikana *täyttä laajennusta*, kun tietyn komennon laajennusprosessi on valmis, TeX-moottori jatkaa lukemaan/käsittelemään kaikki tokenit, jotka syntyvät tuon komennon “laajennuskäyttäytymisestä” — sen täytyy edelleen laajentaa kaikki tuotetut tokenit. Kuitenkin, `\unexpanded` *ohittaa* kaiken lisälaajennuksen: näin se tekee sen.

TeX-moottorin sisällä `\unexpanded` komento muuntaa ensin merkit ja komennot sisällä `⟨material⟩` väliaikaiseksi token-listaksi, joka koostuu *laajentamattomat* tokeneista. Kun kaikki tokenit on luotu ja tallennettu siihen väliaikaiseen token-listaan, `\unexpanded` komento saa `\directlua` kohteeseen *ohittamaan* palaamasta lukemaan ja käsittelemään niitä — vaikka \directlua suorittaa täyttä laajennusta. Sen sijaan nuo *laajentamattomat* tokenit kulkevat suoraan läpi ja tulevat osaksi päätoken-listaa, jota rakentaa `\directlua` (sisällä `scan_toks()` funktion). Tällä tavoin kaikki sisällä `⟨material⟩` muunnetaan tokeneiksi ja laajennusprosessi ohitetaan kyseiseltä tokenijoukolta. Komennon toiminta `\unexpanded{⟨material⟩}` on samankaltaista kuin komennon `\the\toks`, jota käsittelemme alla.

**Esimerkki**

`\unexpanded` tuottaa tuloksia samankaltaisella tavalla kuin `\noexpand` paitsi että se voi estää useiden tokenien laajentamisen; tässä on esimerkki:

```
\directlua{
   local x = "\unexpanded{\foo\bar\foobar}. But Lua can't process this code!"
}
```

mikä tuottaa seuraavan tekstin Lualle koodina:

`local x = "\foo \bar \foobar . But Lua can't process this code!"`

**Huomaa**: Jokaisen komennon nimen jälkeen on välilyöntimerkki. Tämä on jälleen seurausta LuaTeXin myöhemmästä laajentamattomien tokenien muunnoksesta `\foo`, `\bar` ja `\foobar` takaisin tekstiksi sisällä `tokenlist_to_cstring()` funktion.

#### suojatut makromäärittelyt

Se `\protected` komento on etuliite, joka liitetään makromäärittelyyn estämään kyseisen makron laajentaminen, kun TeX rakentaa laajennettua token-listaa, kuten token-listaa, jonka rakentaa `\directlua`n esikäsittelyä.

**Esimerkki**

Oletetaan, että määrittelet seuraavat makrot käyttäen tai käyttämättä `\protected` etuliitettä:

```
\def\macroA{"This unprotected macro contains a string"}
\protected\def\macroB{"This protected macro also contains a string"}
```

Jos käytät Luan merkkijonon yhdistämisoperaattoria (`..`) kirjoittaaksesi

```
\directlua{
   local x=\macroA..\macroB
}
```

`\directlua`LuaTeXin esikäsittely tuottaisi seuraavan koodin Lualle välitettäväksi:

`local x="This unprotected macro contains a string"..\macroB`

`makroA` ei ole määritelty käyttäen `\protected` joten se laajennetaan, mikä tuottaa yhdistettävän merkkijonon ensimmäisen osan, mutta `makroB` on määritelty käyttäen `\protected` joten sitä ei ole laajennettu.

Esikäsittelyn aikana LuaTeXin `scan_toks()` funktio loi tokenin `makroA`, tunnisti sen tavalliseksi laajennettavaksi komennoksi ja laajensi sen: tuo laajennus tuottaa merkkitokenien sekvenssin, yhden merkkitokenin jokaista merkkiä kohti `"This unprotected macro contains a string"`. Jokainen merkkitoken välitetään eteenpäin ja lisätään rakennettavaan token-listaan.

Kun `scan_toks()` luo tokenin `makroB` se huomaa, että komento oli määritelty muodossa `\protected` eikä laajenna sitä: token, joka edustaa `makroB` kulkee läpi koskemattomana (laajentamatta) rakennettavaan token-listaan. Kun tuo token-lista on rakennettu, esikäsittelyn seuraava vaihe, sisällä `tokenlist_to_cstring()` funktion, on muuntaa kaikki token-listan tokenit takaisin niiden tekstuaaliseen esitykseen. Laajentamaton token, joka edustaa `makroB` havaitaan ja muunnetaan tekstiesityksekseen, minkä tuloksena syntyy teksti `makroB` joka näkyy koodissa, joka on tarkoitettu Lualle. Huomaa, että Lua ei voi varsinaisesti yhdistää `"This unprotected macro contains a string"..\macroB` tuottaakseen lopullisen merkkijonon, koska `makroB` ei tarkoita mitään Luan syntaksissa, mikä johtaa virheeseen `unexpected symbol near '\'`.

**Pieni trivia**: Se `\protected` komennon esitteli $$\varepsilon\text{-}\mathrm{\TeX}$$-ohjelma, Knuthin alkuperäisen TeX-ohjelmiston ensimmäinen merkittävä laajennus, ja sitä tukevat kaikki TeX-moottorit, joiden koodin sukulinjaan kuuluu $$\varepsilon\text{-}\mathrm{\TeX}$$.

### Laajentamattomat tokenit: \the\toksin käyttäminen \directlua:ssa

Ohjelmoinnin elämä ei olisi samanlaista ilman niitä “erikoistapauksia”, joiden kanssa toimia ja joiden käyttö `\the` yhdessä `\toks` jossakin `\directlua` komento on yksi tällainen erikoistapaus.

#### Lyhyt taustoitus \toks-komennosta

TeXin primitiivi `\toks` käskee TeX-moottoria tallentamaan joitakin tokeneita myöhempää käyttöä varten: sen sijaan että ne välitettäisiin jatkokäsittelyyn, nuo tokenit asetetaan sivuun ja tallennetaan muistipaikkaan, joka määritetään käyttäen *token-rekisteriä*. Esimerkiksi voimme käskeä TeX-moottoria luomaan joitakin tokeneita ja tallentamaan ne token-rekisteripaikkaan `100` käyttäen

`\toks100={Hi, \TeX! \hskip 5bp}`

Tässä TeX käyttää token-rekisteriä `100` päästäkseen käsiksi tunnettuun sijaintiin muistissaan: tallennusalueeseen, joka on tarkoitettu token-listojen säilyttämiseen.

Tokenit, jotka edustavat kaikkea välillä `{` ja `}` luodaan, *mutta niitä ei laajenneta*, ja ne ketjutetaan token-listaksi—samankaltaiseksi kuin token-lista, jota tarkastelimme aiemmin tässä artikkelissa. Käyttääksemme näitä tokeneita uudelleen kirjoittaisimme `\the\toks100` jossa `\the` (laajennettava komento) käskee TeX:iä hakemaan tallennetut tokenit ja lisäämään ne kohtaan, johon kirjoitit `\the\toks100`. Toinen tapa ajatella tätä on `\the\toks` saa TeX:n lisäämään joitakin tokeneita siihen kohtaan.

Se `\toks` komento *ei laajenna* yhtäkään tokeneista, joita sen pyydetään luomaan ja tallentamaan: se yksinkertaisesti muuntaa merkit ja komennot välillä `{` ja `}` tokeneiksi ja tallentaa ne.

#### Takaisin \directluaan

Laajennusta käsitellessämme totesimme `\directlua{⟨koodi⟩}` suorittaa *täyttä laajennusta* kohteelle `⟨koodi⟩`: kaikkien laajennettavien komentojen poistaminen ja niiden korvaaminen niiden laajennuskäyttäytymisen tuloksella — jatkaen *edelleen laajentamaan* kaikkia tokeneita, jotka syntyvät laajennettavan komennon alkuperäisestä laajennuksesta.

`\the` on laajennettava komento, joten `\directlua` laajentaa sen; kuitenkin, kun `\the` käytetään yhdessä `\toks` sisällä `\directlua`, kuten kohdassa `\the\toks⟨token register⟩`, lisätyt tokenit ovat *eivät laajennu enää*. Laajennus komennosta `\the\toks⟨token register⟩` työntää sekvenssin *laajentamattomat* tokeneita, jotka on tallennettu `⟨token register⟩`, suoraan token-listaan, jota rakentaa `\directlua`: tämä käyttäytyminen ohittaa täyden laajennuksen tavanomaisen prosessin. Käytännössä nuo tokenit kulkevat läpi, *laajentamattomat*ja ne tulevat osaksi päätoken-listaa, jota rakentaa `\directlua`— tämä laajentamattomien tokenien läpikulkuprosessi on toiminnaltaan samankaltainen kuin `\unexpanded`, as discussed earlier.

**Esimerkki**

Oletetaan, että määrittelemme makron `\mymacro` as `\def\mymacro{\TeX}`. Se sisältää vain yhden tokenin `\TeX` komennolle (joka on makro): joten meillä on laajennettava komento `\mymacro` joka sisältää toisen makron `\TeX`, joka on myös laajennettava.

Seuraava koodi saa Luan yrittämään luoda merkkijonomuuttujan `x`:

```
\def\mymacro{\TeX}
\directlua{
   local x="\mymacro"
}
```

Sisällä \\`directlua`, tokenille `\mymacro` laajennetaan, mutta siitä seuraa toinen laajennettava token, `\TeX`jota laajennetaan edelleen. Plain TeXissä nuo laajennukset tuottavat seuraavan tekstin, joka välitetään Lualle:

`local x = "T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX"`

Tämä koodi yrittää määritellä merkkijonon, joka sisältää tekstiä, joka edustaa `\TeX` makron laajennettua versiota. Jos yrität suorittaa tämän esimerkin, Lua yrittää rakentaa tuon merkkijonon, mutta epäonnistuu ja tuottaa virheen:

`invalid escape sequence near ' "T\k'.`

Myöhemmin tässä artikkelissa tutkimme merkitystä “invalid escape sequence”.

Verrataan nyt komennon `\mymacro` käyttöä sijoittamalla `\TeX` token token-listaan, jonka tuottaa `\toks` komento:

```
\toks100={\TeX}
\directlua{
   local x="\the\toks100"
}
```

LuaTeXin `\directlua` käsittely tuottaa tämän merkkijonon Lualle:

`local x = "\TeX "`

Välilyöntimerkki jälkeen `\TeX` syntyy LuaTeXin komento-tokenista merkkijonoksi -muunnosprosessissa.

**Mutta huomaa**: Se `\TeX` makro on *sisällä* laajennettu sen muodostaviin tokeneihin. `\the\toks100` sai rekisteriin 100 tallennetut tokenit lisätyiksi, mutta siinä kaikki: niitä *sisällä* ei laajennettu enää, vaan ne tulevat osaksi päätoken-listaa, jota rakentaa `\directlua` (funktion sisällä `scan_toks()`). Tokenien laittaminen token-listaan, jonka luo `\toks` on jälleen yksi tapa estää tokenien laajentaminen.

Jos suoritamme tämän esimerkin, sekin tuottaa virheen:

`invalid escape sequence near ' "\T'.`

Tutkimme Luan escape-sekvenssejä myöhemmin artikkelissa.

## Muut laajennuksessa käytetyt komennot/tekniikat

Tässä osiossa tarkastelemme joitakin lisäTeX-komentoja/-menetelmiä, joista voi olla hyötyä tilanteissa, joissa laajennusta sovelletaan (kuten sisällä `\directlua`).

### \string ⟨token⟩

`\string` on laajennettava komento, joka muuntaa ⟨tokenin⟩ sarjaksi merkkitokeneita, joista jokaisella on kategoriakoodi 12.

Esimerkiksi, `\string\TeX` tuottaisi neljän merkkitokenin sarjan `\`, `T`, `e` ja `X` jossa jokaiselle merkille annetaan kategoriakoodi 12 (mukaan lukien alussa oleva `\` merkki).

Jos kirjoitamme

```
\directlua{
   local x="I will use \string\newcommand"
   print(x)
}
```

sivustolta `\string` komento laajennetaan, mikä tuottaa sekvenssin merkkitokeneita, joilla on kategoriakoodi 12. Kun `\string` on laajennettu, syntyneet merkkitokenit (jotka edustavat jokaista merkkiä tekstissä `\newcommand`) sisällytetään päätoken-listaan, jota rakentaa `\directlua`. Kun `\directlua` on saanut päätökseen päätoken-listansa rakentamisen, sen muodostavat tokenit muunnetaan takaisin tekstuaaliseen esitykseensä, mikä tuottaa seuraavan koodin välitettäväksi Lua-tulkille:

`local x="I will use \newcommand" print(x)`

Kun tämä koodi välitetään Lualle, `print(x)` tulostaa merkkijonon `x` näytölle (konsoliin). Olemme kuitenkin olleet hieman ovelia ja käyttäneet tarkoituksella esimerkkikomentoa, joka alkaa `\n`. Jos pystyt suorittamaan tämän esimerkin paikallisessa TeX-asennuksessa, huomaat että Lua tulostaa seuraavan tekstin näytölle:

```
   Käytän
   ewcommand
```

Voit suorittaa tämän koodin Overleafissa käskeällä LuaTeXin kirjoittamaan suoraan `.log` tiedostoon käyttämällä LuaTeXin Lua-API-funktiota `texio.write(*string*)`:

```
\directlua{
   local x="I will use \string\newcommand"
   texio.write(x)
}
```

Jos tarkastelet syntynyttä `.log` tiedostoa, huomaat, että se sisältää myös

```
   Käytän
   ewcommand
```

Tämä odottamaton tulos johtuu siitä, että Lua tulkitsee `\n` alussa olevan `**\n**ewcommand` rivinvaihtomerkin escape-sekvenssiksi (merkkikoodi 10): se olettaa, että haluat aloittaa uuden tekstirivin, joka alkaa `ewcommand`. Käsittelemme Luan escape-sekvenssejä myöhemmin tässä artikkelissa.

### \detokenize{⟨material⟩}

`\detokenize` on vaikutuksiltaan usean tokenin versio komennosta `\string` ja sekin on laajennettava komento, joka muuntaa kaiken sisällä `⟨material⟩` sarjaksi merkkitokeneita, joilla on kategoriakoodi 12—*paitsi* välilyöntimerkit (ASCII/Unicode-arvo 32), joille annetaan kategoriakoodi 10. `\detokenize` lisää myös jälkimmäisen välilyöntimerkin komentonimien jälkeen, jotka ovat *ohjaussanat* (esim., `\foo`) mutta välilyöntimerkkiä ei lisätä jälkeen *ohjaussymbolit* (esim., `\#`, `\%` jne).

### Esimerkki

Vaikka makrot `\foohoo`, `\foo`, `\bar` ja `\foobar` eivät ole määriteltyjä, jos kirjoitat tämän:

```
\directlua{
   local x = "\string\foohoo\detokenize{\foo\bar\foobar}"
}
```

se tuottaisi seuraavan tekstin koodiksi välitettäväksi Lua-tulkille

`local x = "\foohoo\foo \bar \foobar "`

Jos et käytä `\string` ja `\detokenize` ja kirjoitat:

`\directlua{local x = "\foohoo\foo\bar\foobar"}`

`\directlua` käsittelisi `\foohoo`, tunnistaisi sen komennoksi ja yrittäisi laajentaa sen; mutta koska `\foohoo` ei ole määritelty, se johtaisi virheeseen:

```
   ! Undefined control sequence.
   l.1 \directlua{local x = "\foohoo
                      \foo\bar\foobar"}
         ?
```

Koska `\string` ja `\detokenize` muuntavat argumenttinsa sarjaksi merkkitokeneita, `\directlua`LuaTeXin laajennusprosessi saa mahdollisuuden havaita laajennettavien komentotokenien `\foohoo`, `\foo`, `\bar`, tai `\foobar`: ne muunnetaan merkkitokenien sekvensseiksi kauan ennen kuin ne voivat laukaista laajennuksen.

Kuten aiemmin todettiin, komennon laajentaminen tarkoittaa sen poistamista syötteestä ja korvaamista sen “laajennuskäyttäytymisen” tuloksella. Laajennuksen tulokset (yleensä tokenit) luetaan sen jälkeen TeX-moottorissa. Tässä “laajennuskäyttäytyminen” komennolle `\string` ja `\detokenize` on imaista syötteestä merkki- ja komentotokenit ja muuntaa ne merkkitokenien sekvensseiksi, jotka aluksi tallennetaan väliaikaiseen token-listaan, jonka `\directlua` myöhemmin lukee. Nuo merkkitokenit tulevat osaksi päätoken-listaa, jota rakentaa `\directlua`.

Seuraava kuva esittää, miten `\string` muuntaa `\foohoo` komennon merkkitokenien sekvenssiksi, tuottaen väliaikaisen token-listan, jonka myöhemmin lukee `\directlua` ottaakseen nuo merkkitokenit osaksi rakennettavaa päätoken-listaa.

![](/files/1c8bd38001deadc03d1360f358e2964dbb730f19)

Jos `\string` tai `\detokenize` kohtaavat merkkejä argumentissaan, esim. `\string a` tai `\detokenize{abc}` noista merkeistä (tässä kategoriakoodilla 11) syntyy merkkitokeneita, mutta kategoriakoodilla 12.

Huomautuksia:

Jos palaamme yllä olevaan esimerkkiin:

`\directlua{local x = "\string\foohoo\detokenize{\foo\bar\foobar}"}`

joka tuottaa seuraavan tekstin koodiksi Lua-tulkille välitettäväksi

`local x = "\foohoo\foo \bar \foobar "`

voimme havaita seuraavaa:

* `\detokenize` on lisännyt välilyöntimerkin jokaisen makronimen jälkeen, mutta `\string` ei tehnyt niin.
* `\string` vaikuttaa yhteen tokeniin.
* Merkkijonossa `"\foohoo\foo \bar \foobar "` määriteltäessä `x` kohtaamme jälleen Luan escape-merkkimekanismin (käsitellään alla):

  * `\bar` alkaa `\b` joka on Luan escape-sekvenssi, jota käytetään esittämään [askelpalautinmerkkiä](https://en.wikipedia.org/wiki/Backspace) (merkkikoodi 8);
  * komennot `\foohoo`, `\foo` ja `\foobar` kaikki alkaa `\f`joka on Luan escape-sekvenssi, jota käytetään esittämään [sivunvaihtomerkkiä](https://en.wikipedia.org/wiki/Page_break#Form_feed) (merkkikoodi 12).

  Koska merkkisekvenssit `\b` ja `\f` käytetään merkkijonossa, joka on luotu käyttämällä kaksoislainausmerkkejä `"..."` ne tuottavat ei-toivottuja tuloksia, ellei sitä estetä käyttämällä Luan niin sanottuja *pitkiä hakasulkeita* merkkijonomenetelmää: aihe, jota voimme nyt käsitellä yhdessä Luan escape-sekvenssien kanssa.

## Mitä ovat “Luan escape-sekvenssit”?

Ohjelmointikielet varaavat tietyt merkit “erikoiskäyttöön” osana kielen syntaksia: käytännössä näille merkeille määritellään jokin erityinen merkitys. Joskus sinun täytyy kuitenkin tilapäisesti “kytkeä pois” tällaisen merkin erityinen merkitys, jos esimerkiksi haluat, että merkki upotetaan osaksi pidempää merkkijonoa, jossa sen tavanomainen käyttäytyminen aiheuttaisi syntaksivirheitä. Pohjimmiltaan kyseinen merkki täytyy käsitellä *ilman* niin, että sen normaali tulkinta laukeaa — että se pääsee läpi huomaamatta. Tämän tekemiseksi ohjelmoijat käyttävät tekniikkaa nimeltä *escapointi* jossa “erikoismerkki” esitetään niin sanotulla *escape-sekvenssillä*.

Tavallinen esimerkki (myös Lua tukee tätä) on kaksoislainausmerkkien käyttäminen merkkijonon sisällä siten, että sisäiset kaksoislainausmerkit pakotetaan escape-sekvenssillä `\"`:

`"Kun heiltä kysyttiin LuaTeXistä, he vastasivat: \"Se on mahtava TeX-moottori!\" Olin samaa mieltä."`

Lua-kieli tarjoaa useita mekanismeja escape-sekvenssien käsittelyyn:

* vakiopakosekvenssejä, mukaan lukien `\n` (rivinvaihto), `\r` (palautusmerkki), `\\` (kenoviiva), `\"` (kaksoislainausmerkki), `\t` (vaakasuuntainen tabulaattori), `\v` (pystysuuntainen tabulaattori) ja `\'` (yksinkertainen lainausmerkki);
* `\xXX`, jossa `XX` on täsmälleen kahden heksadesimaalisen numeron sarja;
* `\ddd`, jossa `ddd` on enintään kolmen desimaalisen numeron sarja;
* siihen aikaan kun tämä artikkeli kirjoitettiin (elokuu 2019), uusin LuaTeX-versio, vaikka sitä ei vielä ollut saatavilla Overleafissa, käyttää Luan versiota 5.3, joka toi tuen UTF-8-escape-sekvensseille: `\u{XXX}`. Tämä escape-mekanismi on UTF-8-koodatuille Unicode-merkkeille, joissa `XXX` on yhden tai useamman heksadesimaalisen numeron sarja, joka esittää merkin koodipistettä. Huomaa, että sulkeena olevat hakasulkeet `{ }` ovat pakolliset.

### Escape-sekvenssien hallinta

Perinteisesti merkkijonot määritellään kaksoislainausmerkeillä, kuten `"tämä on merkkijono"`; tällaisen merkkijonon sisällä voit käyttää escape-sekvenssejä: `"tämä on merkkijono.\nAloitan nyt uudelle riville."`. Lua:ssa on kuitenkin toinen ja *erittäin* kätevä tapa määritellä merkkijonoja: sen niin sanotut *pitkät hakasulkeet* mekanismi, jossa määrittelet merkkijonon ympäröimällä tekstin `[[` ja `]]`:

`[[Olen pitkä hakasulkeinen merkkijono]]`

Pitkien hakasulkeiden menetelmällä luodussa merkkijonossa Luan merkkien escapointimekanismi on *kytketty pois päältä*: escape-sekvenssejä käsitellään tavallisina merkkeinä. Esimerkiksi merkkijonossa

`[[Olen pitkä hakasulkeinen\n merkkijono]]`

sivustolta `\n` escape-sekvenssiä ei käsitellä yksittäisenä palautusmerkkinä (ASCII-koodi 13), vaan kahtena tavallisena merkkinä: `\` seurattuna `n`.

### Miksi pitkien hakasulkeiden merkkijonot ovat niin hyödyllisiä?

Kuten myöhemmin tutkimme, LuaTeX tarjoaa joukon erikoistuneita, sisäänrakennettuja Lua-funktioita, joita voit käyttää `\directlua` hallitsemaan LuaTeXin ladonta-käyttäytymistä. Näiden monien funktioiden joukossa on yksi nimeltä `tex.print(*string*)` joka sallii sinun välittää `*string*` aineistoa Lua-koodista takaisin LuaTeXille ladottavaksi. Hyvin yksinkertainen esimerkki on:

`\directlua{tex.print("Hello, World!")}`

mikä saa LuaTeXin latoamaan `Hello, World!`

Se `*string*` käytettynä `tex.print(*string*)` voi myös sisältää tekstiä, joka edustaa TeX- ja LaTeX-komentoja LuaTeXin käsiteltäväksi. TeX-/LaTeX-komennot alkavat kuitenkin `\` merkillä, mikä on ongelmallista kaksoislainausmerkeillä luoduissa merkkijonoissa, koska Lua yrittäisi jäsentää merkkijonon, havaita alkuperäisen `\` merkin ja tulkita sen escape-sekvenssin aluksi. Kun Lua yrittää käsitellä escape-sekvenssiä, se yleensä epäonnistuu, koska alkuperäinen `\` yhdistettynä monien TeX-/LaTeX-komentojen nimen ensimmäiseen merkkiin ei muodosta kelvollista Luan tuntemaa escape-sekvenssiä. Esimerkiksi käsiteltäessä merkkijonoa kuten `"Pidän \LaTeXista"` Lua näkisi `\L` ja epäonnistuisi virheellä “virheellinen escape-sekvenssi”, ja tämä on edellä mainittujen virheiden syy.

#### Pitkien hakasulkeiden merkkijonot tulevat apuun!

Merkkijonojen luomisen (määrittelemisen) pitkien hakasulkeiden menetelmä on erittäin hyödyllinen, koska vaikka TeX-/LaTeX-komennot alkavatkin `\` merkillä, pitkien hakasulkeiden merkkijonomenetelmä poistaa käytöstä Luan escape-sekvenssimekanismin. Tässä on lyhyt esimerkki, muistaen että meidän täytyy estää makrojen laajentuminen käyttämällä esimerkiksi `\protected` tai `\noexpand`.

Oletetaan, että määrittelemme `\newtest` makron näin

`**\protected**\def\newtest#1{Argumentti: #1}`

ja käytämme sitä `\directlua` LuaTeXin Lua API -funktion kanssa `tex.print()`:

```
\directlua{
   tex.print("\newtest{Hello}")
}
```

Koska käytössä on `\protected`, makro `\newtest` ei laajene, mikä johtaa seuraavaan tekstiin, joka välitetään Lua:lle:

`tex.print("\newtest {Hello}")`

Välilyönti, joka lisätään `\newtest` jälkeen ja ennen avausaaltosuljetta (`{`) on sivuvaikutus `\directlua`komentotokenien takaisin niiden tekstuaaliseen esitykseen muuntamisesta.

Tämä koodi välitetään Lua:lle, joka suorittaa sen jälkeen LuaTeX-funktion `tex.print()` mutta siinä on ongelma, joka ilmenee eri tavoin käyttämiesi fonttien mukaan. Overleafin LaTeXissa näkisit tulosteen kuten tämän:

![](/files/a9b05bcba775d9f8d2f0bb0520a273021bc44971)

sekä lokitiedostossa olevan varoituksen:

```
   Puuttuva merkki: Fontissa ei ole
   (U+000A) fontissa [lmroman10-regular]:+tlig;!
```

Pelkässä TeXissä saatat nähdä tulosteen, joka näyttää suunnilleen tältä:

![](/files/eab9e1da66967b8f55456239d84ad6c214239ea7)

Molemmissa tapauksissa `\newtest` makroa ei kutsuta ja tuloste ei ole sitä, mitä tarkoitimme. Virhe johtuu Luan escape-merkinkäsittelystä: tekstissä `\newtest {Hello}` makron nimi alkaa `\n` merkistä, jonka Lua tunnistaa rivinvaihtomerkin escape-sekvenssiksi, joten se korvaa `\n` ASCII-merkkiarvolla 10, eli heksana 0A. LaTeXin virheilmoituksessa, `U+000A` on tapa esittää Unicode-arvo neljällä heksadesimaalilla.

Koska `\n` muunnetaan rivinvaihtomerkiksi, LuaTeX ei näe makrokutsua vaan olettaa sen sijaan, että sitä pyydetään latoamaan tekstiä, joka alkaa ASCII-merkkiarvolla 10:

`⟨ASCII 10⟩ewtest {Hello}`

Käytetystä fontista riippuen LuaTeX voi tai ei ehkä pysty latoamaan `⟨ASCII 10⟩` merkkiä, mutta loppu teksti tulostetaan sellaisenaan, ja `{` ja `}` käsitellään ryhmänä eikä tulosteta.

Pelkässä TeXissä saadaan erilainen tulos, koska oletusfontti on Computer Modern Roman, jolla on outo merkistö, jonka vuoksi merkkiarvon 10 kohdalla ladotaan iso omega.

Näiden ongelmien estämiseksi meidän täytyy käyttää pitkien hakasulkeiden merkkijonoja, jotta Luan escapointimekanismia ei sovelleta. Oikea tulos saadaan käyttämällä

`\directlua{tex.print([[\newtest{Hello}]])}`

joka tuottaa seuraavassa kuvakaappauksessa näytetyn tuloksen:

![](/files/45c8ee43929024d223e40b38f09c7ebd19e873c3)

### Laajeneminen ja laajenemattomien komentojen ei-suorittaminen

Laajenemista käsitellessämme totesimme, että kyseessä on prosessi, jossa TeX-moottori *poistaa* laajenevan komennon (tokenin) nykyisestä syötteestä ja *korvaa* sen tämän laajenevan komennon tuottamilla tuloksilla. Koska \directlua suorittaa *pelkkään laajennukseen* tähtääviä toimintoja (tokeniluettelon luomiseksi), se *ei* ei vie LuaTeXin käsittelyä sitä pidemmälle. Kun laajeneva komento on luettu ja laajennettu täysin, tämän laajennuksen tulokset — joihin usein sisältyy laajenemattomia komentoja (tokeneita) — sisällytetään rakennettavaan tokeniluetteloon, valmiina muunnettavaksi takaisin tekstiksi, joka välitetään Lualle.

Tässä vaikuttaa tärkeä periaate: aikana *pelkkään laajennukseen* toimintojen, joiden tarkoituksena on tuottaa tokeniluettelo, TeX-moottorit, mukaan lukien LuaTeX, *eivät suorita* mitään laajenemattomia primitiivi-, sisäänrakennettuja tai TeX-komentoja.

Tapauksessa `\directlua{⟨koodi⟩}`, jos `⟨koodi⟩` täysin laajennettu versio sinun *tuottaa tai sisältää laajenemattomia TeX-/LaTeX-komentoja, ne* välitetään Lualle

#### Esimerkki

(esitettynä tekstinä). `\directlua`). Oletetaan, että määrittelemme makron `\setcountreg` näin:

`\def\setcountreg#1#2{\count#1=#2\relax}`

**Huomaa**: Käytämme `\relax` parametrin `#2` jälkeen estääksemme LuaTeXiä menemästä liian pitkälle, kun se etsii numeerista arvoa (argumenttia), joka vastaa parametria `#2`.

Jos, tämän ulkopuolella, `\directlua`myöhemmin ajamme makron näin

```
   \setcountreg{100}{50}
   Count-rekisterin 100 arvo on \the\count100.
```

se tuottaisi tulosteeksi

`Count-rekisterin 100 arvo on 50.`

Tässä yhteydessä mikä tahansa TeX-moottori käsittelisi makron `\setcountreg`— laajentaisi makron, määrittäisi argumentit ja jatkaisi lukemista *ja toimisi* (suorittaisi) komennot, jotka sisältyvät makron korvaavaan tekstiin (määritelmään). Tuloksena tässä on asettaa `50` arvoksi, joka on tallennettu rekisteriin `\count100`.

Kuitenkin, kun TeX-moottori suorittaa *pelkkään laajennukseen* toimintoja, kuten `\directlua`, se *ei suorita* laajenemattomia komentoja, jotka sisältyvät makron määritelmään.

Jos kirjoitamme

```
\def\setcountreg#1#2{\count#1=#2\relax}
\directlua{
   local x = [[\setcountreg{100}{50}]]
}
```

se tuottaa seuraavan tekstin Luan koodiksi:

`local x = [[\count 100=50\relax ]]`

Yllä tuotettu Lua-koodi osoittaa, että sisällä `\directlua` sivustolta `\setcountreg` on laajennettu, sen argumentit tunnistettu ja sijoitettu asianmukaiseen parametriin (`#1` ja `#2`) mutta se ei mene sen pidemmälle: laajenematon primitiivinen TeX-komento `\count` oli *ei suoriteta* aikana `\directlua`laajennuksen käsittelyn aikana.

Kuitenkin LuaTeX suorittaa TeX-koodin, jos välitämme tuloksena saadun merkkijonon `x` *takaisin LuaTeXille* kautta `tex.print(x)` näin

```
\count100=50 % asetetaan \count100:n alkuarvoksi 50
\def\setcountreg#1#2{\count#1=#2\relax}
\directlua{
   local x = [[\setcountreg{100}{250}]]
   tex.print(x)
}
Count-rekisteriin 100 tallennettu arvo on \the\count100.
```

Kun `\directlua` on valmis, tuloste olisi

`Count-rekisteriin 100 tallennettu arvo on 250.`

osoittaen, että count-rekisteri `100` sisältää nyt arvon `250`.

Yllä olevasta esimerkistä tuotettu Lua-koodi on

`local x = [[\count 100=250\relax ]] tex.print(x)`

Tämä koodi määrittelee `x` olemaan merkkijonon, joka on luotu pitkien hakasulkeiden menetelmällä ja jota käytetään välttämään virheet virheellisissä escape-sekvensseissä. Jos käyttäisimme kaksoislainausmerkkejä `"..."` määritelläksemme x:n, merkkijono `\c` alussa olevan `\count` aiheuttaisi virheen: `virheellinen escape-sekvenssi lähellä ' "\c'`.

LuaTeXin Lua API -kutsu `tex.print(x)` johtaa siihen, että LuaTeX suorittaa TeX-koodijonon `\count 100=250\relax` ja `\count100` saa arvokseen `250` kuten ladotusta tulosteesta näkyy:

`Count-rekisteriin 100 tallennettu arvo on 250.`

#### Varoitus: makrot ja LuaTeXin Lua API

Yllä olevassa esimerkissä näimme, että aikana `\directlua`n esikäsittelyn (laajennuksen) LuaTeX ei suorittanut koodia `\count 100=250`, joka sisältää `laajentumattomia` primitiivikomento `\count`: sen suorittamiseksi meidän täytyi *välittää se takaisin LuaTeXille* kautta `tex.print()`.

`\directlua` on vain yksi tapaus, jossa LuaTeX suorittaa pelkästään laajennukseen tähtäävää käsittelyä tokeniluettelon rakentamiseksi. On muitakin komentoja, jotka suorittavat samanlaista laajennuskäsittelyä ja tokeniluettelon tuottamista, kuten `\write-komennon` ja `\edef`: nämä komennot eivät myöskään suorita laajenemattomia primitiivejä laajennuskäsittelynsä aikana. Yleinen periaate on, että TeX-moottorit eivät suorita laajenemattomia primitiivejä tokeniluetteloa rakentaessaan pelkän laajennuskäsittelyn aikana.

**Makron kirjoittaminen uudelleen LuaTeXin Lua API:n käyttöä varten**

Voimme kirjoittaa uudelleen `\setcountreg` makron käyttäen LuaTeXin Lua API -funktiota nimeltä `tex.setcount()`, välttäen siten TeX-komennot, joilla muutetaan count-rekisteriin `100`:

```
   \def\setcount#1#2{\directlua{tex.setcount(#1,#2)}}
   \count100=50
   count-rekisteri 100 sisältää \the\count100\par
   \setcount{100}{250}
   count-rekisteri 100 sisältää nyt \the\count100\par
```

Tämä koodi latoo:

```
count-rekisteri 100 sisältää 50
count-rekisteri 100 sisältää nyt 250
```

Tässä käytämme `tex.setcount()`, yhtä LuaTeXin monista Lua API -funktioista, jotta voimme *suoraan käyttää* LuaTeXin sisäistä datan tallennusaluetta sijoittaaksemme arvon `250` muistipaikkaan, joka edustaa count-rekisteriä `100`. Käytännössä olemme *ohittaneet* LuaTeXin tavalliset TeX-moottorin syötteenkäsittelymenetelmät: syötteen lukemisen, tokenien luomisen ja TeX-primitiivikomentojen suorittamisen. Tässä on kuitenkin varoittava esimerkki: käyttämällä LuaTeXin Lua API -funktioita pelkästään laajennukseen tähtäävä käsittely *voi johtaa sivuvaikutuksiin*: muutoksiin TeX-moottorin sisällä tallennetuissa arvoissa, jotka eivät muuten olisi mahdollisia pelkillä TeX-/LaTeX-komennoilla.

**Esimerkki: odottamattomat sivuvaikutukset**

Tässä on esimerkki, joka osoittaa *odottamattomia* sivuvaikutuksia, joita voi syntyä makroissa, joissa käytetään `\directlua`. Oletetaan, että kirjoitamme seuraavan koodin:

```
\def\dochange{\directlua{tex.setcount(999,12345)}}
\edef\careful{\dochange}
\the\count999
```

Tämän koodin suorittaminen latoo: `12345`!

Miten se voi olla? Emme *nimenomaisesti* kutsuneet mitään koodia tai makroja sijoittaaksemme tuon arvon count-rekisteriin `999`. Vai olemmeko?

Määrittelimme `\dochange` seuraavalla: `\directlua` komennon, joka käyttää `tex.setcount()` tallentaakseen arvon `12345` count-rekisteriin `999`: TeX-koodissa se vastaa `\count999=12345`. Sitten käytimme tavallista TeX-primitiiviä `\edef` määritelläksemme makron `\careful`— juuri `\edef` n käyttö laukaisee odottamattoman sivuvaikutuksen.

`\edef` laajentaa argumenttinsa täysin: tässä se havaitsee laajenevan makron `\dochange` ja laajentaa sen.  `\dochange` makro käyttää laajenevaa komentoa `\directlua` , joka sisältää Lua API -kutsun; joten `\dochange` laajentaminen johtaa `\directlua` laajenemiseen ja se saa `tex.setcount()` kutsutuksi, mikä muuttaa count-rekisterin arvoa `999`.

Jos määrittelemme `\dochange` käyttämään TeX-komentoja:

```
   Ennen: count-rekisterissä 999 on \the\count999.\par
   \def\dochange{\count999=12345\relax}
   \edef\careful{\dochange}
   Jälkeen: count-rekisterissä 999 on \the\count999.\par
```

tämän koodin suorittaminen latoo

```
Ennen: count-rekisterissä 999 on 0.
Jälkeen: count-rekisterissä 999 on 0.
```

On selvää, että tällä ei ollut vaikutusta `\count999`. Kun `\edef` määrittelee `\careful` se laajentaa `\dochange` mutta tuo laajennus tuottaa vain laajenemattomia TeX-primitiivejä: niitä ei *ei suoriteta* vaan ainoastaan *tallennetaan* makron määritelmän muodostavassa tokeniluettelossa `\careful`.

Varmuuden vuoksi sama periaate selittää, miksi tämä tuottaa ladottua tulostetta:

```
\def\dochange{\directlua{tex.print("Hello")}}
\edef\careful{\dochange}
```

## Lyhyt johdatus LuaTeXin Lua API:hin

Kuten olemme nähneet, `\directlua` ei ainoastaan anna sinun kirjoittaa tavallista Lua-koodia tai Lua- ja TeX/LaTeX-koodin sekoitusta, vaan se tarjoaa myös pääsyn joukkoon lisä-Lua-funktioita (LuaTeXiin liittyviä), joita voit käyttää (kutsua) viestiäksesi LuaTeXin ladontaohjelmiston sisäisen toiminnan kanssa tai ohjataksesi sitä suoraan. Olemme käyttäneet useita Lua-funktioita tässä artikkelissa, `tex.print()`, `texio.write()`, `tex.setcount()` ja nämä yhdessä *monien* muiden kanssa, on dokumentoitu [LuaTeXin viiteoppaassa](http://www.pragma-ade.com/general/manuals/luatex.pdf) joissa toisiinsa liittyviä funktioryhmiä kutsutaan *kirjastoiksi*.

Voit ajatella näitä Lua-funktioita LuaTeXin Lua API:na (**Yksi**sovellus **S**ohjelmointi **I**rajapinta), joka tarjoaa työkalut kehittyneiden ladonta- ja dokumenttiteknisten ratkaisujen rakentamiseen ohjaamalla LuaTeXin ladonta-käyttäytymistä Luan avulla.

Kuten todettu, LuaTeX järjestää API:nsä funktiosarjoiksi, joita se kutsuu kirjastoiksi: funktioryhmiksi, jotka liittyvät toisiinsa tarkoituksensa tai toimintojensa kautta. Jokainen funktiosarja on suunniteltu tarjoamaan pääsy LuaTeXin sisäisten prosessien, tietorakenteiden, tietovarastojen ja ladonta-algoritmien tiettyyn osa-alueeseen. Sisäisesti LuaTeX koostuu useista osista: ohjelmistokirjastoista/työkaluista (enimmäkseen C:llä kirjoitetuista), jotka muodostavat paitsi itse TeX-moottorin myös muita alijärjestelmiä, kuten Luan, MetaPostin, Kpathsean, FontForgen, libpng:n ja zlibin. Nämä kirjastot on integroitu rakentamaan LuaTeX-suoritettavan ohjelmiston ominaisuudet ja toiminnot, ja juuri Lua API:n kautta käyttäjille annetaan pääsy LuaTeXin toiminnallisuuteen, joka perustuu näiden useiden ohjelmistokomponenttien integraatioon ja koordinointiin.

## Muutamia esimerkkejä ja sudenkuoppia

Tässä osiossa esittelemme joitakin lisäesimerkkejä, jotka hyödyntävät tässä artikkelissa esitettyjä aiheita, käsitteitä ja selityksiä.

### Aaltomerkin (\~) käyttäminen

Lua-kieli käyttää `~` merkkiä (kutsutaan aaltomerkiksi) osana syntaksiaan, mukaan lukien syntaksi “ei yhtä suuri kuin” -testin suorittamiseksi; esimerkiksi testataksemme, onko muuttuja `x` ei yhtä suuri kuin `4` voisimme kirjoittaa:

```
   local x=3
   jos x ~= 4 sitten
   print("x ei ole yhtä suuri kuin 4")
   end
```

Jos yritämme suorittaa tämän yksinkertaisen Lua-koodin kautta `\directlua`:

```
\directlua{
   local x=3
   jos x ~= 4 sitten
   print("x ei ole yhtä suuri kuin 4")
   end
}
```

saamme virheen:

`[\directlua]:1: 'then' expected near '\'.`

Tämä on outoa, koska koodimme on oikein: olemme käyttäneet `'then'` eikä koodissamme ole `\` merkkiä koodissamme, joten mikä meni pieleen? Ymmärtääksemme tämän meidän on muistettava, että TeX/LaTeX:lle `~` on yleensä määritelty “erikoismerkiksi” kategoriakoodilla 13: niin sanotuiksi aktiivisiksi merkeiksi, jotka ovat minimakroja ja siten laajenemisen alaisia. Kun `\directlua` havaitsee `~` merkin *se laajennetaan poistamalla se* syötteestä ja *korvaten sen* ja korvaamalla se sen laajennuksen tuloksella. Käytettäessä tavallista TeXiä, tuloksena syntyvä teksti (koodi), jonka LuaTeX tuottaa ja välittää Lua-tulkille, ei itse asiassa sisällä `~` merkkiä, ja on:

`local x=3 if x \penalty \@M \ = 4 then print("x ei ole yhtä suuri kuin 4") end`

Se `~` merkki on ollut *poistetaan* ja *laajennettu* sen osatekijäkomentoihin — yllä oleva Lua-koodi on tavallisen TeXin aktiivisen merkin määritelmän tulosta `~`. Nyt voimme nähdä, miksi Lua vastaa virheellä `'then' expected near '\'`—se alkaa jäsentää tätä koodia, mutta kohtaa sanan `\penalty` joka ei merkitse Lua:lle mitään ja aiheuttaa syntaksivirheen.

Tämän korjaamiseksi `~` merkillä on oltava turvallinen kategoriakoodi sillä hetkellä `\directlua` käsittelee koodiasi; esimerkiksi voimme tilapäisesti muuttaa merkin `~` kategoriakoodiksi 11 (kirjain) sulkemalla koodi ryhmään:

```
\begingroup
\catcode`\~=11
\directlua{
   local x=3
   jos x ~= 4 sitten
   print("x ei ole yhtä suuri kuin 4")
   end
}
\endgroup
```

Tämä koodi toimii odotetusti, ja `x ei ole yhtä suuri kuin 4` tulostuu konsoliin. On muitakin vaihtoehtoja: voimme käyttää laajenevia komentoja `\noexpand` tai `\string`.

#### Käyttäen \string⟨token⟩

Voimme soveltaa `\string` yksittäismerkkiin `tokenin` `~` jolla on kategoriakoodi 13 (aktiivinen merkki); `\string` muuntaa `~` merkkiä luodaksemme merkkitunnuksen, jolla on kategoriakoodi 12. Jos teemme

```
\directlua{
   local x=3
   if x \string~= 4 then
   print("x ei ole yhtä suuri kuin 4")
   end
}
```

se tuottaa tarvitsemaamme Lua-koodia:

`local x=3 if x ~= 4 then tex.print("x ei ole yhtä suuri kuin 4") end`

#### Käyttäen \noexpand⟨token⟩

Voimme käyttää `\noexpand~` aktiivisen merkin laajenemisen estämiseksi `~`

```
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x ei ole yhtä suuri kuin 4")
   end
}
```

Laajentamaton `~` tunnus kulkee läpi tunnusluetteloon, jota rakennetaan `\directlua` ja muunnetaan takaisin tekstiksi, joka tuottaa toimivan Lua-koodin.

### Käyttäen #-merkkiä

Lua-kielessä `#` merkkiä voidaan käyttää taulukon pituuden selvittämiseen. Kuitenkin, jos yritämme seuraavaa koodia

```
\directlua{
   local tbl = {}
   tbl[1] = "Hei"
   tbl[2] = "Maailma"
   tex.print("Taulukon pituus on "..#tbl)
}
```

voisimme odottaa LuaTeXin ladovan

`Taulukon pituus on 2`

mutta se tuottaa virheen:

`\directlua]:1: attempt to get length of a number value`

Tämä virhe aiheutuu siitä, että `#` merkillä on yleensä kategoriakoodi 6 (makroparametri) — `#` merkkiä käytetään TeX/LaTeX:ssa kahdella tavalla: osoittamaan makroparametreja (`#1`, `#2`… `#9`) ja tasausmallien korvaavassa tekstissä ( `\halign` ja `\valign`).

Kun `\directlua` luo tunnuksia rakentaakseen tunnusluetteloaan, se näkee `#` merkin, jonka kategoriakoodi on 6, ja luo sopivan merkkitunnuksen sitä edustamaan. Kun lopullinen tunnusluettelo on aika muuntaa takaisin tekstimuotoon, #-merkin merkkitunnus (kategoriakoodilla 6) käsitellään erityisesti: se tulostetaan muodossa *kaksi peräkkäistä merkkiä*: `##`, jolloin Lua:lle välitetään seuraava koodi:

`local tbl = {} tbl[1] = "Hei" tbl[2] = "Maailma" print(##tbl)`

Muunnettaessa Lua-koodiksi alkuperäinen `#` on kaksinkertaistettu, ja se aiheuttaa virheen:

`\directlua]:1: attempt to get length of a number value`

Tämä ongelma johtuu TeXin syntaksista, jossa käytetään kaksoisrisua `##` yksittäisen `#` tunnuksen esittämiseen tai luomiseen; tätä syntaksia käytetään makroissa, jotka määrittävät muita parametreja ottavia makroja, tai makroissa, joita käytetään mallien luomiseen `\halign` tai `\valign` taulunrakennuskäskyjä varten. Tämä on melko sekavaa, joten katsotaan esimerkkiä.

#### Esimerkki

Oletetaan, että määrittelemme makron `\mymacro` joka ottaa yhden parametrin, `#1`, mutta se määrittää myös toisen makron `\foo` joka itsekin ottaa yhden parametrin. Erottamaan parametrin `#1` käytön `\mymacro` ja tarpeen määritellä `\foo` käyttämään omaa parametritaan `#1` TeXin syntaksi edellyttää, että käytät `##1` sisällä `\mymacro` esittämään parametrin, jota käytetään `\foo`:

`\def\mymacro#1{\def\foo##1{#1 Hei##1}}`

Jos kirjoittaisit `\mymacro{Hei!}` se määrittäisi makron `\foo` olevan

`\def\foo#1{Hei! Hei#1}`

Huomaa, että `\mymacro`parametri `#1` (`Hei!`) on sisällytetty määritelmään `\foo` ja sarja `##1` on muunnettu `#1` määritelmässä `\foo`. Voimme siis käyttää `\foo` näin:

`\foo{, World!}`

ladottavan `Hei! Hei, World!`

Voimme ratkaista `\directlua`käsittelyn `#` merkkiä muuttamalla sen kategoriakoodia tilapäisesti ennen kuin LuaTeX käsittelee koodin. Esimerkiksi:

```
\begingroup
   \catcode`\#=11
   \directlua{
   local tbl = {}
   tbl[1] = "Hei"
   tbl[2] = "Maailma"
   tex.print("Taulukon pituus on "..#tbl)
}
\endgroup
```

Tämä tuottaa Lua-koodin

```
local tbl = {} tbl[1] = "Hei" tbl[2] = "Maailma" tex.print("Taulukon pituus on "..#tbl)
```

joka latoo odottamamme tuloksen:

`Taulukon pituus on 2`

### Käyttäen %-merkkiä

TeX/LaTeX:ssa, `%` merkkiä käytetään tyypillisesti yksirivisten kommenttien lisäämiseen koodiin: merkitsemään TeX-moottorille, että sen tulisi sivuuttaa kaikki siitä kohdasta rivin loppuun asti, jolla `%` on kirjoitettu. Lua-kielessä kuitenkin `%` merkkiä käytetään joissakin hyvin hyödyllisissä merkkijonojen käsittelyfunktioissa, kuten `string.format(...)`, `string.gmatch(...)`, ja `string.gsub(...)` joissa `%` merkillä on tärkeä rooli osana kyseisten funktioiden syntaksia.

Käytettäessä TeX/LaTeX:n kanssa `%` toimii kommenttimerkkinä, koska sille on annettu kategoriakoodi 14. Jotta se käyttäytyisi tavallisena merkkinä ja sen tavanomainen TeX/LaTeX-käyttäytyminen kytkettäisiin pois, meidän on muutettava sen kategoriakoodi turvalliseksi arvoksi, kuten 12. Alla oleva `\directlua` esimerkki käyttää useita aiemmin artikkelissa käsiteltyjä tekniikoita sekä yhtä, jota emme ole vielä maininneet: ``\catcode`\^^M=12``, mikä sallii meidän käyttää Lua-kommentteja koodissamme; tästä keskustellaan alla.

#### Esimerkki

Seuraavat esimerkit on lainattu [lua-users.org](http://lua-users.org/wiki/StringLibraryTutorial), sopivasti muokattuina käytettäviksi `\directlua`.

```
\documentclass{article}
\begin{document}
\begingroup
\ttfamily
\let\\\relax
\catcode`\^^M=12 %<---tutkimme tätä lisää alla!
\catcode`\%=12
\directlua{
   local str -- ilmoita paikallinen muuttuja tuloksen tallentamista varten

   tex.print("Käyttäen string.format():".."\\par")

   str=string.format("%s %q", "Hei", "Lua-käyttäjä!") -- merkkijono ja lainausmerkillinen merkkijono
   tex.print(str.."\\par")
   str = string.format("%c%c%c", 76, 117, 97) -- merkki
   tex.print(str.."\\par")
   str=string.format("%e, %E", math.pi, math.pi) -- eksponentti
   tex.print(str.."\\par")
   str=string.format("%f", math.pi) -- liukuluku
   tex.print(str.."\\par")
   str=string.format("%g, %g", math.pi, 10^9) -- liukuluku tai eksponentti
   tex.print(str.."\\par")
   str = string.format("%o, %x, %X", 99, 125, 125)  -- oktaali, heksadesimaali, heksadesimaali
   tex.print(str.."\\par")

   tex.print("\\vskip3mm".."Käyttäen string.gmatch():".."\\par")

   for word in string.gmatch("Hei TeX-käyttäjä", "%a+") do
      tex.print(word.."\\par")
   end

   tex.print("\\vskip3mm".."Käyttäen string.gsub():".."\\par")
   str=string.gsub("banana", "(an)", "%1-") -- sieppaa kaikki "an"-esiintymät ja korvaa
   tex.print(str.."\\par")
}
\endgroup
\end{document}
```

Seuraava kuvakaappaus näyttää yllä olevan koodin ladotun tuloksen:

![Lua-merkkijonofunktioiden käyttäminen \directlua:ssa](/files/29cedbb08b44faec29caff57fe8bb7a6444e7db7)

## Miksi Lua-koodi näytetään yhtenä rivinä?

Kuten olet ehkä huomannut, kaikki tässä artikkelissa esitetyissä esimerkeissä näkyvät (luodut) Lua-koodinpätkät esitetään yhtenä tekstirivinä: alun perin `\directlua` koodikatkelmissa olleita rivinvaihtoja ei noudateta. Miksi näin? Siksi, että Lua-koodin rivinvaihdot on *poistettu* LuaTeXin esikäsittelyssä `\directlua`, jolloin Lua-koodista tulee yksi pitkä tekstirivi. Tämä käyttäytyminen johtuu tavasta, jolla TeX-moottorit käsittelevät rivinlopun merkkejä — joita merkitään `\r` (koodilla CR, carriage return) ja `\n` (koodilla LF, line feed) ohjelmointikirjallisuudessa. Miksi meidän täytyy välittää näistä pienistä yksityiskohdista, käy selväksi, kun käsittelemme Lua:n mekanismien käyttämistä koodiosien kommentoimiseen.

Kun ohjelmisto kirjoittaa (tallentaa) tekstitiedoston, jokainen yksittäinen tekstirivi päättyy niin sanottuihin “newline”-merkkeihin — varsinaiset rivinvaihtomerkit riippuvat sovelluksesta ja käyttöjärjestelmästä, jota kyseisen tiedoston kirjoittamiseen käytetään. Wikipediassa on [kiinnostava artikkeli](https://en.wikipedia.org/wiki/Newline) jossa tarkastellaan nykyään käytössä olevien rivinvaihtomerkkien historiaa ja kehitystä.

Missä tahansa tekstitiedostossa yksittäiset tekstirivit voivat päättyä eri merkkien yhdistelmiin, joita kutsutaan carriage returniksi (ASCII/Unicode-merkki 13) ja/tai line feediksi (ASCII/Unicode-merkki 10), joita merkitään `\r` ja `\n` vastaavasti. Koska TeX-moottorit on suunniteltu alustariippumattomiksi, ne tarvitsevat menetelmän kiertää tekstitiedostojen rivinpäätteiden luontaisesti alustariippuvainen luonne. Luonnollisesti TeX-moottoreilla on sisäänrakennettu (mutta muokattava) menetelmä rivinlopun merkkien käsittelyyn.

### Miten TeX-moottorit käsittelevät rivinpäätteitä

Kun LuaTeX käsittelee `\directlua{⟨koodi⟩}` se lukee tekstin, joka on tiedostossasi `⟨koodi⟩` ja soveltaa TeX-moottorin vakiomenetelmiä tiedostossasi olevien rivinpäätteiden käsittelyyn `⟨koodi⟩`. Oletusarvoisesti nämä TeXin vakiomenetelmät poistavat kaikki rivinlopun merkit (carriage returnit ja line feedit) ja korvaavat ne välilyönneillä. Sanomme “oletusarvoisesti”, koska TeX-moottorin tapaa käsitellä rivinlopun merkkejä voidaan muuttaa käyttäjän määritettävissä olevan parametrin avulla nimeltä `\endlinechar`. Tässä tarjoamme lyhyen kaksivaiheisen yleiskatsauksen, mutta lisätietoja löytyy Overleaf-artikkelista [Johdatus \endlinechar-komentoon: Miten TeX lukee rivejä tekstitiedostoista](/latex/fi/syvalliset-artikkelit/05-an-introduction-to-endlinechar-how-tex-reads-lines-from-text-files.md).

#### Vaihe 1: TeX lisää oman rivinlopun merkkinsä

Luettuaan tekstirivin syöttötiedostostasi TeX-moottorit poistavat välittömästi kaikki `\r` tai `\n` merkit kyseisen rivin lopusta. Seuraavaksi TeX-moottorit *lisäävät* (lisäävät takaisin) oman rivinlopun merkkinsä kyseisen rivin loppuun. Tuo merkki määräytyy käyttäjän määritettävissä olevan TeX-parametrin arvon mukaan, jota kutsutaan `\endlinechar` ja tämän mekanismin kautta TeX-moottorit voivat käsitellä rivinlopun merkkejä alustariippumattomasti: ne valitsevat ja asettavat rivinlopun merkin riippumatta siitä, mitä syöttötekstitiedostossa alun perin oli.

Yleensä TeX-moottorit käyttävät asetusta

`\endlinechar=13`

joka on carriage return -merkki (`\r`). Käyttäjät voivat kuitenkin aina asettaa jonkin muun merkkikoodin arvoksi `\endlinechar`—minkä näemme myöhemmin tässä artikkelissa.

Näin ollen kaikki rivinlopun merkit, jotka ovat `⟨koodi⟩` käsiteltävinä `\directlua{⟨koodi⟩}` poistetaan ja korvataan yhdellä TeX-moottorin itsensä määrittämällä merkillä. Huomaa, että TeX-moottorit suorittavat tämän rivinlopun käsittelyn heti luettuaan uuden tekstirivin tiedostosta ja *ennen kuin* käsitellen siinä rivissä olevat merkit (tunnusten luomiseksi). Tämä ei kuitenkaan ole tarinan loppu: mitä TeX-moottori *ei* tekee näille rivinlopun merkeille (jotka se on lisännyt) selittää, miksi Lua-koodista tulee yksi ainoa rivi.

#### Vaihe 2: TeX muuntaa oman rivinlopun merkkinsä välilyönniksi

Sen lisäksi, että ne lisäävät oman rivinlopun merkkinsä, joka määräytyy arvon `\endlinechar`, TeX-moottorit käyttävät myös kategoriakoodia 5 merkeille, joiden tulee olla *käsitelty* rivinlopun merkkinä. Tämän seurauksena TeX-moottorit toimivat yleensä seuraavasti:

1. rivinlopun merkki, jonka määrittää `\endlinechar`;
2. sama merkki *yleensä* saa kategoriakoodin 5.

Juuri se, mitä TeX tekee tuolle rivinlopun merkille, selittää pulman yksittäisistä Lua-koodiriveistä. Kun TeX-moottori käsittelee syöteriviä, se havaitsee lopulta kyseisen rivin viimeisen merkin: merkin, jonka määrittää `\endlinechar`. Yleensä tuolla merkillä on kategoriakoodi 5, mikä saa TeXin *korvaamaan sen* välilyönnillä: toisin sanoen rivin lopussa TeX käytännössä poistaa rivinlopun merkkinsä ja korvaa sen välilyönnillä. Sivuhuomautuksena: TeX-moottorit käyttävät kategoriakoodin 5 merkkejä myös tyhjien rivien havaitsemiseen ja uuden kappaleen aloittamiseen, mutta emme käsittele sitä tässä.

Totta kai, TeX:n luonteeseen kuuluu, että voit tehdä kaikenlaisia erityisiä makro-ohjelmointikikkoja asettamalla uudelleen `\endlinechar` joksikin muuksi merkiksi ja/tai antamalla merkille, jolle on annettu `\endlinechar` haluamasi kategoriakoodiarvon.

Jos haluat estää Lua-koodin muuttumisen yhdeksi ainoaksi tekstiriviksi, voit joko (tilapäisesti) muuttaa arvon, joka on annettu `\endlinechar` tai muuttaa vakiomuotoisen rivinlopun päätemerkin kategoriakoodia `\r`.

### TeXin erikoinen ^^-merkintä

Seuraavissa osioissa törmäämme TeXin epätavalliseen `^^` merkintään, joka tunnetaan nimellä “laajennettu merkkimekanismi”. Knuth suunnitteli sen helpottamaan “ohjausmerkkien”, kuten rivinlopun päätemerkkien, tabulaattorien ja niin edelleen, kirjoittamista. Esimerkiksi:

* `^^J` edustaa merkkikoodia 10 (`\n`, line feed);
* `^^M` edustaa merkkikoodia 13 (`\r`, carriage return).

Merkkijonot kuten `^^M` muunnetaan vastaaviksi merkkikoodeiksi jo varhaisessa vaiheessa TeXin syöteen skannausprosessissa, kun TeX lukee syötemerkkejä luodakseen vastaavat merkkitunnukset.

### Merkin, jolle on annettu \endlinechar, muuttaminen

Muistaen, että meidän on yhä estettävä `~` merkin laajeneminen, voimme kirjoittaa

```
\begingroup
\endlinechar=10 % Muuta rivinlopun merkki arvoon \n
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x ei ole yhtä suuri kuin 4")
   end
}% en halua \n:n näkyvän tässä
\endgroup% tai \n tähän
```

Yllä oleva asetus `\endlinechar` saa LuaTeXin lisäämään merkkikoodin 10 (`\n`, line feed) jokaisen lukemansa rivin loppuun. Teemme näin, koska `\n` (line feed) -merkillä on yleensä kategoriakoodi 12, minkä voit testata kirjoittamalla ``\the\catcode`\^^J``. Koska `\n` ei omaa kategoriakoodia 5, LuaTeX ei muunna sitä välilyönniksi, joten se pysyy jokaisen LuaTeXin lukeman rivin lopussa. Tämän seurauksena koodin 10 merkki jää jokaisen rivin loppuun ja päätyy siten tunnusluetteloon, jota rakentaa `\directlua` ja ilmestyy myöhemmin uudelleen Lua-koodissa, kun tunnusluettelo muunnetaan tekstiksi. Yllä olevan muutoksen myötä Lua-koodi lähetetään Lua-tulkille seuraavana merkkijonona:

**\n**local x=3\*\*\n**jos x \~= 4 sitten**\n**print("x ei ole yhtä suuri kuin 4")**\n**end**\n\*\*

jossa **\n** merkintä on tarkoitettu edustamaan merkkikoodia 10 *sisällä* jotakin tuntematonta makroa `\n`. Nyt Lua-tulkki näkee koodissa rivinvaihdot täsmälleen niin kuin ne alun perin kirjoitettiin `\directlua` komento:

```
   local x=3
   jos x ~= 4 sitten
   print("x ei ole yhtä suuri kuin 4")
   end
```

Muuten, huomaa, että Lua-koodimerkkijonon aivan ensimmäinen merkki on `\n` (ennen `paikallisen` avainsanaa). Tämä `\n` johtuu rivistä

`\directlua{`

koska heti avaavan `{` jälkeen on rivinvaihto, ja tämäkin säilyy. Sen estämiseksi voit kirjoittaa

`\directlua{%`

### Merkin \r kategoriakoodin muuttaminen

Säilyttääksemme rivinvaihdot Lua-koodissamme voimme myös muuttaa merkin `\r` kategoriakoodin joksikin muuksi kuin 5, jotta `\r` ei enää tunnisteta (käsitellä) rivinlopun merkkinä. Tällä tekniikalla LuaTeX käyttää edelleen `\endlinechar=13` ja lisää edelleen `\r` jokaisen rivin loppuun; kuitenkin, koska `\r` ei enää omaa kategoriakoodia 5, LuaTeX ei tunnista `\r` merkkiä rivinlopun merkiksi: se ei muunna sitä välilyönniksi vaan välittää sen vahingoittumattomana Lua-koodiin.

Muistaen, että meidän on yhä estettävä `~` merkin laajeneminen, voimme kirjoittaa

```
\begingroup
\catcode`\^^M=12 % muuta \r:n kategoriakoodi arvoon 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x ei ole yhtä suuri kuin 4")
   end
}
\endgroup
```

Tässä tapauksessa Lua-koodi lähetetään Lua-tulkille muodossa:

**\r**local x=3\*\*\r**jos x \~= 4 sitten**\r**print("x ei ole yhtä suuri kuin 4")**\r**end**\r\*\*

jossa `\r` merkintä on tarkoitettu edustamaan merkkikoodia 13, ei jotakin tuntematonta makroa `\r`. Kuten `\endlinechar` esimerkissä, Lua-tulkki näkee nyt koodissa rivinvaihdot täsmälleen niin kuin ne alun perin kirjoitettiin `\directlua` komento:

```
   local x=3
   jos x ~= 4 sitten
   print("x ei ole yhtä suuri kuin 4")
   end
```

Huomaa taas, että Lua-koodimerkkijonon aivan ensimmäinen merkki on `\r` (ennen local-avainsanaa): tämäkin johtuu rivistä

`\directlua{`

#### Miksi \r käytti kategoriakoodia 12 mutta ei kategoria koodia 11?

Vastaus liittyy riskiin tuoda vahingossa virheitä, jotka laukeavat `\r` (kategoriakoodin 11) lisääntymisestä syöttötiedostostamme luettujen TeX/LaTeX-komentojen loppuun. Ota tämä esimerkki:

```
\begingroup
\catcode`\^^M=11 % muuta \r:n kategoriakoodi arvoon 11
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x ei ole yhtä suuri kuin 4")
   end
}
\endgroup
```

joka tuottaa virheen:

```
   ! Undefined control sequence.
   l.9 \endgroup
```

Miten se voi olla totta, kun `\endgroup` on vakiomuotoinen TeXin primitiivikomento? Virheen syy on melko hienovarainen: Kun LuaTeX luki tekstin viimeisen rivin — sen, joka sisälsi `\endgroup`— se lisäsi myös `\endlinechar` merkkiä `\r` kyseisen rivin loppuun. Nyt LuaTeX näkee muistissaan merkkijonon

`\endgroup\r`

jossa käytämme `\r` osoittamaan merkkiä, jolla on koodi 13 — ei jonkin tuntemattoman TeX-makron nimeä `\r`.

Sillä hetkellä, kun LuaTeX luki tämän rivin tekstitiedostostamme, alkuperäinen `\begingroup` on yhä toiminnassa: olemme ryhmässä, jota ei ole vielä suljettu suorittamalla vastaavaa `\endgroup` komentoa — mikä saisi `\r` palaamaan takaisin aiempaan kategoriakoodiarvoonsa 5.

Kun LuaTeX alkaa käsitellä (luoda tunnuksia) tekstirivistä `\endgroup\r` se tunnistaa ensimmäisen merkin `\` eskapemerkiksi, joka käynnistää LuaTeXin etsimään komennon nimeä. Komennon nimen tunnistamiseksi LuaTeX etsii merkkijonoa, jolla on kategoriakoodi 11, mutta koska `\r` myös on kategoriakoodi 11, LuaTeX ajattelee, että `\r` merkki (edelleen kategoriakoodilla 11) muodostaa *osan komentoa* nimeltä `\endgroup\r` jota ei tietenkään ole olemassa, joten LuaTeX ilmoittaa `Määrittelemätön ohjaussarja` virheen. Siksi käytimme kategoriakoodia 12 emmekä 11:tä.

Koska LuaTeXin virheilmoitus kirjoitettiin konsoliin, emme voineet helposti nähdä/havaita `\r` merkkiä, joten ei ollut ilmeistä, mikä oli aiheuttanut virheen.

### Miksi murehdimme rivinlopuista?

Syy on, että se mahdollistaa Lua:n kommentointitavan käyttämisen koodissasi! Voit käyttää LuaTeXin vakiomekanismia lisätä `%` merkkejä kommentoimaan yksittäisiä rivejä koodissasi; Lua-kielellä on kuitenkin omat, erittäin hyödylliset *moniriviset* kommentointimekanismit, joista haluat ehkä hyötyä.

Aloitetaan katsomalla, mitä tapahtuu, jos yritämme käyttää yksirivisiä Lua-kielen kommentteja käsittelemättä rivinvaihto-ongelmia. Siinä missä TeX käyttää `%` merkkiä kommentoidakseen yksittäisiä koodirivejä, Lua käyttää kaksoisviivaa: `--`.

Mitä tapahtuu, jos yritämme suorittaa tämän:

```
\directlua{
   local x=3
   if x \noexpand~= 4 then
   -- Aion tulostaa tämän monimutkaisen testin tuloksen
   print("x ei ole yhtä suuri kuin 4")
   end
}
```

Saamme virheen:

`[\directlua]:1: 'end' expected near <eof>`

Tämä virhe johtuu rivinvaihtojen puuttumisesta tulkille välitetyssä Lua-koodissa, joka näkee vain yhden yhtenäisen merkkijonon, jossa kommentti alkaa kesken merkkijonon:

```

local x=3 if x ~= 4 then -- Aion tulostaa tämän monimutkaisen testin tuloksen print("x ei ole yhtä suuri kuin 4") end
```

Kaikki `**local x=3 if x ~= 4 then**` käsitellään kommentoiduksi, mikä saa tulkin näkemään puutteellisen Lua-koodinpätkän ja johtaa virheeseen

`'end' expected near <eof>`.

jossa `<eof>` tarkoittaa tiedoston loppua.

Kuten olet luultavasti arvannut, meidän on korjattava tämä varmistamalla, että rivinvaihdot välittyvät tuloksena syntyvään Lua-koodiin, minkä voimme tehdä esimerkiksi muuttamalla merkin `\r` kategoriakoodiksi 12:

```
\begingroup
\catcode`\^^M=12 % muuta \r:n kategoriakoodi arvoon 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   -- Aion tulostaa tämän monimutkaisen testin tuloksen
   print("x ei ole yhtä suuri kuin 4")
   end
}
\endgroup
```

Nyt Lua-tulkki näkee merkkijonon, mutta se sisältää `\r` rivinvaihtoja sellaisina kuin ne on kirjoitettu `\directlua` katkelmassa:

**\r**local x=3\*\*\r**jos x \~= 4 sitten**\r\*\*-- Aion tulostaa tämän monimutkaisen testin tuloksen\*\*\r**tex.print("x ei ole yhtä suuri kuin 4")**\r**end**\r\*\*

Tämä on käytännössä sama kuin kirjoittaisi

```
   local x=3
   if x \noexpand~= 4 then
   -- Aion tulostaa tämän monimutkaisen testin tuloksen
   print("x ei ole yhtä suuri kuin 4")
   end
```

mikä tarkoittaa, että Lua pystyy käsittelemään tämän koodin oikein ja sivuuttamaan rivin, jonka kommentoimme pois.

**Lohkokommentit**

Lua-kieli tukee myös syntaksia, jota se kutsuu [”lohkokommentiksi”](https://www.lua.org/pil/1.3.html) (tai *pitkä kommentti*): nämä alkavat merkillä `--[[` ja ovat käytännössä voimassa siihen asti, kunnes vastaava `]]`. Tätä kätevää syntaksia voidaan käyttää monirivisten kommenttien kirjoittamiseen tai sellaisten koodiosien kommentoimiseen, jotka haluamme poistaa väliaikaisesti:

```
\begingroup
\catcode`\^^M=12 % muuta \r:n kategoriakoodi arvoon 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   --[[ Aion tulostaa tämän monimutkaisen testin tuloksen
   yksinkertaisesti siksi, että se todella on
   niin upea johtopäätös]]
   print("x ei ole yhtä suuri kuin 4")
   end
}
\endgroup
```

## Yhteenvetona

Ensinnäkin, onnittelut, jos olet jaksanut lukea tämän laajan artikkelin läpi! Olemme pyrkineet tuottamaan melko kattavan oppaan TeXiin liittyvistä käsitteistä ja aiheista, jotka tarjoavat taustan, jota tarvitaan, jotta LuaTeXistä saa parhaan hyödyn tämän `\directlua` komennon. Toivomme, että olemme tuottaneet artikkelin, joka on opettavainen ja tuo jotain hyödyllistä ja arvokasta Overleafin käyttäjäyhteisölle ja sen ulkopuolellekin. Kuten aina, otamme mielellämme palautetta vastaan, joten ota rohkeasti [ota yhteyttä](https://www.overleaf.com/contact) kommentteja tästä artikkelista tai ehdotuksia aiheista, joista haluaisit meidän kirjoittavan lisää.

Mukavia $$\text{Lua}\mathrm{\TeX}\text{-ing!}$$ Graham Douglasilta ja Overleaf-tiimiltä.

### Ja lopuksi... käytä vain luacode-pakettia

Vaikka TeX ja Lua toimivat perustavanlaatuisesti eri tavoilla, näillä kielillä on useita merkkejä, joilla on ”erityisiä merkityksiä” kunkin kielen kontekstissa—kuten \\, %, \~, #, ^, &—tietenkin Lua ja TeX antavat näille erityismerkityksille *erittäin* eri tarkoitukset. Tutkimuksemme ongelmallisista merkeistä osoittaa, miksi vaikeuksia voi syntyä ja miten ne voi ratkaista; kuitenkin monien pienten Lua-koodikatkelmien korjaaminen käsin saattaa olla varsin työlästä, joten useimmat käyttäjät suosivat LaTeX-paketteja, jotka poistavat nämä haasteet. Yksi tällainen paketti on [`luacode`](https://ctan.org/pkg/luacode?lang=en) joka tarjoaa joukon ominaisuuksia, jotka on suunniteltu helpottamaan työskentelyä `\directlua`, mutta ainakin sinulla saattaa nyt olla parempi ymmärrys ongelmista `luacode` jotka se ratkaisee puolestasi.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/fi/syvalliset-artikkelit/09-an-introduction-to-luatex-part-2-understanding-directlua.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
