:TITLE: Interpretadores filhos
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl43.lsn,v 1.2 2000/04/24 16:17:53 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: 18/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
O comando <B>interp</B> cria novos interpretadores filhos dentro
de um interpretador existente. Os interpretadores filhos podem
ter seus próprios conjuntos de variáveis e arquivos, ou eles podem
te dar acesso a itens no interpretador pai.
<P>
Se o filho for criado com a opção <B>-safe</B> ele não irá ser capaz
de acessar o sistema de arquivos ou danificar seu sistema.
Esta característica permite que um script avalie o código de um
site desconhecido (e não confiável).
<P>
Os nomes dos interpretadores filhos são uma lista hierárquica. Se
o interpretador <B>foo</B> é um filho do interpretador <B>bar</B>,
então ele pode ser acessado do nível de topo do interpretador como
<CODE>{bar foo}</CODE>.
<P>
O interpretador primário (o que você adquire quando você digita tclsh)
é a lista vazia {}.
<P>
O comando <B>interp</B> tem muitos subcomandos e opções. Um subconjunto
principal é:
<DL>
<B><DT>interp</B> create <I>?-safe? ?nome?</I>
<DD>Cria um novo interpretador e retorna o nome. Se a opção
<I>-safe</I> é usada, o novo interpretador não será capaz
de acessar certas facilidades de sistema perigosas.
<B><DT>interp</B> delete <I>nome</I>
<DD>Exclui o interpretador filho que possui o <I>nome</I> indicado.
<B><DT>interp</B> eval <I>args</I>
<DD>Isso é similar ao comando regular <B>eval</B>, exceto que ele
avalia o script no interpretador filho ao invés de no interpretador
primário. O comando <B>interp eval</B> concatena os args em uma
string, e entrega aquela linha para o interpretador filho avaliar.
<B><DT>interp</B> alias <I>caminhoOrigem comandoOrigem caminhoAlvo comandoAlvo ?arg arg?</I>
<DD>O comando <B>interp alias</B> permite a um script compartilhar procedimentos
entre os interpretadores filhos e entre um interpretador filho e o
interpretador primário.
</DL>
<P>
Note que interpretadores escravos têm um estado e espaço de nomes separado,
mas <B>não</B> têm eventos de laço separados. Eles não são <I>threads</I>,
e eles não executam independentemente. Se um interpretador escravo ficou
parado por causa de uma requisição bloqueante de entrada/saída, por exemplo,
nenhum outro interpretador será processado até que ele seja desbloqueado.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
Para a maioria das aplicações, um único interpretador e subrotinas
são suficientes. Todavia, se você está construindo um sistema
cliente-servidor (por exemplo) você pode precisar ter muitos 
interpretadores conversando com diferentes clientes, e manter 
o estado deles. Você pode fazer isso com variáveis de estado,
convenções de nomeação, ou trocar o estado para e do disco, mais
isso fica confuso.
<P>
O comando <B>interp</B> cria novos interpretadores filhos dentro
de um interpretador existente. Os interpretadores filhos podem
ter seus próprios conjuntos de variáveis e arquivos, ou eles podem
te dar acesso a itens no interpretador pai.
<P>
Se o filho for criado com a opção <B>-safe</B> ele não irá ser capaz
de acessar o sistema de arquivos ou danificar seu sistema.
Esta característica permite que um script avalie o código de um
site desconhecido (e não confiável).
<P>
Os nomes dos interpretadores filhos são uma lista hierárquica. Se
o interpretador <B>foo</B> é um filho do interpretador <B>bar</B>,
então ele pode ser acessado do nível de topo do interpretador como
<CODE>{bar foo}</CODE>.
<P>
O interpretador primário (o que você adquire quando você digita tclsh)
é a lista vazia {}.
<P>
O comando <B>interp</B> tem muitos subcomandos e opções. Um subconjunto
principal é:
<DL>
<B><DT>interp</B> create <I>?-safe? ?nome?</I>
<DD>Cria um novo interpretador e retorna o nome. Se a opção
<I>-safe</I> é usada, o novo interpretador não será capaz
de acessar certas facilidades de sistema perigosas.
<B><DT>interp</B> delete <I>nome</I>
<DD>Exclui o interpretador filho que possui o <I>nome</I> indicado.
<B><DT>interp</B> eval <I>args</I>
<DD>Isso é similar ao comando regular <B>eval</B>, exceto que ele
avalia o script no interpretador filho ao invés de no interpretador
primário. O comando <B>interp eval</B> concatena os args em uma
string, e entrega aquela linha para o interpretador filho avaliar.
<B><DT>interp</B> alias <I>caminhoOrigem comandoOrigem caminhoAlvo comandoAlvo ?arg arg?</I>
<DD>O comando <B>interp alias</B> permite a um script compartilhar procedimentos
entre os interpretadores filhos e entre um interpretador filho e o
interpretador primário.
</DL>
<P>
Note que interpretadores escravos têm um estado e espaço de nomes separado,
mas <B>não</B> têm eventos de laço separados. Eles não são <I>threads</I>,
e eles não executam independentemente. Se um interpretador escravo ficou
parado por causa de uma requisição bloqueante de entrada/saída, por exemplo,
nenhum outro interpretador será processado até que ele seja desbloqueado.
<P>
O exemplo abaixo mostra dois interpretadores filhos sendo criados
sob um interpretador primário {}. A cada um desses interpretadores
é dada uma variável <CODE>nome</CODE> que contém o nome do interpretador.
<P>
Note que o comando <CODE>alias</CODE> faz com que o procedimento
seja avaliado no interpretador no qual o procedimento foi definido,
não no interpretador no qual ele foi avaliado. Se você precisar que
um procedimento exista dentro de um interpretador, você deve utilizar
o comando <CODE> interp eval</CODE> para avaliar um <CODE>proc</CODE>
dentro daquele interpretador. Se você quer que um interpretador seja
capaz de retornar ao interpretador primário (ou outro interpretador)
você pode usar o comando <CODE> interp alias</CODE>.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Para a maioria das aplicações, um único interpretador e subrotinas
são suficientes. Todavia, se você está construindo um sistema
cliente-servidor (por exemplo) você pode precisar ter muitos 
interpretadores conversando com diferentes clientes, e manter 
o estado deles. Você pode fazer isso com variáveis de estado,
convenções de nomeação, ou trocar o estado para e do disco, mais
isso fica um pouco confuso.
<P>
O comando <B>interp</B> cria novos interpretadores filhos dentro
de um interpretador existente. Os interpretadores filhos podem
ter seus próprios conjuntos de variáveis e arquivos, ou eles podem
dar acesso a itens no interpretador pai.
<P>
Se o filho for criado com a opção <B>-safe</B> ele não irá ser capaz
de acessar o sistema de arquivos ou danificar seu sistema.
Esta característica permite que um script avalie o código de um
site desconhecido (e não confiável).
<P>
A opção <B>-safe</B> permite que você construa sistemas baseados no
modelo cliente/servidor no qual um Cliente envia comandos Tcl para o
Servidor, e o Servidor pode avaliar esses comandos em um interpretador
seguro para impedir que clientes mal intencionados danifiquem o Servidor.
Isso permite que você tenha um grande poder para lidar com tais
aplicações, uma vez que
você não precisa definir qualquer nova sintaxe para a comunicação
cliente/servidor, ou escrever qualquer código de tratamento especial.
<P>
Os nomes dos interpretadores filhos são uma lista hierárquica. Se
o interpretador <B>foo</B> é um filho do interpretador <B>bar</B>,
então ele pode ser acessado do nível de topo do interpretador como
<CODE>{bar foo}</CODE>.
<P>
O interpretador primário (o que você adquire quando você digita tclsh)
é a lista vazia {}.
<P>
O comando <B>interp</B> tem muitos subcomandos e opções. Um subconjunto
principal é:
<DL>
<B><DT>interp</B> create <I>?-safe? ?nome?</I>
<DD>Cria um novo interpretador e retorna o nome. Se a opção
<I>-safe</I> é usada, o novo interpretador não será capaz
de acessar certas facilidades de sistema perigosas.
<B><DT>interp</B> delete <I>nome</I>
<DD>Exclui o interpretador filho que possui o <I>nome</I> indicado.
<B><DT>interp</B> eval <I>args</I>
<DD>Isso é similar ao comando regular <B>eval</B>, exceto que ele
avalia o script no interpretador filho ao invés de no interpretador
primário. O comando <B>interp eval</B> concatena os args em uma
string, e entrega aquela linha para o interpretador filho avaliar.
<B><DT>interp</B> alias <I>caminhoOrigem comandoOrigem caminhoAlvo comandoAlvo ?arg arg?</I>
<DD>O comando <B>interp alias</B> permite a um script compartilhar procedimentos
entre os interpretadores filhos e entre um interpretador filho e o
interpretador primário.
</DL>
<P>
Note que interpretadores escravos têm um estado e espaço de nomes separado,
mas <B>não</B> têm eventos de laço separados. Eles não são <I>threads</I>,
e eles não executam independentemente. Se um interpretador escravo ficou
parado por causa de uma requisição bloqueante de entrada/saída, por exemplo,
nenhum outro interpretador será processado até que ele seja desbloqueado.
<P>
O exemplo abaixo mostra dois interpretadores filhos sendo criados
sob o interpretador primário {}. A cada um desses interpretadores
é dada uma variável <CODE>nome</CODE> que contém o nome do interpretador
usando o comando
<CODE> interp eval $int [list set nome $int]</CODE>.
<P>
Note o uso da lista, aspas duplas e strings delimitadas
por colchetes para os comandos <CODE>interp eval</CODE>. 
O comando <CODE>interp eval</CODE> concatena os argumentos em uma
lista, como o comando <CODE>eval</CODE> faz. Se você tentar utilizar
um comando <CODE> interp eval</CODE> dessa forma:
<P>
<CODE>interp eval $foo [list puts "o valor de bar em $foo é $bar"]</CODE>
<P>
Ambos, <CODE>$foo</CODE> e <CODE>$bar</CODE> serão substituídos no
interpretador pai antes da linha ser avaliada no interpretador filho.
<P>
Se você preceder <CODE>$bar</CODE> com uma barra invertida para substituir
<CODE>$foo</CODE> no pai e <CODE>$bar</CODE> no filho, dessa forma:
<P>
<CODE>interp eval $foo [list puts "o valor de bar em $foo é \$bar"]</CODE>
<P>
Você irá encontrar aquela saída remontada:
<P>
<CODE> o valor de bar em interp2 é $bar</CODE>
<P>
Usando o comando <CODE>list</CODE> para agrupar os argumentos para
<CODE>interp eval</CODE> avaliar faz com que o comando passado
para o interpretador filho seja remontado dessa forma:
<P>
puts {o valor de bar em interp2 é $bar}
<P>
Porque listas são agrupadas com chaves. Uma vez que o argumento para
<CODE>puts</CODE> no interpretador filho está agrupado com chaves,
nenhuma substituição ocorre.
<P>
Se você quer que substituições ocorram no interpretador filho, você
pode precisar criar o comando usando chaves, ou usando os comandos
<CODE>format</CODE> ou <CODE>concat</CODE> como mostrado nas lições
32, 33 e 34.
<P>
A última linha no exemplo é um erro.
O comando <CODE>interp alias</CODE> faz com que o procedimento seja
avaliado no interpretador no qual o procedimento foi definido, não
no interpretador no qual ele foi avaliado. Se você precisar que
um procedimento exista dentro de um interpretador, você deve utilizar
o comando <CODE> interp eval</CODE> para avaliar um <CODE>proc</CODE>
dentro daquele interpretador. Se você quer que um interpretador seja
capaz de retornar ao interpretador primário (ou outro interpretador)
você pode usar o comando <CODE> interp alias</CODE>.
:TEXT_END:

