« Tcl: VariabiliAppunti di Tcl/TkTcl: Espressioni matematiche »

Tcl

Sostituzione e valutazione

Ci sono due fasi che effettua l'interprete quando esegue un comando in Tcl, in modo simile a come operano le altre shell UNIX. La prima viene detta fase di sostituzione e la seconda fase di valutazione dal comando. Nella prima fase le parole del comando (sia il nome del comando che gli argomenti) vengono scandite da sinistra a destra e l'interprete, se trova che una parola deve essere sostituita da un altro valore, effettua la sostituzione. Nella seconda fase viene valutato il comando che risulta dalle sostituzioni, che può essere anche molto diverso del comando come era stato scritto dal programmatore, ossia l'interprete esegue le azioni che corrispondono al comportamento del comando, richiamando una funzione C o Tcl che lo implementa e passando tutti i parametri come risultano dalla fase di sostituzione.

Questo esempio dimostra che anche il nome del comando può essere oggetto di sostituzione:

% set a puts
puts
% $a "ciao"
ciao
% $a $a
puts

Occorre tenere presente che viene effettuata una sola fase di sostituzione. Poi viene fatta la fase di esecuzione. Le sostituzioni avvengono prima dell'esecuzione del comando e sono effettuate dall'interprete e non dal comando stesso, esattamente come avviene con le altre shell UNIX. Poiché la fase di sostituzione viene fatta una sola volta, la puts stampa la stringa $b e non ciao in questo esempio:

% set a \$b
$b
% set b ciao
ciao
% puts $a
$b

In questa prima fase, l'interprete effettua vari tipi di sostituzione, che vengono descritti nell'elenco seguente:

Se invece il carattere \ non è seguito da uno dei caratteri delle sequenze di escape viste prima (incluso il newline), allora il significato dello \ è completamente differente: il backslash in tal caso indica che il carattere che segue non deve essere considerato nel suo significato speciale. Questa funzionalità può essere usata ad esempio per stampare il simbolo del dollaro, evitandone l'interpretazione speciale, che come abbiamo visto è quella di introdurre un valore di una variabile:

% puts $100
can't read "100": no such variable
% puts \$100
$100
% set a 100
% puts $$a
$100
% puts \$$a
$100
oppure per stampare le parentesi graffe o le quadre:
% puts \{\}
{}
altri esempi:
% puts "esempio di \"quotatura\""
esempio di "quotatura"
% puts \\
\
% puts \\\\
\\

Come abbiamo visto, le virgolette doppie o le parentesi graffe permettono entrambe di raggruppare diverse parole da considerare, nella fase di valutazione, come un argomento singolo. Tuttavia c'è una differenza in quanto i due tipi di delimitatori causano un comportamento differente durante la fase di sostituzione. Quando si raggruppa tramite le virgolette doppie, tutte le le sostituzioni della lista precedente vengono effettuate all'interno delle virgolette. Dopo la sostituzione, il risultato viene valutato come un argomento singolo:

% set PI 3.14159
3.14159
% puts "PI\t$PI" ;# le " qui sono opzionali
PI  3.14159
% puts "2 PI\t[expr 2*$PI]"
2 PI    6.28318

Invece non viene effettuata alcuna sostituzione nelle stringhe raggruppate tramite le parentesi graffe. L'effetto delle { } è di raggruppare disabilitando le sostituzioni, o in altri termini la sequenza delle parole raggruppate viene valutata (ovvero passata come parametro al comando) esattamente come è stata scritta:

% puts {Le sequenze di escape sono: \a \b \t \n \v \f \r}
Le sequenze di escape sono: \a \b \t \n \v \f \r
% puts {$var}
$var
% puts {[expr 1+2]}
[expr 1+2]

Fa eccezione la sequenza \ seguita da newline, che è l'unica sequenza di escape che viene valutata all'interno delle parentesi graffe:

% puts {uno\
due}
uno due

