:TITLE: Substituição sem avaliação - format, subst
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl34.lsn,v 1.4 2000/04/24 16:17:52 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# Veja o arquivo "AVISO" com os termos da licença.
;#
;#*********************************************************
;# Portuguese translation: Lucio Agostinho Rocha
;# E-mail: outrosdiasvirao@yahoo.com.br
;# Last update: 16/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
O interpretador Tcl faz apenas um passo de substituição durante 
a avaliação do comando. Algumas situações, tais como colocar o
nome de uma variável em uma variável, requer dois passos pela
fase de substituição. Neste caso, o comando <B>subst</B> é útil.
Ele realiza um passo de substituição sem realizar qualquer execução 
de comandos exceto aqueles requeridos para a substituição ocorrer,
ou seja: comandos dentro de <B>[]</B> serão executados, e os
resultados colocados na string de retorno.
<P>
O comandos <B>format</B> pode também ser usado para forçar que algum
nível de substituição ocorra.
<DL>
<B><DT>subst ?-nobackslashes? ?-nocommands? ?-novariables? </B> <I>string</I>
<DD>Passa a <I>string</I> na fase de substituição Tcl, e retorna a
string original com as seqüências de barra invertida, comandos e variáveis
substituídas por seus equivalentes.
<P>
Se algum dos argumentos <B>-no...</B> estiver presente, então aquele conjunto de
substituições não irá ser feito.
<P>
NOTA: <B>subst</B> não respeita delimitações por chaves ou aspas duplas.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
O interpretador Tcl realiza apenas um passo de substituição durante
a avaliação de comandos. Algumas situações, tais como colocar o nome
de uma variável em uma variável, requer dois passos pela fase de
substituição. Neste caso, o comando <B>subst</B> é util.
<P>
<B>Subst</B> realiza um passo de substituição sem realizar qualquer 
execução de comandos exceto aqueles requeridos para a substituição
ocorrer, ou seja: comandos dentro de <B>[]</B> serão executados, e os
resultados colocados na string de retorno.
<P>
No código do exemplo: <CODE>puts "[subst $$c]\n"</CODE> mostra um exemplo
de colocar um nome de variável em uma variável, e avaliação através de
indireção.
<P>
O comando <B>format</B> pode também ser usado para forçar que algum nível
de substituição ocorra.
<DL>
<B><DT>subst ?-nobackslashes? ?-nocommands? ?-novariables? </B> <I>string</I>
<DD>Passa a <I>string</I> na fase de substituição Tcl, e retorna a
string original com as seqüências de barra invertida, comandos e variáveis
substituídas por seus equivalentes.
<P>
Se algum dos argumentos <B>-no...</B> estiver presente, então aquele conjunto de
substituições não irá ser feito.
<P>
NOTA: <B>subst</B> não respeita delimitações por chaves ou aspas duplas.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Muitas linguagens de programação suportam um conceito chamado indireção.
Isso significa que ao invés de uma variável conter dados ela contém um
ponteiro para onde o dado atualmente está.
<P>
Em Tcl este conceito pode ser implementado colocando o nome de
outra variável em uma variável.
<P>
Por exemplo:
<PRE><CODE>
set a alpha
set c a
</CODE>
</PRE>
Agora, a variável <B>c</B> contém o nome da variável (<B>a</B>) que
atualmente contém o dado (<B>alpha</B>).
<P>
Se você fosse tentar exibir o valor <B>alpha</B>, você poderia tentar
alguma coisa como:
<PRE><CODE>
puts "$$c"
</CODE></PRE>
Isso não irá funcionar. Isso irá imprimir <B>$a</B>.
<P>
Isto é porque Tcl só faz um passo na substituição. Se uma variável requer
dois passos de substituição, isso não irá ocorrer.
<P>
O comando <B>subst</B> é a solução para este problema. Quando uma string é
passada para o comando <B>subst</B> ela passa pela fase normal de substituição 
Tcl, e então dentro do comando <B>subst</B> ela é passada para uma segunda 
fase de substituição. O resultado da segunda substituição é retornado.
<P>
O comando <B>format</B> pode também ser usado para forçar que algum nível de
substituição ocorra.
<P>
Execute o exemplo, e siga adiante com esta explicação.
<P>
A primeira linha no exemplo:
<PRE><CODE>
set a alpha
</CODE></PRE>
apenas atribui uma string simples a uma variável.
<P>
A próxima linha:<PRE><CODE>
set b a
</CODE></PRE>
Atribui a variável <B>b</B> para que ela contenha o nome da
variável <B>a</B>.
<P>
As próximas duas linhas mostram os resultados de executar
<B>puts</B> com os argumentos dentro de chaves (nenhuma substituição
irá ocorrer) ou dentro de aspas duplas (um passo da substituição
será feito quanto Tcl avaliar o comando).
<P>
As duas linhas depois daquela mostram os mesmos argumentos, mas
processa o argumento com o comando <B>subst</B> antes de avaliar
o <B>puts</B>. Note que usar chaves para delimitar o argumento
faz com que <B>subst</B> realize um único passo de substituição,
da mesma forma como é feito pelo interpretador Tcl. Se os
argumentos são delimitados por aspas duplas, então há um passo de
substituição quando o comando <B>subst</B> é avaliado, e então
dentro do comando <B>subst</B>, um segundo passo de substituição
ocorre. Quando a string <B>$$b</B> é substituída enquanto avalia os
argumentos para a chamada a <B>subst</B>, ela fica substituída com
<B>$a</B>, e então dentro do comando <B>subst</B> a string fica
substituída com <B>alpha</B>.
<P>
As próximas três linhas mostram dois métodos diferentes de
forçar a segunda fase de substituição. O primeiro exemplo é
apenas usar <B>format</B> e não adquirir substituição. A próxima
linha mostra a saída do comando <B>format</B> ($a) sendo usada 
como argumento para <B>subst</B>. Isso faz com que dois passos
de substituição ocorram, e <B>alpha</B> é a saída.
<P>
A terceira dessas linhas mostram o comando <B>puts ...</B> sendo avaliado
por <B>eval</B>. Neste caso, o <B>$b</B> é substituído por <B>a</B> quando
o comando <B>format</B> é avaliado.  Isso cria a string:
<PRE><CODE>
"puts \"eval depois de format: $a\""
</CODE>
</PRE>
Quando aquela string é passada para <B>eval</B>, outro passo de
substituições ocorre, e o <B>$a</B> é substituído com a string 
<B>alpha</B>.
<P>
As sete linhas finais neste exemplo mostram como o proc nomeArqTemp
que foi definido nas duas lições anteriores poderiam ser definidas
usando o comando <B>format</B>. A terceira linha deste exemplo,
<CODE>set cmd [format "%s {global num; incr num;" $cmd]</CODE>, 
apenas adiciona a string <B>{global num; incr num;</B> a <B>cmd</B>.
<P>
A quarta linha: <CODE>set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd [pid] ]</CODE>
adiciona o texto <B>return "/tmp/TMP.%s.$num</B> a <B>cmd</B>, e também
substitui o <B>%s</B> com o retorno de <B>pid</B>. Como a string
de <CODE>format</CODE> está dentro de chaves, <B>$num</B> não
é substituída.
<P>
A última linha deste exemplo mostra o corpo do proc nomeArqTemp.
Este é o mesmo corpo que foi criado nas lições anteriores usando os
comandos de lista.
<P>
Se você precisa passar o nome de um vetor para um proc, e então
acessar um valor dentro daquele vetor, o comando format pode ser
usado, como mostrado no último exemplo. Se você usar uma linha como
<CODE><PRE>
eval [set $a($b) $c]
</PRE>
</CODE>
ele tentará avaliar o valor do índice
<B>$b</B> no vetor <B>a</B>, ao invés de substituir
<B>$a</B> com o valor de <B>a</B>, e <B>$b</B> com o valor de
<B>b</B>.
<DL>
<B><DT>subst ?-nobackslashes? ?-nocommands? ?-novariables? </B> <I>string</I>
<DD>Passa a <I>string</I> na fase de substituição Tcl, e retorna a
string original com as seqüências de barra invertida, comandos e variáveis
substituídas por seus equivalentes.
<P>
Se algum dos argumentos <B>-no...</B> estiver presente, então aquele conjunto de
substituições não irá ser feito.
<P>
NOTA: <B>subst</B> não respeita delimitações por chaves ou aspas duplas.
</DL>
:TEXT_END:

:CODE_START:
;# Alguns exemplos de subst:
set a alpha
set b a

puts {a e b sem substituição: $a $$b}
puts "a e b com um passo de substituição: $a $$b"
puts "a e b com subst em chaves: [subst {$a $$b}]"
puts "a e b com subst em aspas duplas: [subst "$a $$b"]\n"


puts "format sem subst [format {$%s} $b]"
puts "format com subst: [subst [format {$%s} $b]]"
eval "puts \"eval depois de format: [format {$%s} $b]\""

;# Criação do proc nomeArqTemp com format

set num 0
set cmd "proc nomeArqTemp {} "
set cmd [format "%s {global num; incr num;" $cmd]
set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd [pid] ]
set cmd [format "%s }" $cmd ]
eval $cmd

puts "[info body nomeArqTemp]"

;# Um exemplo onde format funciona

set a nomeVetor
set b indice
set c novoValor
eval [format "set %s(%s) %s" $a $b $c]

puts "Índice: $b de $a foi atribuído para: $nomeVetor(indice)"

:TEXT_END: