Baixe o app para aproveitar ainda mais
Prévia do material em texto
GCC 105 – LINGUAGENS DE PROGRAMAÇÃO I AULA 6 – Nomes e Vinculação II 1º Semestre de 2015 Prof. Janderson Rodrigo de Oliveira Universidade Federal de Lavras Departamento de Ciência da Computação Escopo • O escopo de uma variável é a faixa de sentenças nas quais ela é visível. • Uma variável é visível em uma sentença se ela pode ser referenciada nessa sentença. • As regras de escopo de uma linguagem determinam como uma ocorrência em particular de um nome é associada com uma variável. Escopo • Uma variável é local a uma unidade ou a um bloco de programa se ela for lá declarada. • As variáveis não locais de uma unidade ou de um bloco de programa são aquelas visíveis dentro da unidade ou do bloco de programa, mas não declaradas nessa unidade ou nesse bloco. Escopo Estático • O ALGOL 60 introduziu o método de vincular nomes a variáveis não locais, chamado de escopo estático, copiado por muitas linguagens imperativas subsequentes. • O escopo estático é chamado assim porque o escopo de uma variável pode ser determinado estaticamente – ou seja, antes da execução. • Isso permite a um compilador determinar o tipo de cada variável. Escopo Estático • Existem duas categorias de escopo estático: – Aquelas nas quais subprogramas podem ser aninhados, as quais criam escopos estático aninhados; – Aquelas nas quais subprogramas não podem ser aninhados. Escopos estáticos para subprogramas também são criados, mas os aninhados são criados apenas por definições de classes aninhadas ou de blocos aninhados. • Ada, JavaScript, Fortran 2003 e PHP permitem subprogramas aninhados, mas as linguagens baseadas em C não. Escopo Estático • Inicialmente vamos nos concentrar nas linguagens que permitem subprogramas aninhados e vamos realizar uma discussão simplificada neste cenário. • Quando o leitor de um programa encontra uma referência a uma variável, os atributos dessa variável pode ser determinados por meio da descoberta da sentença na qual ela está declarada. • Em linguagens de escopo estático com subprogramas, esse processo pode ser visto da seguinte forma. Escopo Estático • Suponha que uma referência é feita a uma variável x em um subprograma Sub1. • Se nenhuma declaração for encontrada em Sub1, a busca continua nas declarações do subprograma que declarou Sub1, chamado de seu pai estático. • Se nenhuma declaração for encontrada lá, a busca continua para a próxima unidade maior que envolve o pai estático de Sub1, e assim por diante. Escopo Estático • O processo se repete até que uma declaração para x seja encontrada ou a maior unidade de declaração tenha sido buscada sem sucesso. • Nesse caso, um erro de variável não declarada é detectado. • Exemplo: considere o seguinte procedimento em Ada, chamado Externo, no qual estão aninhados os procedimentos Sub1 e Sub2. Escopo Estático procedure Externo is X : Integer; procedure Sub1 is X : Integer; begin -- de Sub1 ... end; -- de Sub1 procedure Sub2 is begin -- de Sub2 ... X ... end; -- de Sub2 begin -- de Externo ... end; -- de Externo Escopo Estático • Em linguagens que usam escopo estático, independentemente de ser permitido o uso de subprogramas aninhados ou não, algumas declarações de variáveis podem ser ocultadas de outros segmentos de código. • Em Ada, variáveis ocultas de escopos ancestrais podem ser acessadas com referências seletivas, que incluem o nome do escopo ancestral. • Exemplo: o X declarado em Externo pode ser acessado em Sub1 pela referência Externo.X. Blocos • Muitas linguagens permitem que novos escopos estáticos sejam definidos no meio do código executável. • Esse poderoso conceito, introduzido no ALGOL 60, permite uma seção de código ter suas próprias variáveis locais, cujo escopo é minimizado. • Tais variáveis são dinâmicas da pilha, de forma que seu armazenamento é alocado quando a seção é alcançada e liberado quando a seção é abandonada. Blocos • As linguagens baseadas em C permitem que quaisquer sentenças compostas tenham declarações e, dessa forma, definam um novo escopo. • Tais sentenças compostas são blocos. Exemplo: if (list[i] < list[j]) { int temp; temp = list[i]; list[i] = list[j]; list[j] = temp; } Blocos • Os escopos criados por blocos, que podem ser aninhados em blocos maiores, são tratados exatamente como aqueles criados por subprogramas. void sub() { int contador; ... while (...) { int contador; contador++; .... } ... } Blocos • Em geral, uma declaração de uma variável efetivamente esconde quaisquer declarações de variáveis com o mesmo nome no escopo externo maior. • O código do último exemplo seria permitido em C e C++, mas seria ilegal em Java e C#. – Os projetistas de Java e C# acreditavam que o reuso de nomes em blocos aninhados era muito propenso a erros para ser permitido. Ordem de Declaração • Em C89, como em algumas outras linguagens, todas as declarações de dados em uma função, exceto aquelas em blocos aninhados, devem aparecer no início da função. • Algumas linguagens – como C99, C++, Java e C# – permitem que as declarações de variáveis apareçam em qualquer lugar onde uma sentença poderia aparecer em uma unidade de programa. Escopo Global • Algumas linguagens, incluindo C, C++, PHP e Python, permitem uma estrutura de programa que é uma sequência de definições de funções, nas quais as definições de variáveis podem aparecer fora das funções. • Definições de variáveis fora de funções em um arquivo criam variáveis globais, potencialmente visíveis a essas funções. • Uma variável global em C é implicitamente visível em todas as funções subsequentes no arquivo, exceto aquelas que incluem uma declaração de uma variável local com o mesmo nome. Escopo Global • Uma variável global em C definida após uma função pode ser tornada visível na função declarando-a como externa, como: • Outro exemplo: regras de visibilidade para variáveis globais em Python. – Uma variável global pode ser referenciada em uma função; – Uma variável global pode ter valores atribuídos a ela apenas se tiver sido declarada como global na função. extern int soma; Escopo Global • Exemplo em Python: • Saída: dia = “Segunda” def teste(): print “O dia global e: ”, dia teste() O dia global e: Segunda Escopo Global • Exemplo em Python: • Saída: dia = “Segunda” def teste(): print “O dia global e: ”, dia dia = “Terça” print “O novo dia global e: ”, dia teste() UnboundLocalError Escopo Global • Exemplo em Python: • Saída: dia = “Segunda” def teste(): global dia print “O dia global e: ”, dia dia = “Terça” print “O novo dia global e: ”, dia teste() O dia global e: Segunda O novo dia global e: Terça Avaliação do Escopo Estático • Fornece um método de acesso a não locais que funciona bem em muitas situações. • Desvantagens: – Fornece mais acesso do que o necessário; – Sistemas se software são altamente dinâmicos e os desenvolvedores têm a tendência a descartar restrições de acesso às variáveis e subprogramas ao realizar manutenções. Escopo Dinâmico • O escopo de variáveis em APL, SNOBOL4 e nas primeiras versões de LISP era dinâmico. • O escopo dinâmico é baseado na sequência de chamadas de subprogramas, não em seu relacionamento espacial uns com os outros. • Logo, o escopo pode ser determinado apenas em tempo de execução. Escopo Dinâmico procedure Externo is X : Integer; procedure Sub1 is X : Integer; begin -- de Sub1 ... end; -- de Sub1 procedure Sub2 is begin -- de Sub2 ... X ... end; -- de Sub2 begin -- de Externo ... end; -- de Externo Escopo Dinâmico • Assuma que asregras de escopo dinâmico se aplicam a referências não locais. O significado do identificador X referenciado em Sub2 é dinâmico. • Ele pode referenciar a qualquer uma das declarações de X, dependendo da sequência de chamadas. • Uma maneira pela qual o significado correto de X pode ser determinado em tempo de execução é iniciar a busca com as variáveis locais. Escopo Dinâmico • Quando a busca por declarações locais falha, as declarações do pai dinâmico, o procedimento que o chamou, são procuradas. • Se uma declaração para X não é encontrada lá, a busca continua no pai dinâmico desse procedimento chamador, e assim por diante, até que uma declaração de X seja encontrada. • Se nenhuma for encontrada, ocorre um erro em tempo de compilação. Avaliação do Escopo Dinâmico • Uma referência para uma variável não local pode se referir a diferentes variáveis não locais durante diferentes execuções do subprograma. • Impossibilidade de verificar os tipos das referências a não locais estaticamente. • O escopo dinâmico faz os programas serem muito mais difíceis de serem lidos. Essa tarefa é praticamente impossível para um leitor humano. Escopo Estático e Escopo Dinâmico • Os programas em linguagens com escopo estático são mais fáceis de ler, mais confiáveis e executam mais rapidamente do que programas equivalentes em linguagens com escopo dinâmico. Escopo e Tempo de Vida • Algumas vezes, o escopo e o tempo de vida de uma variável parecem ser relacionadas. • Exemplo: considere uma variável declarada em um método Java que não contém nenhuma chamada a método. – Escopo: declaração – final do método; – Tempo de vida: entrada no método – fim da execução do método. Escopo e Tempo de Vida • Apesar do escopo e do tempo de vida da variável serem diferentes, devido ao escopo estático ser um conceito textual, ou espacial, enquanto o tempo de vida é um conceito temporal, eles parecem ser relacionados nesse caso. • Esse relacionamento aparente entre escopo e tempo de vida não se mantém em outras situações. • Em C e C++, por exemplo, uma variável declarada em uma função usando o especificador static é estaticamente vinculada ao escopo dessa função e ao armazenamento. Escopo e Tempo de Vida • Logo, seu escopo é estático e local à função, mas seu tempo de vida se estende pela execução completa do programa do qual ela é parte. • O escopo e o tempo de vida também não são relacionados quando chamadas a subprogramas estão envolvidas. Escopo e Tempo de Vida void imprimir() { ... } /*Fim de imprimir*/ void calcular() { int soma; ... imprimir(); } /*Fim de calcular*/ Ambientes de Referenciamento • O ambiente de referenciamento de uma sentença é a coleção de todas as variáveis visíveis na sentença. • O ambiente de referenciamento de uma sentença em uma linguagem de escopo estático é composto pelas variáveis declaradas em seu escopo local mais a coleção de todas as variáveis de seus escopos ancestrais visíveis. • É necessário enquanto a sentença é compilada. Ambientes de Referenciamento • Considere o seguinte esqueleto de programa em Ada: procedure Exemplo is A, B : Integer; procedure Sub1 is X, Y : Integer; begin -- de Sub1 ... � 1 end; -- de Sub1 procedure Sub2 is X : Integer; ... procedure Sub3 is X : Integer; begin -- de Sub3 ... � 2 end; -- de Sub3 begin -- de Sub2 ... � 3 end -- de Sub2 begin -- de Exemplo ... � 4 end -- de Exemplo Ambientes de Referenciamento • Os ambientes de referenciamento dos pontos de programa indicados são: Ponto Ambiente de referenciamento 1 X e Y de Sub1, A e B de Exemplo 2 X de Sub3, (X de Sub2 está oculto), A e B de Exemplo 3 X de Sub2, A e B de Exemplo Ambientes de Referenciamento • O ambiente de referenciamento de uma sentença em uma linguagem de escopo dinâmico é composto pelas variáveis declaradas localmente, mais as variáveis de todos os subprogramas ativos. • Um subprograma está ativo se sua execução já tiver começado, mas não terminado ainda. • Considere o exemplo a seguir. Assuma que as únicas chamadas a funções são: main chama sub2, que chama sub1. Ambientes de Referenciamento • Considere o seguinte esqueleto de programa em Ada: void sub1() { int a, b; ... � 1 } /*Fim de sub1*/ void sub2() { int b, c; ... � 2 sub1(); } /*Fim de sub2*/ voidmain() { int c, d; ... � 3 sub2(); } /*Fim da main*/ Ambientes de Referenciamento • Os ambientes de referenciamento dos pontos de programa indicados são: Ponto Ambiente de referenciamento 1 a e b de sub1, c de sub2, d da main, (c da main e b de sub2 estão ocultas) 2 b e c de sub2, d da main, (c da main está oculta) 3 c e d da main Constantes Nomeadas • Uma constante nomeada é uma variável vinculada a um valor apenas uma vez. • Constantes nomeadas são úteis para auxiliar a legibilidade e a confiabilidade dos programas. • A legibilidade por ser melhorada, por exemplo, ao ser usado no nome pi em vez da constante 3.14159. • Outro uso importante de constantes nomeadas é na parametrização de um programa. Constantes Nomeadas • Exemplo em Java: void Exemplo() { int [] lista = new int[100]; String[] listaStr = new String[100]; ... for (indice = 0; indice < 100; indice++){ ... } for (indice = 0; indice < 100; indice++){ ... } ... media = soma/100; ... } Constantes Nomeadas • Exemplo em Java - parametrização: void Exemplo() { final int tamanho = 100; int [] lista = new int[tamanho]; String[] listaStr = new String[tamanho]; ... for (indice = 0; indice < tamanho; indice++){ ... } for (indice = 0; indice < tamanho; indice++){ ... }... media = soma/tamanho; ... }
Compartilhar