:CODE_START:
set i1 [interp create primeiroFilho]
set i2 [interp create segundoFilho]

puts "primeiro interpretador filho:  $i1"
puts "segundo interpretador filho: $i2\n"

# Atribui uma variável "nome" em cada interpretador filho, e
# cria um procedimento dentro de cada interpretador
# para retornar aquele valor

foreach int [list $i1 $i2] {
  ;# Crio o conteúdo de cada um dos interpretadores filhos
  ;# A linha de baixo poderia ser: [list set nome $int]
  interp eval $int set nome $int
  interp eval $int {proc nomeAtribuido {} { global nome; return "O nome retornado é: $nome" } }
}  

foreach int [list $i1 $i2] {
    interp eval $int "puts \"EVAL EM $int: nome é \$nome\""
    puts "Retorno de 'nomeAtribuido' - [interp eval $int nomeAtribuido]"
}

#
# Um pequeno programa para retornar o valor do "nome"
#
proc retornarNome {} {
    global nome
    return "Nome retornado é: $nome"
}

#
# Confere um outro nome para aquele procedimento (alias) para um proc em $i1
#
# $1 ........... caminhoOrigem
# retornarNome.. comandoOrigem
# {} ........... caminhoAlvo
# retornarNome.. comandoAlvo
#
interp alias $i1 retornarNomePai {} retornarNome

puts ""

# Isso é um erro. O alias fez com que a avaliação
# acontecesse no interpretador {}, onde a variável 'nome'
# não está definida
#
# Descomente a linha abaixo para fazer o script funcionar
# com sucesso
# set nome teste
puts "primeiroFilho exibe - [interp eval $i1 retornarNomePai]"
:TEXT_END:
