Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
PROGRAMMAZIONE LUA
LA GUIDA COMPLETA
PER MAC, WINDOWS E LINUX
© 2014 Area 51 s.r.l., San Lazzaro di Savena (Bologna)
Prima edizione ebook Area51 Publishing: settembre 2014
Curatore della collana: Mirco Baragiani
Cover: Valerio Monego
Redazione e sviluppo ebook: Enrico De Benedictis
Se intendi condividere questo ebook con un’altra persona, ti chiediamo cortesemente di scaricare una
copia a pagamento per ciascuna delle persone a cui lo vuoi destinare. Se stai leggendo questo ebook e
non lo hai acquistato, ti chiediamo, se ti piace, di acquistarne anche una copia a pagamento, al fine di
poterci permettere di far crescere il nostro lavoro e di offrirti sempre più titoli e una qualità sempre
maggiore. Grazie per il tuo aiuto e per aver rispettato il lavoro dell’autore e dell’editore di questo
libro.
Data la rapidità con cui i tool di sviluppo e i linguaggi vengono aggiornati, i contenuti di questo
ebook si intendono fedeli allo stato dell’arte al momento della pubblicazione.
Google Plus
Pinterest
www.area51editore.com
www.area51editore.com/blog
I computer sono incredibilmente veloci, accurati e stupidi. Gli uomini
sono incredibilmente lenti, inaccurati e intelligenti. L’insieme dei due
costituisce una forza incalcolabile. (Albert Einstein)
Introduzione
• LUA è portabile
LUA è distribuito in un pacchetto di piccole dimensioni e si integra “out-of-
the-box” in tutte le piattaforme che hanno un compilatore C standard. LUA
funziona su tutte le versioni di Unix e Windows, su dispositivi mobili (con
sistema operativo Android, iOS, BREW, Symbian, Windows Phone), su
microprocessori embedded (come ARM e rabbit, per applicazioni come
Lego Mindstorms), su mainframe IBM, etc.
• LUA è libero
LUA è open-source, distribuito sotto la famosa licenza MIT. Esso può
essere utilizzato per qualsiasi scopo, compresi progetti commerciali, senza
alcun costo. Basta scaricarlo e usarlo.
Utilizzare l’interprete di LUA nel tuo computer, che tu sia un utente Mac,
Linux/Unix oppure Windows, è un’operazione semplice e immediata, ti
basta scaricare l’interprete dal sito del progetto oppure un’ambiente di
sviluppo integrato. La seconda ipotesi è la scelta che ti propongo per questo
manuale. Zerobrane Studio ha realizzato un bellissimo IDE per sviluppare
attraverso LUA, l’applicativo è disponibile per tutti i sistemi operativi e
potrai utilizzarlo gratuitamente oppure contribuendo con una donazione a
tua discrezione. LUA, come hai potuto appurare, è un linguaggio di
scripting molto potente, semplice da apprendere e leggero. Questi sono solo
alcuni motivi che ne hanno decretato il successo planetario e molti
produttori di motori di sviluppo si sono orientati a questo linguaggio
soprattutto nel campo videoludico. Attraverso l’IDE che ti propongo potrai
provare e testare tutto il codice presente in questo manuale.
1. Alla tua sinistra puoi notare un corposo elenco di cartelle e file con
esempi di codice realizzati attraverso LUA.
2. Al centro c’è l’editor del codice, con tutte le caratteristiche di un
moderno editor (completamento della sintassi etc.).
3. In basso puoi notare la consolle di output dove visualizzerai tutti i tuoi
risultati.
2. Clicca ora due volta il pulsante verde di Run, se tutto è andato a buon
fine nella consolle vedrai visualizzata la stringa “Hello world”.
Conclusione
Le variabili
Come tutti i linguaggi, anche LUA possiede le variabili. Puoi pensare alle
variabili come a contenitori dove memorizzare qualsiasi tipologia di
informazione: lo stato di un processo, un valore numerico, una stringa, un
oggetto etc. Memorizzare gli elementi citati precedentemente in una
variabile viene comunemente chiamato assegnamento. LUA utilizza
principalmente tre tipologie di variabili per tale operazione:
Globali
Locali
Campi di tabella
Variabili globali
Una variabile globale può essere modificata in qualsiasi parte di un
programma e il suo campo di visibilità è totale. Questo significa che è
possibile accedere a essa da qualsiasi punto del tuo programma sia in lettura
che in scrittura. Una variabile è considerata globale nel momento in cui tu
le assegni un valore. Osserva i seguenti esempi:
varialibe_esempio = 99
print (varabile_esempio)
Variabili locali
Le variabili locali, a differenza di quelle globali, hanno un campo di
visibilità molto più limitato e solitamente possono essere modificate oppure
lette solo da una funzione, oppure da un blocco specifico di codice. Quando
tu crei una funzione oppure un blocco di codice definito, in sostanza stai
creando un campo di esistenza locale e puoi dichiarare e inizializzare una
variabile al suo interno, la variabile avrà un ciclo di vita che si andrà a
esaurire con il contesto creato. La localizzazione delle variabile è molto
salutare per il tuo codice, essa ti aiuta a migliorare le prestazioni della tua
applicazione. Osserva il seguente esempio per comprendere come realizzare
una variabile locale:
local x = 5
x = 7
local k = 3
while K <= 10 do
local x = k * 3
print (x)
k = k + 1
end
print (x)
Campi di tabelle
print (tabella.str1)
print (tabella.str1,tabella.str2)
Questo frammento di codice crea una tabella chiamata “tabella” composta
da due campi, il campo str1 associato alla stringa ‘Ciao’ e il campo str2
associato alla stringa ‘Mondo’. La prima funzione print stamperà nel
terminale il valore del primo campo associato “Ciao”, la seconda print
invece stamperà entrambi i campi “Ciao” e “Mondo”.
--[[
a = 10
print (a)
]]--
Quando crei una nuova variabile con LUA devi rispettare alcune regole e
convenzioni, il nome di una variabile deve sempre iniziare con una lettera
oppure con il simbolo underscore (_). Non sono ammessi spazi e potrai
utilizzare solo numeri, lettere e simboli underscore. Il linguaggio è
case_sensitive, questo significa che fa distinzione tra maiuscole e
minuscole: una variabile chiamata Var1 è diversa da un’altra chiamata var1.
Le seguenti parole sono riservate al linguaggio e non possono essere
utilizzate per creare il nome di una variabile:
and
break
do
else
elseif
end
false
for
function
if
in
local
nil
not
or
repeat
return
then
true
until
while
If Then Else
If <condizione> Then
<espressione vera>
Else
<espressione falsa>
End
La condizione Else (espressione falsa) è opzionale e può essere omessa.
Osserva alcuni esempi:
(1)
if k > 0 then k=k-1 end
(2)
Else
(3)
If K > 10 then
If K ~= M then
Printf(“K è diverso da M”)
Else
Print(“K è uguale ad M”)
End
End
In questo terzo esempio puoi notare l’utilizzo innestato del costrutto If, con
questa tecnica puoi andare in profondità e generare condizioni di confronto
anche complesse. È buona norma in questi casi non esagerare mai con gli
innesti e scrivere un codice sempre indentato bene, l’ordine e la pulizia
nella scrittura del codice sono importantissimi! Come puoi notare il
costrutto if più esterno ha omesso la variante Else.
Il linguaggio LUA non ha nella sua sintassi un costrutto di tipologia switch
(interruttore multiplo). Questo scoglio è facilmente superabile
dall’estensione elseif del costrutto if.
Osserva il seguente esempio:
ris = a - b
ris = a – b
ris = a – b
else
Operatori Aritmetici
x = 3 * 5 + 4
print(x)
k = 24 % 7
print(k)
l = 2^3
print(l)
Operatori relazionali
< “minore”
> “maggiore”
<= “minore o uguale a”
>= “maggiore o uguale a”
== “uguale a”
~= “diverso da”
local a = 10
local b = 20
print ( a == b ) -- false
and
or
not
local a = 10
local b = 20
local str2=”Mondo”
local num=2013
print(prv3)
^
not # - (unario)
*/
+-
..
< > <= >= ~= ==
and
or
Tutti gli operatori hanno associatività a sinistra tranne i casi particolari degli
operatori ^ e .. che hanno associatività a destra. Puoi a ogni modo utilizzare
le parentesi tonde per cambiare la precedenza degli operatori secondo le tue
necessità. Quando due operatori devono essere risolti e hanno la stessa
precedenza, sarà valutato prima quello a sinistra, osserva il seguente
esempio:
print( 9 – 3 + 7) – questa operazione restituisce il numero 13
Una stringa non è altro che una sequenza finita di caratteri, puoi
memorizzare sia caratteri numerici che alfanumerici ma anche veri e propri
dati binari mascherati al suo interno.
Fondamentalmente esistono tre tipologie di quotazione per le stringhe: la
prima con il doppio apice, la seconda con il singolo apice e la terza con
doppia parentesi quadrata.
Osserva i seguenti esempi:
Le sequenze di uscita nel linguaggio LUA per le stringhe sono molto simili
a quelle del linguaggio C, eccoti un elenco esaustivo con la descrizione:
\a segnale acustico
\b back space
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\” doppio apice
\’ singolo apice
local val1 = 10
Cicli
Cicli definiti
Cicli indefiniti
Il ciclo for
Il ciclo for appartiene alla categoria dei cicli definiti. Nel linguaggio LUA
presenta la seguente sintassi:
end
for k , v in pairs( t ) do
.. codice ..
end
1 lunedì
2 martedì
ecc …
Il ciclo while
Il while è il primo dei due cicli afferenti la categoria di ciclo indefinito
introdotta precedentemente, la sua specializzazione è definita come
prefissa. Questo significa che la condizione di verità è testata a monte del
ciclo. Ecco la generica sintassi di un ciclo while in LUA:
while (condizione) do
.. istruzioni di loop ..
end
Fino a che la condizione risulta essere vera il ciclo esegue le sue iterazioni,
ovvero la ripetizione del codice all’interno delle parole chiavi do e end.
Appena la condizione è falsa il ciclo smette di iterare e il programma
continua con il normale flusso. Osserva ora il seguente esempio pratico:
local i = 1
while ( i <= 10 ) do
print(i)
i=i+1
end
La condizione testata all’inizio del ciclo è vera fino a che la variabile i non
è maggiore di 10, quindi il ciclo eseguirà esattamente dieci iterazioni. In
questo caso il ciclo “emula” un for ma non è difficile intuire che attraverso
delle condizioni aleatorie all’interno del ciclo è possibile modificare la
condizione in un qualsiasi momento.
Il ciclo repeat
Il repeat è il secondo dei due cicli afferenti la categoria di ciclo indefinito
introdotta precedentemente, la sua specializzazione è definita come
postfissa. Questo significa che la condizione di verità è testata a valle del
ciclo. Ecco la generica sintassi di un ciclo repeat in LUA:
repeat
.. istruzioni di loop ..
until (condizione)
Come puoi ben notare la condizione è testata alla fine del ciclo, questo
implica che almeno una volta il ciclo sarà sempre eseguito. Osserva il
seguente esempio:
repeat
line = io.read( )
print(line)
until line ~= “ “
repeat
.. istruzioni de loop ..
local var
until (var)
Tabelle
colori = {
[1] = “Verde”
[2] = “Blu”
[3] = “Giallo”
[4] = “Arancione”
[5] = “Rosso”
}
vett = { }
for i = 1, 1000 do
vett[i] = 0
end
matrice = { }
for i = 1, N do
matrice[ i ] = { } -- Creazione di una riga
for j = 1, M do
matrice[ i ],[ j ] = 0 -- Inizializzazione a zero della
singola cella
end
end
list = nil
list1 = nil
listn = nil
local l = list
while l do
.. lettura dei valori della lista (es:l.value) ..
l = l.next
end
Come puoi notare nel codice è all’interno del ciclo stesso che viene caricato
il prossimo nodo della lista; quando sarà raggiunto l’ultimo nodo valido,
non essendoci un nodo successivo, la condizione del ciclo while sarà
impostata a falsa e di conseguenza si avrà l’uscita dal ciclo.
3. Metatabelle e metametodi
Esempio operativo
local mt = {}
Set = {}
1. Ottimo lavoro, per rendere più operativo il tuo oggetto set appena
creato dovrai ora realizzare due funzione per poter serializzare gli
elementi della tabella set e stamparli ad esempio nella consolle. La
prima funzione “Set.tostring” restituisce una concatenazione ben
formata di tipo stringa, leggendo gli elementi del set attraverso un
ciclo for.
-- funzione di concatenazione
function Set.tostring (set)
local l = {}
for e in pairs (set) do
l[#l +1 ] = e
end
end
-- esempio di funzionamento
print(getmetatable(s1))
print(getmetatable(s2))
s3 = s1 + s2
3. Esegui ora un test finale stampando i due oggetti set prima dell’unione
e l’oggetto set risultante dalla somma dei precedenti.
Set.print (s1)
Set.print (s2)
print("Unione:")
Set.print (s3)
Soluzione esercizio
s4 = s1 * s2
print("Intersezione:")
Set.print (s4)
Genera ora due nuovi oggetti set e per essi prova diverse configurazioni,
utilizzando gli operatori ridefiniti precedentemente e passati come
parametro alla funzione print.
print(sm1 ~= sm2)
-- return prototipo[chiave]
-- end
4. Crea ora un nuovo oggetto partendo dal prototipo, soltanto con i primi
due parametri.
-- Creazione di un nuovo oggetto prototipo con i primi due
parametri
print(w.larghezza)
print(w.altezza)
In alcuni casi può essere utile generare valori di default per una tabella
attraverso una funzione associata, sfruttando sempre le metatabelle.
2. Testa ora il codice appena realizzato, creando una tabella con due
valori, stampandone solo uno e cercando di visualizzare un terzo
valore non presente che restituirà nil. Per ovviare a questo, invoca la
funzione alla tabella appena creata e riprova la stampa, noterai a
questo punto che il secondo valore viene sostituito dal valore di default
così come ti saresti aspettato.
-- Test della funzione
print(tabella.a, tabella.c)
setDefault(tabella, 77)
Lavorando con le tabelle per taluni casi può essere necessario tracciarne
l’accesso, in LUA questa operazione è possibile attraverso le metatabelle e
gli strumenti messi a disposizione da esse:
t = {}
setmetatable(t, mt)
1. Crea una tabella “index” che utilizzerai per memorizzare tutti gli indici
degli accessi alle tabelle, a questo punto il codice è simile al
precedente e prevede l’implementazione dei due campi esclusivi
__index e __newindex con l’opportuna implementazione della tabella
precedentemente realizzata.
local index = {}
local mt = {
__index = function (t, k)
print("Accesso all'elemento: " .. tostring(k))
return t[index][k] -- accesso alla tabella di
origine
end,
t[index][k] = v
end,
Per testare quanto appena realizzato crea una nuova tabella “t1”. Ti basterà
a questo punto assegnare alla tabella la funzione “track” appena realizzata,
che ha come parametro la tabella stessa, e l’impianto è attivo.
-- Test accesso a più tabelle
t1 = { }
t1=track(t1)
setmetatable(proxy, mt)
return proxy
end
Per il test non ti resta che realizzare una nuova tabella, sfruttando la
funzione “soloLettura” come nell’esempio sottostante:
-- Test tabella solo lettura
colori =
soloLettura{"Giallo","Verde","Blu","Rosso","Arancione"}
print(colori[5])
colori[2] = "Viola"
4. L’ambiente
Introduzione
Audio = 10
_G.Audio = 10
È bene, per pulizia e leggibilità del codice, utilizzare la seconda
nomenclatura nel caso si voglia predisporre una variabile globale a uso
generale in tutti i moduli del progetto. La lettura di tale variabile non
prevede a ogni modo la presenza del prefisso, mentre per ogni modifica è
necessario inserirlo.
Per avere un sunto più completo di tutte le variabili globali è possibile
stampare anche l’indirizzo di memoria di ognuna, attraverso la seguente
sintassi:
setfield("italia.bologna.montesanpietro", 40050)
cap = getfield("italia.bologna.montesanpietro")
print(cap)
setmetatable(_G, {
__newindex = function (_, n)
error("stai cercando di assegnare un valore ad una
variabile non dichiarata "..n, 2)
end,
__index = function (_, n)
error("stai cercando di leggere una variabile non
dichiarata "..n, 2)
end,
})
var1 = 10
rawset(_G,"var1",false)
var1 = 10
local M = {}
return M
Nel file main.lua (ma questo può avvenire in qualsiasi file o modulo di
progetto) carica il file globals.lua attraverso la funzione “require” e una
variabile puntatore assegnata a essa. Ora potrai memorizzare le variabili
globali precedute dal puntatore e richiamarle da qualsiasi altro modulo con
la stessa tecnica:
local Glob = require( "globals" )
Glob.var1 = 20
print(Glob.var1)
Moduli e pacchetti
return modulo
function modulo.foo()
print("Ciao Corona SDK")
end
function modulo.mediabinaria(val1,val2)
return (val1+val2)/2
end
Per utilizzare il modulo all’interno di un altro modulo, oppure nel tuo main,
devi prima di tutto importarlo. Questa operazione avviene attraverso la
direttiva “require” con la seguente sintassi: var_puntatore =
require”nome_modulo”. A questo punto puoi utilizzare le funzioni del
modulo utilizzando la variabile puntatore che lo ha richiesto nella sintassi:
var_puntatore.funzione_del_modulo. Nell’esempio sottostante vengono
invocate le funzioni create nel precedente modulo:
m = require "modulo"
m.foo()
m.bar()
Primo approccio
1. Una classe è a tutti gli effetti una tabella, quindi la prima operazione
consiste nella creazione di una tabella vuota con il nome della classe.
Per poter invocare i metodi di classe e quindi coppie chiavi valori della
tabella dovrai creare una sorta di “cortocircuito” nella tua tabella
attraverso l’operatore __index. Ecco il codice necessario:
local miaClasse = {} -- la tabella rappresenta la classe,
le istanze vengono generate attraverso metatable
function miaClasse.new(init)
end
self.valore = nuovoval
end
-- metodo getter
function miaClasse.get_valore(self)
return self.valore
end
return miaClasse
La classe è pronta e non ti resta che testarla. Per fare questo è necessario
scrivere del codice nel file main.lua.
2. Non ti resta che visualizzare nella consolle del simulatore i tuoi frutti;
questa operazione è possibile passando alla funzione print il metodo
get che di fatto recupera il valore dell’attributo. Prova poi a modificare
il valore con il metodo set e ristampalo a video nuovamente.
print(num:get_valore())
})
-- metodo setter
function miaClasse:set_valore(nuovoval) -- aggiunta
dei due punti
self.valore = nuovoval
end
-- metodo getter
function miaClasse:get_valore()
return self.valore
end
setmetatable(miaClasse, {
__call = function (cls, ...)
local self = setmetatable({}, cls)
self:init(...)
return self
end,
})
function miaClasse:init(init,file,posx,posy)
self.valore = init
self.visual = display.newImage(file, posx, posy, true )
-- aggiunta di un attributo oggetto
return self
end
setmetatable(miaClasseDerivata, {
__index = miaClasse, -- Meccanismo di ereditarietà
__call = function (cls, ...)
local self = setmetatable({}, cls)
self:init(...)
return self
end,
})
function miaClasseDerivata:init(init1,init2,file,posx,posy)
miaClasse.init(self,init1,file,posx,posy) -- chiamata
del costruttore ereditato
self.valore2 = init2
end
return miaClasseDerivata
Anche la classe derivata è pronta, non ti rimane che testare questo ultimo
codice andando a modificare il file main.lua
miaClasse.init(self,init1,file,posx,posy) -- chiamata
del costruttore ereditato
self.valore2 = init2
end
Secondo approccio
2. Crea ora i tuoi attributi privati. Questi attributi, inizializzabili con una
costante oppure un parametro passato all’istanza della classe, sono
privati e interni alla classe. La classe garantisce la loro integrità; per la
lettura di suddetti valori è necessaria la realizzazione di un metodo di
classe, come vedrai più avanti.
-- attributi privati
local num_prv = init
-- metodi privati
local function media_binaria(var_a,var_b)
local mediab = (var_a+var_b) / 2
return mediab
end
-- metodi pubblici
function self.somma()
print(media_binaria(self.num_pub,num_prv) )
return self.num_pub + num_prv
end
function self.incremento()
num_prv = num_prv + 1
end
4. Il metodo getNum restituisce l’istanza dell’attributo privato
esternamente alla classe ed è l’unico modo per accedere a tale valore,
se non viene implementato non è possibile un accesso al valore
specifico. Questo garantisce una reale protezione dei valori privati
interni alla classe.
function self.getNum()
return num_prv
end
5. Per terminare il codice di classe è necessario “ritornare” self e il nome
stesso della classe attraverso la funzione “return”.
-- ritorno istanza
return self
end
-- ritorno classe
return miaClasse
Una volta realizzata la classe, implementerai nel file main.lua una sua
istanza andando così a creare un oggetto del tipo della classe. Utilizzerai
quindi i metodi pubblici di essa, potrai anche accedere in modo molto
semplice agli attributi pubblici mentre ti sarà negato di modificare quelli
privati, che possono essere inizializzati solo in fase di creazione se è
previsto il passaggio di un parametro.
print(num.somma())
num.incremento()
print(num.num_pub)
num.num_pub = 20
print(num.num_pub)
print(num.getNum() )
self.num_pub = 30
function self.getNum()
return num_prv + self.num_pub + base_GetNum()
end
return self
end
return miaClasseDerivata
numDer.incremento()
print(numDer.getNum())
6. Le coroutine
Introduzione
Primo approccio
-- la funzione è anonima
c1 = coroutine.create(function () print ("ciao mondo") end) --
Creazione di una coroutine(parametro una funzione)
coroutine.resume(c1)
c2 = coroutine.create(function ()
for i=1, 10 do
print("c2",i )
end
end)
coroutine.resume(c2)
Adesso viene il bello: alla funzione di prima integrerai una nuova chiamata
“coroutine.yield(nome coroutine)”. Questa importantissima chiamata
sospende l’esecuzione della coroutine e per farla ripartire è necessario
invocare per essa la chiamata “coroutine.resume(nome coroutine)”. Come
puoi intuire questo meccanismo è di cruciale importanza perché ti permette
di sospendere o eseguire una o più coroutine dal programma principale, di
fatto controllandone il flusso a tuo piacimento.
Osserva il seguente codice:
c3 = coroutine.create(function ()
for i=1, 10 do
print("c3",i )
coroutine.yield(c3) -- sospende la funzione
end
end)
coroutine.resume(c3)
print(coroutine.status(c3))
coroutine.resume(c3)
Esempi notevoli
-- Esempio uno
print("esc1", a, b, c + 7)
end)
coroutine.resume(esc1, 1, 2, 3)
Il terzo esempio mostra come sia possibile creare un filtro con la chiamata
“coroutine.yield” sulle variabili passate in ingresso. Il corretto passaggio dei
parametri viene processato dalla prima print nel blocco della coroutine.
Passaggi di parametri diversi possono essere propagati invece dalla
chiamata “coroutine.yield”.
-- Esempio tre
print(coroutine.resume(esc4))
La libreria math
do
local sin,asin = math.sin, math.asin
local deg, rad = math.deg, math.rad
math.sin = function (x) return sin(rad(x)) end
math.asin = function (x) return deg(asin(x)) end
end
La libreria table
Introduzione
La libreria table è costituita da funzioni ausiliarie per manipolare vettori e
tabelle generiche. Essa mette a disposizione funzioni per l’inserimento e
l’estrazione di elementi da un vettore, l’ordinamento di un vettore e la
concatenazione di una stringa di elementi del vettore.
Maggiori dettagli e un elenco esaustivo della libreria sono presenti al
seguente indirizzo:
http://lua-users.org/wiki/TableLibraryTutorial
function printVett(vett)
for n in pairs(vett) do
print(vett[n])
end
end
2. Popola ora un vettore con cinque elementi, quindi attraverso la
funzione di libreria “insert” inserisci il numero 29 in terza posizione.
Stampa il vettore per verificare la correttezza di suddetta operazione e
quindi rimuovi l’elemento in quinta posizione con la funzione
“remove”. Come ultima operazione ordina il vettore attraverso la
funzione “sort”.
t = {10, 17, 3, 7, 9}
table.insert(t,3,29)
printVett(t)
table.remove(t,5)
printVett(t)
table.sort(t)
printVett(t)
table.sort(t,compare)
printVett(t)
2. Inserisci ora un vettore di stringhe e, attraverso la funzione “concat”,
concatena le stringhe in un’unica stringa prima di stamparla nella
consolle. Attraverso la funzione “maxn” puoi stampare il maggiore
numero di un vettore numerico e attraverso il simbolo “#” davanti a un
vettore puoi ricavarne la dimensione.
anagrafica =
{
"Mario",
"Rossi",
"40"
}
print(table.maxn(t))
print(#t)
La libreria string
print(string.len(stringa))
print(ripetizione)
print(string.sub(s,i,j))
print(s1)
print(conteggio)
g, m, a = string.match(data, "(%d+)/(%d+)/(%d+)")
print(g,m,a)
La libreria I/O
La libreria I/O permette di manipolare i file, salvando le informazioni in
modo persistente. Essa lavora principalmente in due modalità: una semplice
e una completa. La modalità semplice lavora in modo asincrono su file di
input e output (scrittura/lettura). La modalità completa ha un approccio
molto più complesso e una strutturazione del lavori di tipo object oriented,
questa funzionalità è pensata per un uso massivo dei file.
Maggiori informazioni sulla libreria sono presenti al seguente URL:
http://lua-users.org/wiki/IoLibraryTutorial
La libreria debug
Questa libreria non ha la pretesa di offrire un ambiente integrato di debug,
ma offre tutte le primitive necessarie alla costruzione di un ambiente di
debug personalizzato. Queste funzioni sono molto dispendiose in termini di
prestazioni ed efficienza ed è bene utilizzarle con parsimonia.
Maggiori informazioni sulla libreria sono reperibili al seguente URL:
http://www.lua.org/pil/23.html
#include <lua.hpp>
#include <iostream>
int add(lua_State *L);
int main()
lua_State *L = luaL_newstate( );
luaL_openlibs(L);
lua_pushcfunction(L, add);
lua_setglobal(L, “add”);
luaL_dofile(L, “test.lua”);
lua_getglobal(L, “x”);
lua_close(L);
return 0;
return 1;
}
Come puoi notare tutta la logica del programma è all’interno della funzione
main ed è in essa che viene definita e attivata la funzione “add” per LUA.
La funzione “add” per comunicare con LUA utilizzerà uno stack locale
speciale chiamato L, questo oggetto viene dichiarato e inizializzato
all’inizio della funzione main nel seguente modo ed è sempre
indispensabile: lua_State *L = LUAL_newstate( );
Solo a questo punto potrai aggiungere la funzione con il suo relativo stack
alla libreria e renderla globale con il seguente codice:
lua_pushcfunction(L, add);
lua_setglobal(L, “add”);
Bene, accorpa ora al tuo codice il file LUA che invocherà la funzione e
rendi globale la variabile da essa risultante nell’assegnazione del valore di
ritorno, questo valore ti servirà per una stampa in consolle tramite
streaming.
luaL_dofile(L, “test.LUA”);
lua_getglobal(L, “x”);
lua_close(L);
return 0;
Osserva ora il codice della funzione “add”, puoi notare che lo stack L come
ti aspettavi è il candidato per il passaggio dei parametri e l’assegnazione dei
medesimi all’interno della funzione. Nell’esempio qui riportato la funzione
“lua_tonumber” ha lo scopo di convertire un valore stringa numerico in un
valore puramente numerico.
Ricorda che per terminare correttamente la funzione è necessario eseguire
l’istruzione return seguita dal valore 1.
return 1;
}
Prima di testare la tua nuova funzione C++ per LUA, ricordati di aprire un
nuovo file LUA (ad esempio test.lua) con la seguente sintassi:
x = add(13, 17)
Conclusione