Notate che quando le parentesi graffe vengono usate per raggruppare, se compare un accapo all'interno delle parentesi, l'interprete non considera terminato il comando finché le parentesi non vengono chiuse. Siccome, come vedremo, alcuni comandi accettano altre stringhe comandi come argomenti, questo risulta utile per passare stringhe comandi multilinea:

% puts {uno
due}
uno
due

È importante che la graffa di apertura si trovi sulla stessa linea del comando:

% puts 
wrong # args: should be "puts ?-nonewline? ?channelId? string"
% {prova}
invalid command name "prova"

Non fatevi trarre in inganno dai casi in cui le virgolette doppie appaiono all'interno delle parentesi graffe o viceversa. Se una stringa è già raggruppata tramite le parentesi graffe o le virgolette, e rispettivamente le virgolette o le parentesi graffe appaiono all'interno della stringa, allora naturalmente non rappresentano operatori di raggruppamento, ma vengono trattati come normali caratteri ASCII. Se la stringa è raggruppata tramite le virgolette doppie, le sostituzioni avverranno anche all'interno della stringa quotata, perfino all'interno delle parentesi graffe:

% set a a
% puts "{$a}"
{a}
% puts {"$a"}
"$a"

Notate come le parentesi quadre in Tcl rappresentano l'equivalente funzionale degli apici inversi nella shell sh(1) o delle chiamate di funzione o degli operatori predefiniti in linguaggio C. Questi meccanismi permettono tutti di manipolare dei dati con un certo comando e poi di memorizzare il risultato in modo che sia accessibile successivamente ad un altro comando. In Tcl per avere accesso al risultato di un comando occorre racchiudere la stringa del comando tra parentesi quadre. Il comando così racchiuso verrà valutato nella fase di sostituzione; l'intera sottostringa [comando] verrà sostituita dal valore di ritorno del comando.

Ad es. una assegnazione multipla che in C si scrive come a=b=1, in Tcl diventa:

% set a [set b 1]
1
% puts $a
1
% puts $b
1

Un altro esempio è l'incremento di una variabile che in C si scrive come a=a+1:

% set a 1
1
% set a [expr $a + 1]
2

Cosi come in C esiste l'utile abbreviazione a++, in Tcl potete usare il comando incr, la cui sintassi è:

incr varName ?increment?

Esempi:

% set a 1
1
% incr a
2
% incr a 3
5
% incr a -2
3

Per evitare la valutazione di un comando racchiuso tra [ ] occorre eliminare il significato speciale di [ tramite uno backslash oppure racchiuderlo tra { }:

% puts "[expr 1+2]" ;# " opzionali
3
% puts "\[expr 1+2]" ;# " obbligatorie
[expr 1+2]
% puts {[expr 1+2]}
[expr 1+2]

Le parentesi quadre possono essere innestate anche a più livelli. Quando l'interprete Tcl incontra una stringa tra parentesi quadre, chiama ricorsivamente sé stesso per interpretarla. La valutazione si compone delle due fasi di sostituzione e di esecuzione, esattamente come se la stringa racchiusa tra parentesi quadre fosse stata passata all'interprete su una linea a sé stante senza le [ ]. Ricordo ancora che viene effettuata una sola fase di sostituzione. Al ritorno dalla chiamata ricorsiva dell'interprete, il controllo ritorna all'interprete principale che sostituisce la stringa tra [ ] con il risultato del comando e poi continua la fase di sostituzione sulla linea ottenuta dopo la sostituzione del risultato del comando, a partire dal primo carattere successivo alla stringa che ha sostituito il comando tra [ ]. Ad esempio il comando:

% set a [set b [set c 1]]
1
viene di fatto eseguito come tre comandi più semplici disposti nell'ordine seguente:
% set c 1
1
% set b $c
1
% set a $b
1

« Tcl: VariabiliAppunti di Tcl/TkTcl: Espressioni matematiche »