:TITLE: Mais deputação - trace
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl37.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: 17/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
O interpretador Tcl suporta um método para rastrear quando e
como uma variável é acessada. Com o comando <B>trace</B>, 
um procedimento pode ser definido para ser executado toda
vez que uma variável é lida, escrita ou desatribuída.
<P>
O comando <B>trace</B> executa no mesmo nível de pilha do
acesso à variável. O proc que <I>trace</I> chama está um nível de
pilha abaixo. Portanto, com o comando uplevel, um procedimento
chamado via <I>trace</I> pode exibir as condições que foram
atribuídas quando uma variável foi acessada.
<DL>
<B><DT>trace variable</B> <I>nomeVariavel operacao nomeProc</I>
<DD> Coloca um <I>trace</I> na variável <I>nomeVariavel</I>. Toda vez que
<I>nomeVariavel</I> é acessada para a operação especificada no argumento
<I>operacao</I>, o procedimento <I>nomeProc</I> será chamado.
<P>
<I>Operação pode ser um dos seguintes:</I>
<DL>
<DD>r ...... Read (Leitura)
<DD>w .... Write (Escrita)
<DD>u ...... Unset (Desatribuição)
</DL>
<P>
Uma variável pode ser desatribuída explicitamente com o comando <B>unset</B>,
ou implicitamente quando um procedimento retorna, e todas as variáveis locais
são liberadas.
<P>
Quando <I>nomeVariavel</I> é acessada, <I>procName</I> irá ser chamado com três
argumentos: <I>nomeVariavel, nomeElemento</I> e <I>operacao</I>.  Se a
variável sendo acessada for um vetor associativo, então <I>nomeElemento</I>
irá conter o nome do elemento sendo acessado. Se <I>nomeVariavel</I>
for uma variável simples, então <I>nomeElemento</I> irá ser uma string vazia.
<I>Operacao</I> é a operação que foi feita em <I>nomeVariavel</I> para
chamar a ação de <B>trace</B>.
<B><DT>trace vdelete</B> <I>nomeVariavel operacao nomeProc</I>
<DD>Cancela a ação de <I>trace</I> para a <I>operacao</I> em <I>nomeVariavel</I>.
<B><DT>trace vinfo</B> <I>nomeVariavel</I>
<DD>Retorna informação sobre os <I>traces</I> aplicados a <I>nomeVariavel</I>.
</DL>

:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
Quando você está depurando um programa, é algumas vezes útil saber
quando uma variável foi alterada. O interpretador Tcl suporta um
método para rastrear quando e como uma variável foi acessada. Com
o comando <B>trace</B>, um procedimento pode ser definido para
ser executado toda vez que uma variável for lida, escrita, ou
desatribuída. Com este comando você pode determinar em qual
proc uma variável foi modificada, para qual valor ela foi alterada,
e como outras variáveis estavam nesse momento.
<P>
O comando <B>trace</B> executa no mesmo nível de pilha do
acesso à variável. O proc que <I>trace</I> chama está um nível de
pilha abaixo. Portanto, com o comando uplevel, um procedimento
chamado via <I>trace</I> pode exibir as condições que foram
atribuídas quando uma variável foi acessada.
<DL>
<B><DT>trace variable</B> <I>nomeVariavel operacao nomeProc</I>
<DD> Coloca um <I>trace</I> na variável <I>nomeVariavel</I>. Toda vez que
<I>nomeVariavel</I> é acessada para a operação especificada no argumento
<I>operacao</I>, o procedimento <I>nomeProc</I> será chamado.
<P>
<I>Operação pode ser um dos seguintes:</I>
<DL>
<DD>r ...... Read (Leitura)
<DD>w .... Write (Escrita)
<DD>u ...... Unset (Desatribuição)
</DL>
<P>
Uma variável pode ser desatribuída explicitamente com o comando <B>unset</B>,
ou implicitamente quando um procedimento retorna, e todas as variáveis locais
são liberadas.
<P>
Quando <I>nomeVariavel</I> é acessada, <I>procName</I> irá ser chamado com três
argumentos: <I>nomeVariavel, nomeElemento</I> e <I>operacao</I>.  Se a
variável sendo acessada for um vetor associativo, então <I>nomeElemento</I>
irá conter o nome do elemento sendo acessado. Se <I>nomeVariavel</I>
for uma variável simples, então <I>nomeElemento</I> irá ser uma string vazia.
<I>Operacao</I> é a operação que foi feita em <I>nomeVariavel</I> para
chamar a ação de <B>trace</B>.
<B><DT>trace vdelete</B> <I>nomeVariavel operacao nomeProc</I>
<DD>Cancela a ação de <I>trace</I> para a <I>operacao</I> em <I>nomeVariavel</I>.
<B><DT>trace vinfo</B> <I>nomeVariavel</I>
<DD>Retorna informação sobre os <I>traces</I> aplicados a <I>nomeVariavel</I>.
</DL>

:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Um valor de variável muda ferqüentemente durante a execução de um programa
de computador. Algumas vezes o valor é alterado em um lugar ou de uma
maneira que o programador não espera. Por exemplo, se você tem uma
variável que você está usando para manter um valor particular, e então
esquece e usa aquele mesmo nome de variável como um contador em um laço
o valor da variável será perdido.
<P> 
Você pode evitar este tipo de bug utilizando longos e descritivos
nomes de variáveis, ao invés de digitar nomes fáceis como
<B>i</B> ou <B>x</B>.
<P>
Você pode interromper este tipo de bug utilizando o comando <B>trace</B>.
<P>
O comando <B>trace</B> permite a você indicar um procedimento a ser executado
toda vez que uma variável em particular é lida, escrita ou desatribuída.
<P>
Quando uma variável com um <I>trace</I> atribuído é acessada, o proc
declarado no comando <B>trace</B> é executado. O comando <B>trace</B> 
executa no mesmo nível de pilha do
acesso à variável. O proc que <I>trace</I> chama está um nível de
pilha abaixo. Portanto, com o comando uplevel, um procedimento
chamado via <I>trace</I> pode exibir as condições que foram
atribuídas quando uma variável foi acessada.
<P>
Quando um <I>trace</I> é ativado, ele chama o procedimento com três argumentos.
Esses argumentos são o nome da variável que invocou o <I>trace</I>, o elemento
no vetor que invocou o <I>trace</I>, se o trace foi indicado como uma variável
vetor associativo. Se a variável que invocou o <B>trace</B> foi uma variável
normal, esse argumento será uma string vazia. E, finalmente, a operação que
foi feita na variável para fazer com que o <I>trace</I> seja ativado.
<P>
Execute o exemplo, e observe o exemplo de código agora.
<P>
O proc <B>procTrace</B> é definido primeiro. Este é o procedimento que
será chamado neste exemplo quando um <I>trace</I> for ativado. Os
três argumentos para este proc são nomeVariavel, elementoVetor, e
operacao.
<P>
A primeira linha do proc apenas atribui um vetor associativo local com
as strings equivalentes das operações de <B>w</B>, <B>u</B>, e <B>r</B> 
que serão passadas para esta função. Isso é feito simplesmente para tornar
a saída mais fácil de ler.
<P>
A próxima seqüência de linhas adquire o valor atual da pilha e a reduz
em um nível. Se o valor for 0, então o <I>trace</I> foi chamado do
nível principal. Se o valor for maior que 0, então o <I>trace</I> foi 
chamado de um proc, e <CODE>info level $nivel</CODE> irá retornar o
nome do proc e os argumentos para exibir mais tarde.
<P>
A seção final deste proc checa <B>elementoVetor</B> para determinar
se a variável que disparou o <B>trace</B> foi uma variável simples,
ou um vetor associativo. Se <CODE>$elementoVetor</CODE> contém uma
string vazia, então a variável que disparou o <I>trace</I> foi uma
variável simples, e <CODE>$nomeVariavel</CODE> é exibido na saída. Se
<CODE>$elementoVetor</CODE> não é igual à string vazia, então
<CODE>$nomeVariavel</CODE> é um vetor associativo, e o elemento do vetor
será exibido.
<P>
Depois, o <B>procTeste</B> é definido. Este proc atribui o valor do
primeiro argumento, e lê o segundo. Ele realiza comandos
<B>upvar</B> porque Tcl, por padrão, faz chamadas por valor, ao invés
de chamadas por referência quando uma variável é passada para um proc.
Portanto, uma cópia do conteúdo de <CODE>i1</CODE> e <CODE>i2</CODE> seria
passada ao procTeste, ao invés da variável atual. Neste caso, o
<B>trace</B> não seria disparado, uma vez que variáveis sendo
rastreadas não deveriam ser acessadas.
<P>
Depois, o comando <B>trace</B> é chamado para as variáveis <B>i1</B> e
<B>i2</B>. Note que essas variáveis não foram definidas ainda. O
comando <B>trace</B> tem três subcomandos, um dos quais é <B>variable</B>.
Este é o comando que permite a <B>trace</B> ser ativado quando uma
variável em particular é acessada. Essas três linhas marcam um <I>trace</I>
para ser ativado quando a variável <B>i1</B> for escrita, e quando
a variável <B>i2</B> for lida ou escrita.
<P>
Quando a variável <B>i2</B> é inicializada para "valorTeste", o comando
<I>trace</I> é chamado, e a saída exibe que i2 foi escrita no nível
principal.
<P>
Note que quando <B>procTeste</B> é chamado, a saída mostra os nomes
locais das variáveis atribuídas no comando upvar, ao invés dos
nomes que foram usados quando o <B>trace</B> foi ativado.
<P>
O subcomando de <B>trace</B>, <B>vinfo</B>, irá retornar uma lista de
<I>traces</I> na variável. Isso é demonstrado nas próximas
duas linhas do exemplo.
<P>
O terceiro subcomando de <B>trace</B> é o <B>vdelete</B>.  Este comando
apaga um trace. As últimas poucas linhas do exemplo mostram o <I>trace</I>
<I>read</I> em <B>i2</B> sendo removido. Depois do <B>vdelete</B>, o <I>trace</I>
com a operação <I>read</I> não aparece na lista de <I>traces</I> de 
<B>vinfo</B>, e o <I>trace</I> não é disparado quando <B>procTeste</B> é chamado.
<DL>
<B><DT>trace variable</B> <I>nomeVariavel operacao nomeProc</I>
<DD> Coloca um <I>trace</I> na variável <I>nomeVariavel</I>. Toda vez que
<I>nomeVariavel</I> é acessada para a operação especificada no argumento
<I>operacao</I>, o procedimento <I>nomeProc</I> será chamado.
<P>
<I>Operação pode ser um dos seguintes:</I>
<DL>
<DD>r ...... Read (Leitura)
<DD>w .... Write (Escrita)
<DD>u ...... Unset (Desatribuição)
</DL>
<P>
Uma variável pode ser desatribuída explicitamente com o comando <B>unset</B>,
ou implicitamente quando um procedimento retorna, e todas as variáveis locais
são liberadas.
<P>
Quando <I>nomeVariavel</I> é acessada, <I>procName</I> irá ser chamado com três
argumentos: <I>nomeVariavel, nomeElemento</I> e <I>operacao</I>.  Se a
variável sendo acessada for um vetor associativo, então <I>nomeElemento</I>
irá conter o nome do elemento sendo acessado. Se <I>nomeVariavel</I>
for uma variável simples, então <I>nomeElemento</I> irá ser uma string vazia.
<I>Operacao</I> é a operação que foi feita em <I>nomeVariavel</I> para
chamar a ação de <B>trace</B>.
<B><DT>trace vdelete</B> <I>nomeVariavel operacao nomeProc</I>
<DD>Cancela a ação de <I>trace</I> para a <I>operacao</I> em <I>nomeVariavel</I>.
<B><DT>trace vinfo</B> <I>nomeVariavel</I>
<DD>Retorna informação sobre os <I>traces</I> aplicados a <I>nomeVariavel</I>.
</DL>
:TEXT_END:

:CODE_START:

proc procTrace {nomeVariavel elementoVetor operacao} {
  set op(w) "Write"; set op(u) "Unset"; set op(r) "Read"

  set nivel [info level]
  incr nivel -1
  if {$nivel > 0} {
     set procid [info level $nivel]
     } else {set procid "principal"}

  if {![string match $elementoVetor ""]} {
    puts "TRACE: $op($operacao) $nomeVariavel($elementoVetor) em $procid"
    } else {
    puts "TRACE: $op($operacao) $nomeVariavel em $procid"
    }
  }

proc procTeste {entrada1 entrada2} {
  upvar $entrada1 i
  upvar $entrada2 j

  set i 2
  set k $j
  }

trace variable i1 w procTrace
trace variable i2 r procTrace
trace variable i2 w procTrace

set i2 "valorTeste"

puts "\nChamando procTeste"
procTeste i1 i2

puts "\nTraces em i1: [trace vinfo i1]"
puts "Traces em i2: [trace vinfo i2]\n"

trace vdelete i2 r procTeste
puts "Traces em i2 depois de vdelete: [trace vinfo i2]"

puts "\nChamando procTeste novamente"
procTeste i1 i2


:TEXT_END:

