Obsah
1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (5 – tabulky a pole)
2.1 Zdrojový kód příkladu test24.lua
2.2 Překlad příkladu test24.lua do mezijazyka LuaJITu
3. Demonstrační příklad test25.lua – vytvoření a inicializace neprázdné tabulky
3.1 Zdrojový kód příkladu test25.lua
3.2 Překlad příkladu test25.lua do mezijazyka LuaJITu
4. Demonstrační příklad test26.lua – přidání prvků do tabulky s využitím (konstantních) indexů
4.1 Zdrojový kód příkladu test26.lua
4.2 Překlad příkladu test26.lua do mezijazyka LuaJITu
5. Demonstrační příklad test27.lua – přidání prvků do tabulky s využitím (konstantních) klíčů
5.1 Zdrojový kód příkladu test27.lua
5.2 Překlad příkladu test27.lua do mezijazyka LuaJITu
6.1 Zdrojový kód příkladu test28.lua
6.2 Překlad příkladu test28.lua do mezijazyka LuaJITu
7. Demonstrační příklad test29.lua – práce s dvourozměrnými tabulkami (maticemi)
7.1 Zdrojový kód příkladu test29.lua
7.2 Překlad příkladu test29.lua do mezijazyka LuaJITu
8. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů
1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (5 – tabulky a pole)
V programovacím jazyce Lua jsou nejdůležitějším strukturovaným datovým typem tabulky (table). Tento datový typ lze použít jak pro implementaci pole (array) s prvky adresovanými s využitím celočíselných indexů, tak i pro implementaci asociativního pole, kdy jsou namísto celočíselných indexů použity klíče, které jsou typicky reprezentovány řetězci (není to však nutné). V jazyku Lua je interní struktura tabulek implementována takovým způsobem, aby byla práce s tabulkami efektivní jak při použití celočíselných indexů, tak i při použití klíčů. Není tedy divu, že jsou tabulky použity v prakticky všech aplikacích a navíc i samotná Lua tabulky interně poměrně často využívá – příkladem může být například známá globální tabulka _G. Potřeba práce s tabulkami je samozřejmě reflektována i v mezijazyku (IR) LuaJITu. Všechny instrukce, které nějakým způsobem s tabulkami pracují, lze rozdělit do čtyř skupin:
# | Funkce | Seznam instrukcí |
---|---|---|
1 | vytvoření nové tabulky | TNEW, TDUP |
2 | práce s globální tabulkou _G | GGET, GSET |
3 | čtení prvků z tabulky | TGETV, TGETS, TGETB |
4 | zápis prvku do tabulky | TSETV, TSETS, TSETB, TSETM |
V tabulce zobrazené pod tímto odstavcem jsou všechny základní instrukce IR, které se týkají práce s tabulkami, vypsány společně s podrobnějším popisem i s použitými operandy:
# | Instrukce | Operandy (A,B,C/D) | Popis |
---|---|---|---|
1 | TNEW | dst, lit | vytvoření nové tabulky o velikosti specifikované v D (lit), reference na vytvořenou tabulku se uloží do A (dst) |
2 | TDUP | dst, tab | vytvoření nové tabulky na základě šablony specifikované v D (tab), reference na vytvořenou tabulku se uloží do A (dst) |
3 | GGET | dst, str | přečtení prvku z globální tabulky _G, v D (str) je uložen klíč (řetězec) |
4 | GSET | var, str | zápis prvku do globální tabulky _G, v D (str) je uložen klíč (řetězec) |
5 | TGETV | dst, var, var | čtení prvku z tabulky specifikované v B, klíč je uložen v proměnné |
6 | TGETS | dst, var, str | čtení prvku z tabulky specifikované v B, klíčem je řetězec |
7 | TGETB | dst, var, lit | čtení prvku z tabulky specifikované v B, klíčem je literál (konstanta, typicky celé číslo) |
8 | TSETV | var, var, var | zápis prvku do tabulky specifikované v B, klíč je uložen v proměnné |
9 | TSETS | var, var, str | zápis prvku do tabulky specifikované v B, klíčem je řetězec |
10 | TSETB | var, var, lit | zápis prvku do tabulky specifikované v B, klíčem je literál (konstanta, typicky celé číslo) |
11 | TSETM | base, num* | nastavení většího množství prvků dle vztahu: (A-1)[D], (A-1)[D+1], … = A, A+1, … |
S instrukcemi GGET a GSET jsme se již v několika demonstračních příkladech setkali, protože se s využitím těchto instrukcí mj. pracuje i s „globálními“ funkcemi, tj. funkcemi, které nejsou anonymní a nejsou uloženy do uživatelsky definované tabulky. Většinu dalších instrukcí s výjimkou poněkud speciální instrukce TSETM si popíšeme v navazujících kapitolách.
2. Demonstrační příklad test24.lua – vytvoření prázdné tabulky, zjištění počtu prvků tabulky, přístup k prvkům tabulky
V dnešním prvním demonstračním příkladu nazvaném test24.lua jsou ukázány čtyři základní jazykové konstrukce podporované programovacím jazykem Lua, které se používají při práci s tabulkami. Jedná se o konstrukci pro vytvoření prázdné tabulky (jednorozměrného pole – vektoru), dále o tisk informace o celé tabulce (vytiskne se hodnota reference), tisk počtu prvků v tabulce (platí jen pro klasická pole, nikoli pro asociativní pole) a samozřejmě též i o konstrukci sloužící pro získání hodnoty konkrétního prvku v tabulce na základě jeho indexu. Připomeňme si, že v Lue se prvky číslují od jedničky a nikoli od nuly:
2.1 Zdrojový kód příkladu test24.lua
-- -- LuaJIT: demonstrační příklad číslo 24 -- -- Práce s tabulkami: -- * vytvoření prázdné tabulky -- * tisk poctu prvku tabulky -- * přístup k prvkům tabulky -- -- vytvoření prázdné tabulky local tbl = {} -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce print(#tbl) -- tisk hodnoty prvního prvku v tabulce print(tbl[1]) -- tisk hodnoty desátého prvku v tabulce print(tbl[10]) -- finito
2.2 Překlad příkladu test24.lua do mezijazyka LuaJITu
Při pohledu na IR získaný překladem demonstračního příkladu test24.lua do mezijazyka LuaJITu můžeme získat základní představu o tom, jak se v IR s tabulkami pracuje. Pro vytvoření prázdné tabulky se používá instrukce TNEW, které se předají rozměry tabulky a index slotu, do kterého se uloží reference na vytvořenou tabulku. Pro výpočet počtu prvků tabulky se používá instrukce LEN a pro přečtení hodnoty konkrétního prvku uloženého na určitém indexu lze použít instrukci TGETB. Posledním operandem této instrukce je index čteného prvku:
; Překlad demonstračního příkladu test24.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test24.lua:0-31 ; vytvoření prázdné tabulky ; local tbl = {} 0001 TNEW 0 0 ; vytvoření nové prázdné tabulky ; tisk informace o tabulce (reference...) ; print(tbl) 0002 GGET 1 0 ; získání reference na funkci se jménem "print" 0003 MOV 2 0 ; bude se tisknout reference na tabulku 0004 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků v tabulce ; print(#tbl) 0005 GGET 1 0 ; získání reference na funkci se jménem "print" 0006 LEN 2 0 ; získání počtu prvků tabulky (resp. pole, které je součástí tabulky) 0007 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty prvního prvku v tabulce ; print(tbl[1]) 0008 GGET 1 0 ; získání reference na funkci se jménem "print" 0009 TGETB 2 0 1 ; přečtení hodnoty prvního prvku tabulky 0010 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty desátého prvku v tabulce ; print(tbl[10]) 0011 GGET 1 0 ; získání reference na funkci se jménem "print" 0012 TGETB 2 0 10 ; přečtení hodnoty desátého prvku tabulky 0013 CALL 1 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0014 RET0 0 1 ; konec
3. Demonstrační příklad test25.lua – vytvoření a inicializace neprázdné tabulky
Kromě vytvoření prázdné tabulky je možné v programovacím jazyku Lua vytvořit novou tabulku a současně provést i inicializaci jejích prvků. Pro tento účel se v nejjednodušším případě používá konstrukce local tbl = {hodnota1, hodnota2, hodnota3, …}. Vzhledem k tomu, že se jedná o velmi často používanou jazykovou konstrukci, lze očekávat, že bude nějakým způsobem podporována i v IR LuaJITu, takže nezbývá, než si vše otestovat:
3.1 Zdrojový kód příkladu test25.lua
-- -- LuaJIT: demonstrační příklad číslo 25 -- -- Práce s tabulkami: -- * vytvoření a inicializace neprázdné tabulky -- * tisk poctu prvku tabulky -- * přístup k prvkům tabulky -- -- vytvoření desetiprvkové tabulky local tbl = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1} -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce print(#tbl) -- tisk hodnoty prvního prvku v tabulce print(tbl[1]) -- tisk hodnoty desátého prvku v tabulce print(tbl[10]) -- finito
3.2 Překlad příkladu test25.lua do mezijazyka LuaJITu
Pohled na IR demonstračního příkladu test25.lua přeloženého do mezijazyka LuaJITu nám ukáže, že se IR prakticky nijak zásadně neliší od IR předchozího příkladu nazvaného test24.lua. Jediným rozdílem je zde použití instrukce TDUP namísto instrukce TNEW. Zatímco TNEW slouží pro vytvoření prázdné tabulky zadané velikosti, je TDUP interně mnohem komplikovanější, protože vytvoří a inicializuje novou tabulku na základě zadané šablony, která je uložena v obdobě constant poolu. Díky existenci této instrukce je tedy možné IR značným způsobem zkrátit, především v porovnání s některými populárními bajtkódy, které mnohdy inicializaci tabulek neřeší optimálním způsobem:
; Překlad demonstračního příkladu test25.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test25.lua:0-31 ; vytvoření a inicializace desetiprvkové tabulky ; local tbl = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1} 0001 TDUP 0 0 ; pozor - rozdíl oproti předchozímu příkladu ; tisk informace o tabulce (reference...) ; print(tbl) 0002 GGET 1 1 ; získání reference na funkci se jménem "print" 0003 MOV 2 0 ; bude se tisknout reference na tabulku 0004 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků v tabulce ; print(#tbl) 0005 GGET 1 1 ; získání reference na funkci se jménem "print" 0006 LEN 2 0 ; získání počtu prvků tabulky (resp. pole, které je součástí tabulky) 0007 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty prvního prvku v tabulce ; print(tbl[1]) 0008 GGET 1 1 ; získání reference na funkci se jménem "print" 0009 TGETB 2 0 1 ; přečtení hodnoty prvního prvku tabulky 0010 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty desátého prvku v tabulce ; print(tbl[10]) 0011 GGET 1 1 ; získání reference na funkci se jménem "print" 0012 TGETB 2 0 10 ; přečtení hodnoty desátého prvku tabulky 0013 CALL 1 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0014 RET0 0 1 ; konec
4. Demonstrační příklad test26.lua – přidání prvků do tabulky s využitím (konstantních) indexů
V dnešním třetím demonstračním příkladu si vyzkoušíme, jakým způsobem se v mezijazyku LuaJITu řeší situace, kdy je nutné změnit či nastavit hodnotu prvku uloženého na určitém indexu. Opět se jedná o velmi často používanou jazykovou konstrukci, přičemž se velmi často setkáme s použitím relativně malých tabulek s indexy prvků od jedničky do 256. A právě k prvkům takto malých tabulek lze přistupovat velmi efektivním způsobem, což bude patrné z výpisu IR:
4.1 Zdrojový kód příkladu test26.lua
-- -- LuaJIT: demonstrační příklad číslo 26 -- -- Práce s tabulkami: -- * vytvoření a inicializace prázdné tabulky -- * přidání prvku do tabulky s použitím indexu -- * tisk poctu prvku tabulky -- * přístup k prvkům tabulky -- -- vytvoření prázdné tabulky local tbl = {} -- nastavit hodnotu prvního prvku tabulky tbl[1] = 777 -- nastavit hodnotu druhého prvku tabulky tbl[2] = 999 -- nastavit hodnotu desátého prvku tabulky tbl[10] = 1000 -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce print(#tbl) -- tisk hodnoty prvního prvku v tabulce print(tbl[1]) -- tisk hodnoty druhého prvku v tabulce print(tbl[2]) -- tisk hodnoty desátého prvku v tabulce print(tbl[10]) -- finito
4.2 Překlad příkladu test26.lua do mezijazyka LuaJITu
Po překladu demonstračního příkladu test26.lua do mezijazyka LuaJITu je patrné, jakým způsobem se zápis prvků do tabulky přeložil. Můžeme zde vidět dvojici instrukcí KSHORT+TSETB. První z těchto instrukcí uloží celočíselnou konstantu do vybraného slotu, druhá instrukce tuto konstantu zapíše do tabulky na určený index. Povšimněte si toho, že poslední operand instrukce TSETB přímo obsahuje index zapisovaného prvku, druhý operand obsahuje referenci na tabulku a operand první pak index slotu, v němž je uložena zapisovaná hodnota:
; Překlad demonstračního příkladu test26.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test26.lua:0-44 ; vytvoření prázdné tabulky ; local tbl = {} 0001 TNEW 0 0 ; nastavit hodnotu prvního prvku tabulky ; tbl[1] = 777 0002 KSHORT 1 777 ; ukládaná konstanta 0003 TSETB 1 0 1 ; nastavení prvního prvku tabulky ; nastavit hodnotu druhého prvku tabulky ; tbl[2] = 999 0004 KSHORT 1 999 ; ukládaná konstanta 0005 TSETB 1 0 2 ; nastavení druhého prvku tabulky ; nastavit hodnotu desátého prvku tabulky ; tbl[10] = 1000 0006 KSHORT 1 1000 ; ukládaná konstanta 0007 TSETB 1 0 10 ; nastavení desátého prvku tabulky ; tisk informace o tabulce (reference...) ; print(tbl) 0008 GGET 1 0 ; získání reference na funkci se jménem "print" 0009 MOV 2 0 ; bude se tisknout reference na tabulku 0010 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků v tabulce ; print(#tbl) 0011 GGET 1 0 ; získání reference na funkci se jménem "print" 0012 LEN 2 0 ; získání počtu prvků tabulky (resp. pole, které je součástí tabulky) 0013 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty prvního prvku v tabulce ; print(tbl[1]) 0014 GGET 1 0 ; získání reference na funkci se jménem "print" 0015 TGETB 2 0 1 ; přečtení hodnoty prvního prvku tabulky 0016 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty druhého prvku v tabulce ; print(tbl[2]) 0017 GGET 1 0 ; získání reference na funkci se jménem "print" 0018 TGETB 2 0 2 ; přečtení hodnoty druhého prvku tabulky 0019 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty desátého prvku v tabulce ; print(tbl[10]) 0020 GGET 1 0 ; získání reference na funkci se jménem "print" 0021 TGETB 2 0 10 ; přečtení hodnoty desátého prvku tabulky 0022 CALL 1 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0023 RET0 0 1 ; konec
5. Demonstrační příklad test27.lua – přidání prvků do tabulky s využitím (konstantních) klíčů
Kromě celočíselných indexů lze pro adresování ukládaných či čtených prvků použít i klíče jiného typu. Velmi často se v programovacím jazyku Lua používají klíče typu řetězec (string), takže není divu, že přímo v mezijazyku existují instrukce umožňující manipulaci s prvky tabulky určenými právě s využitím řetězců, přesněji řečeno s využitím řetězcových literálů (konstant). Podívejme se na jednoduchý příklad:
5.1 Zdrojový kód příkladu test27.lua
-- -- LuaJIT: demonstrační příklad číslo 27 -- -- Práce s tabulkami: -- * vytvoření a inicializace prázdné tabulky -- * přidání prvku do tabulky s použitím klíčů -- * tisk poctu prvku tabulky -- * přístup k prvkům tabulky -- -- vytvoření prázdné tabulky local tbl = {} -- nastavit hodnotu prvku tabulky tbl["first"] = 777 -- nastavit hodnotu prvku tabulky tbl["second"] = 999 -- nastavit hodnotu prvku tabulky tbl["tenth"] = 1000 -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce print(#tbl) -- tisk hodnoty prvního prvku v tabulce print(tbl["first"]) -- tisk hodnoty druhého prvku v tabulce print(tbl["second"]) -- tisk hodnoty desátého prvku v tabulce print(tbl["tenth"]) -- finito
5.2 Překlad příkladu test27.lua do mezijazyka LuaJITu
Ve zdrojovém kódu demonstračního příkladu test27.lua jsme viděli použití jazykové konstrukce pro zápis prvku do tabulky i pro čtení prvku z tabulky, přičemž pro adresování prvků byl použit řetězcový literál. Tyto dvě konstrukce se do mezijazyka LuaJITu přeloží s využitím instrukcí TSETS a TGETS, kde S na konci jména těchto instrukcí samozřejmě znamená „string“. Tyto instrukce tedy namísto přímého indexu prvku obsahují index do tabulky konstantních řetězců, což znamená, že mnoho operací s asociativními poli je přeloženo velmi efektivním způsobem:
; Překlad demonstračního příkladu test27.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test27.lua:0-44 ; vytvoření prázdné tabulky ; local tbl = {} 0001 TNEW 0 0 ; nastavit hodnotu prvního prvku tabulky ; tbl["first"] = 777 0002 KSHORT 1 777 ; ukládaná konstanta 0003 TSETS 1 0 0 ; uložení hodnoty pod klíčem "first" ; nastavit hodnotu druhého prvku tabulky ; tbl["second"] = 999 0004 KSHORT 1 999 ; ukládaná konstanta 0005 TSETS 1 0 1 ; uložení hodnoty pod klíčem "second" ; nastavit hodnotu desátého prvku tabulky ; tbl["tenth"] = 1000 0006 KSHORT 1 1000 ; ukládaná konstanta 0007 TSETS 1 0 2 ; uložení hodnoty pod klíčem "tenth" ; tisk informace o tabulce (reference...) ; print(tbl) 0008 GGET 1 3 ; získání reference na funkci se jménem "print" 0009 MOV 2 0 ; bude se tisknout reference na tabulku 0010 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků v tabulce ; print(#tbl) 0011 GGET 1 3 ; získání reference na funkci se jménem "print" 0012 LEN 2 0 ; získání počtu prvků tabulky (resp. pole, které je součástí tabulky) 0013 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty prvního prvku v tabulce ; print(tbl["first"]) 0014 GGET 1 3 ; získání reference na funkci se jménem "print" 0015 TGETS 2 0 0 ; přečtení prvku uloženého pod klíčem "first" 0016 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty druhého prvku v tabulce ; print(tbl["second"]) 0017 GGET 1 3 ; získání reference na funkci se jménem "print" 0018 TGETS 2 0 1 ; přečtení prvku uloženého pod klíčem "second" 0019 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty desátého prvku v tabulce ; print(tbl["tenth"]) 0020 GGET 1 3 ; získání reference na funkci se jménem "print" 0021 TGETS 2 0 2 ; přečtení prvku uloženého pod klíčem "tenth" 0022 CALL 1 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0023 RET0 0 1 ; konec
6. Demonstrační příklad test28.lua – přidání prvků do tabulky s využitím proměnných namísto konstantních indexů či klíčů
Existuje ještě jeden způsob adresování prvků uložených v tabulkách – namísto celočíselných konstant či řetězcových literálů se totiž může použít hodnota uložená do proměnné, ať již se jedná o celočíselnou hodnotu či o řetězec či hodnotu jiného typu (kromě nil). I tuto jazykovou konstrukci musí být LuaJIT schopen přeložit do mezijazyka, ovšem nemůže přitom využít ani dvojici TSETB+TGETB ani dvojici TSETS+TGETS:
6.1 Zdrojový kód příkladu test28.lua
-- -- LuaJIT: demonstrační příklad číslo 28 -- -- Práce s tabulkami: -- * vytvoření a inicializace prázdné tabulky -- * přidání prvku do tabulky s použitím proměnných namísto klíčů -- * tisk poctu prvku tabulky -- * přístup k prvkům tabulky -- -- vytvoření prázdné tabulky local tbl = {} -- inicializace proměnných použitých jako klice local key1 = "first" local key2 = 2 local key3 = "tenth" -- nastavit hodnotu prvku tabulky -- s využitím indexu či klice uloženého v proměnné tbl[key1] = 777 -- nastavit hodnotu prvku tabulky -- s využitím indexu či klice uloženého v proměnné tbl[key2] = 999 -- nastavit hodnotu prvku tabulky -- s využitím indexu či klice uloženého v proměnné tbl[key3] = 1000 -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce print(#tbl) -- tisk hodnoty prvku v tabulce -- s využitím indexu či klice uloženého v proměnné print(tbl[key1]) -- tisk hodnoty prvku v tabulce -- s využitím indexu či klice uloženého v proměnné print(tbl[key2]) -- tisk hodnoty prvku v tabulce -- s využitím indexu či klice uloženého v proměnné print(tbl[key3]) -- finito
6.2 Překlad příkladu test28.lua do mezijazyka LuaJITu
Podívejme se nyní na překlad demonstračního příkladu test28.lua do mezijazyka LuaJITu. Můžeme zde vidět novou dvojici instrukcí TSETV a TGETV, kde V na konci jmen těchto instrukcí samozřejmě značí „variable“. Tyto dvě instrukce se použijí při zápisu resp. při čtení hodnoty libovolného prvku tabulky v případě, kdy není možné pro adresaci použít ani celé číslo, ani řetězcový literál. Operandy obou instrukcí jsou tři – index čteného/zapisovaného slotu, index slotu obsahujícího referenci na tabulku a konečně index slotu obsahujícího hodnotu použitou jako index či jako klíč:
; Překlad demonstračního příkladu test28.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test28.lua:0-55 ; vytvoření prázdné tabulky ; local tbl = {} 0001 TNEW 0 0 ; inicializace proměnných použitých jako klíče ; local key1 = "first" 0002 KSTR 1 0 ; řetězec "first" ; local key2 = 2 0003 KSHORT 2 2 ; ukládaná konstanta ; local key3 = "tenth" 0004 KSTR 3 1 ; řetězec "tenth" ; nastavit hodnotu prvku tabulky ; s využitím indexu či klíče uloženého v proměnné ; tbl[key1] = 777 0005 KSHORT 4 777 ; ukládaná konstanta 0006 TSETV 4 0 1 ; uložení hodnoty do tabulky ; nastavit hodnotu prvku tabulky ; s využitím indexu či klíče uloženého v proměnné ; tbl[key2] = 999 0007 KSHORT 4 999 ; ukládaná konstanta 0008 TSETV 4 0 2 ; uložení hodnoty do tabulky ; nastavit hodnotu prvku tabulky ; s využitím indexu či klíče uloženého v proměnné ; tbl[key3] = 1000 0009 KSHORT 4 1000 ; ukládaná konstanta 0010 TSETV 4 0 3 ; uložení hodnoty do tabulky ; tisk informace o tabulce (reference...) ; print(tbl) 0011 GGET 4 2 ; získání reference na funkci se jménem "print" 0012 MOV 5 0 ; bude se tisknout reference na tabulku 0013 CALL 4 1 2 ; volání funkce print() ; tisk poctu prvku v tabulce ; print(#tbl) 0014 GGET 4 2 ; získání reference na funkci se jménem "print" 0015 LEN 5 0 ; získání počtu prvků tabulky (resp. pole, které je součástí tabulky) 0016 CALL 4 1 2 ; volání funkce print() ; tisk hodnoty prvku v tabulce ; s využitím indexu či klíče uloženého v proměnné ; print(tbl[key1]) 0017 GGET 4 2 ; získání reference na funkci se jménem "print" 0018 TGETV 5 0 1 ; přečtení prvku z tabulky 0019 CALL 4 1 2 ; volání funkce print() ; tisk hodnoty prvku v tabulce ; s využitím indexu či klíče uloženého v proměnné ; print(tbl[key2]) 0020 GGET 4 2 ; získání reference na funkci se jménem "print" 0021 TGETV 5 0 2 ; přečtení prvku z tabulky 0022 CALL 4 1 2 ; volání funkce print() ; tisk hodnoty prvku v tabulce ; s využitím indexu či klíče uloženého v proměnné ; print(tbl[key3]) 0023 GGET 4 2 ; získání reference na funkci se jménem "print" 0024 TGETV 5 0 3 ; přečtení prvku z tabulky 0025 CALL 4 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0026 RET0 0 1 ; konec
7. Demonstrační příklad test29.lua – práce s dvourozměrnými tabulkami (maticemi)
Kromě jednorozměrných tabulek je v programovacím jazyce Lua samozřejmě možné pracovat i s tabulkami, které mají vetší počet dimenzí. Velmi časté bývá použití dvourozměrných tabulek neboli matic. Z hlediska programovacího jazyka Lua je práce s vícerozměrnými tabulkami snadná, ovšem zajímavé bude zjistit, jakým způsobem se příkazy pro čtení a zápis prvků přeloží do mezijazyka LuaJITu. K otestování základních vlastností IR nám bude sloužit poměrně jednoduchý demonstrační příklad, v němž je nejdříve vytvořena matice a následně se přistupuje jak k jednotlivým řádkům této matice, tak i k prvkům uloženým v matici (přesněji řečeno na vybraném řádku).
7.1 Zdrojový kód příkladu test29.lua
-- -- LuaJIT: demonstrační příklad číslo 29 -- -- Práce s tabulkami: -- * vytvoření a inicializace dvourozměrné tabulky -- * vložení podtabulek do "hlavni" tabulky -- * přístup k prvkům matice -- -- vytvoření a inicializace dvourozměrné local tbl = { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} } -- tisk informace o tabulce (reference...) print(tbl) -- tisk poctu prvku v tabulce (nejvyšší dimenze) print(#tbl) -- tisk poctu prvku v prvním řádku tabulky (nižší dimenze) print(#tbl[1]) -- tisk poctu prvku ve druhem řádku tabulky (nižší dimenze) print(#tbl[2]) -- tisk poctu prvku ve třetím řádku tabulky (nižší dimenze) print(#tbl[3]) -- tisk hodnoty vybraného prvku v dvourozměrné tabulce print(tbl[1][1]) -- tisk hodnoty vybraného prvku v dvourozměrné tabulce print(tbl[3][4]) -- finito
7.2 Překlad příkladu test29.lua do mezijazyka LuaJITu
V IR přeloženého příkladu test29.lua můžeme vidět hned několik nových technik. První z nich se týká vytvoření a inicializace dvourozměrné tabulky, což je již operace, kterou nelze vykonat jedinou instrukcí TNEW, ale je nutné ještě explicitně vytvořit jednotlivé řádky matice:
; Překlad demonstračního příkladu test29.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test29.lua:0-42 ; vytvoření a inicializace dvourozměrné tabulky ; local tbl = { 0001 TNEW 0 4 ; { 1, 2, 3, 4}, 0002 TDUP 1 0 0003 TSETB 1 0 1 ; { 5, 6, 7, 8}, 0004 TDUP 1 1 0005 TSETB 1 0 2 ; { 9, 10, 11, 12} 0006 TDUP 1 2 0007 TSETB 1 0 3 ; }
Tisk souhrnných informací o tabulce zůstává stejný, nezávisle na tom, zda se jedná o jednorozměrný vektor či o dvourozměrnou matici. Stejný je i způsob zjištění počtu prvků v tabulce, což zde znamená počet řádků matice:
; tisk informace o tabulce (reference...) ; print(tbl) 0008 GGET 1 3 ; získání reference na funkci se jménem "print" 0009 MOV 2 0 0010 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků v tabulce (nejvyšší dimenze) ; print(#tbl) 0011 GGET 1 3 ; získání reference na funkci se jménem "print" 0012 LEN 2 0 ; výpočet velikosti tabulky (nejvyšší dimenze) 0013 CALL 1 1 2 ; volání funkce print()
Zajímavější je již přístup k jednotlivým řádkům matice, protože každý řádek je vlastně prvkem nadřazené tabulky. Totéž platí i při přístupu ke konkrétním prvkům matice, kde je nutné použít dvojici instrukcí TGETB – první pro získání reference na řádek, druhou pro přečtení prvku z tohoto řádku:
; tisk počtu prvků v prvním řádku tabulky (nižší dimenze) ; print(#tbl[1]) 0014 GGET 1 3 ; získání reference na funkci se jménem "print" 0015 TGETB 2 0 1 ; načtení celého řádku tabulky 0016 LEN 2 2 ; výpočet délky jednoho řádku tabulky 0017 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků ve druhem řádku tabulky (nižší dimenze) ; print(#tbl[2]) 0018 GGET 1 3 ; získání reference na funkci se jménem "print" 0019 TGETB 2 0 2 ; načtení celého řádku tabulky 0020 LEN 2 2 ; výpočet délky jednoho řádku tabulky 0021 CALL 1 1 2 ; volání funkce print() ; tisk počtu prvků ve třetím řádku tabulky (nižší dimenze) ; print(#tbl[3]) 0022 GGET 1 3 ; získání reference na funkci se jménem "print" 0023 TGETB 2 0 3 ; načtení celého řádku tabulky 0024 LEN 2 2 ; výpočet délky jednoho řádku tabulky 0025 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty vybraného prvku v dvourozměrné tabulce ; print(tbl[1][1]) 0026 GGET 1 3 ; získání reference na funkci se jménem "print" 0027 TGETB 2 0 1 ; načtení celého řádku tabulky 0028 TGETB 2 2 1 ; načtení vybraného prvku z řádku 0029 CALL 1 1 2 ; volání funkce print() ; tisk hodnoty vybraného prvku v dvourozměrné tabulce ; print(tbl[3][4]) 0030 GGET 1 3 ; získání reference na funkci se jménem "print" 0031 TGETB 2 0 3 ; načtení celého řádku tabulky 0032 TGETB 2 2 4 ; načtení vybraného prvku z řádku 0033 CALL 1 1 2 ; volání funkce print() ; každý program je automaticky ukončen následující instrukcí 0034 RET0 0 1 ; konec
8. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů
Všech šest dnes popsaných a taktéž „disasemblovaných“ demonstračních příkladů bylo uloženo do Git repositáře umístěného na adrese https://github.com/tisnik/luajit-examples. Odkazy na prozatím poslední verze těchto šesti příkladů naleznete v tabulce umístěné pod tímto odstavcem:
9. Odkazy na Internetu
- Wikipedia: Mezijazyk
http://cs.wikipedia.org/wiki/Mezijazyk - The LuaJIT Project
http://luajit.org/index.html - LuaJIT FAQ
http://luajit.org/faq.html - LuaJIT Performance Comparison
http://luajit.org/performance.html - LuaJIT 2.0 intellectual property disclosure and research opportunities
http://article.gmane.org/gmane.comp.lang.lua.general/58908 - LuaJIT Wiki
http://wiki.luajit.org/Home - LuaJIT 2.0 Bytecode Instructions
http://wiki.luajit.org/Bytecode-2.0 - Programming in Lua 9.1 – Coroutine Basics,
http://www.lua.org/pil/9.1.html - Programming in Lua (first edition)
http://www.lua.org/pil/contents.html - Programming in Lua: 6 – More about Functions
http://www.lua.org/pil/6.html - Lua Lanes
http://kotisivu.dnainternet.net/askok/bin/lanes/ - Programming in Lua: 6.1 – Closures
http://www.lua.org/pil/6.1.html - Programming in Lua: 9.1 – Coroutine Basics
http://www.lua.org/pil/9.1.html - Programming in Lua: Numeric for
http://www.lua.org/pil/4.3.4.html - Programming in Lua: break and return
http://www.lua.org/pil/4.4.html - Programming in Lua: Tables
http://www.lua.org/pil/2.5.html - Programming in Lua: Table Constructors
http://www.lua.org/pil/3.6.html - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - Lua: Tables Tutorial
http://lua-users.org/wiki/TablesTutorial - Lua: Control Structure Tutorial
http://lua-users.org/wiki/ControlStructureTutorial - Lua Types Tutorial
http://lua-users.org/wiki/LuaTypesTutorial - Goto Statement in Lua
http://lua-users.org/wiki/GotoStatement - Lua 5.2 sources
http://www.lua.org/source/5.2/ - Lua 5.2 sources – lopcodes.h
http://www.lua.org/source/5.2/lopcodes.h.html - Lua 5.2 sources – lopcodes.c
http://www.lua.org/source/5.2/lopcodes.c.html - Lambda the Ultimate: Coroutines in Lua,
http://lambda-the-ultimate.org/node/438 - Coroutines Tutorial,
http://lua-users.org/wiki/CoroutinesTutorial - Lua Coroutines Versus Python Generators,
http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators