369
1 Capítulo I – Introdução ! " #$%& Uma Linguagem de Programação (LP) é um instrumento utilizado pelo profissional de computação para escrever programas, isto é, conjuntos de instruções a serem seguidas pelo computador para realizar um determina- do processo. Em virtude das limitações físicas dos computadores e da pouca maturida- de da ciência da computação na época de surgimento dos primeiros com- putadores, eles só podiam ser programados através de linguagens de pro- gramação muito simples. Tais linguagens disponibilizavam um pequeno conjunto de tipos de instruções capazes de realizar ações muito elementa- res e se caracterizavam por serem de uso exclusivo de um computador específico. Por conta disso, hoje elas são conhecidas como linguagem de máquina ou de baixo nível. À medida que a computação avançava e se vislumbrava o potencial dessa nova ferramenta, as aplicações iam se tornando cada vez mais complexas. Nessa época, foi constatado que o uso de linguagens tão simples e especí- ficas reduzia significativamente a produtividade dos programadores e im- pedia a ampla disseminação dos computadores. Para contornar esse pro- blema, surgiram as linguagens de programação de alto nível. Em contras- te com as linguagens de máquina, essas linguagens se caracterizam por não serem específicas para um computador e por terem um conjunto mais amplo e expressivo de tipos de instrução. O enfoque desse livro é no estudo dessas linguagens. Dessa maneira, sempre que for utilizado o termo “linguagem de programação”, estaremos nos referindo a uma linguagem de programação de alto nível. Para que os programadores possam construir programas em uma determi- nada linguagem é necessário definir os símbolos que podem ser utilizados e a forma como devem ser combinados para produzir um programa váli- do. Além disso, os programadores também precisam entender como um programa válido será executado pelo computador. Embora existam inúmeras linguagens de programação, cada qual com seu próprio conjunto de símbolos e regras para formação e interpretação de programas, é possível e interessante estudá-las focando os principais con-

Linguagens de Programação - Conceitos e Técnicas - Varejao

  • Upload
    jislane

  • View
    971

  • Download
    16

Embed Size (px)

Citation preview

  • 1

    Captulo I Introduo

    !

    "#$%&

    Uma Linguagem de Programao (LP) um instrumento utilizado pelo profissional de computao para escrever programas, isto , conjuntos de instrues a serem seguidas pelo computador para realizar um determina-do processo. Em virtude das limitaes fsicas dos computadores e da pouca maturida-de da cincia da computao na poca de surgimento dos primeiros com-putadores, eles s podiam ser programados atravs de linguagens de pro-gramao muito simples. Tais linguagens disponibilizavam um pequeno conjunto de tipos de instrues capazes de realizar aes muito elementa-res e se caracterizavam por serem de uso exclusivo de um computador especfico. Por conta disso, hoje elas so conhecidas como linguagem de mquina ou de baixo nvel. medida que a computao avanava e se vislumbrava o potencial dessa nova ferramenta, as aplicaes iam se tornando cada vez mais complexas. Nessa poca, foi constatado que o uso de linguagens to simples e espec-ficas reduzia significativamente a produtividade dos programadores e im-pedia a ampla disseminao dos computadores. Para contornar esse pro-blema, surgiram as linguagens de programao de alto nvel. Em contras-te com as linguagens de mquina, essas linguagens se caracterizam por no serem especficas para um computador e por terem um conjunto mais amplo e expressivo de tipos de instruo. O enfoque desse livro no estudo dessas linguagens. Dessa maneira, sempre que for utilizado o termo linguagem de programao, estaremos nos referindo a uma linguagem de programao de alto nvel. Para que os programadores possam construir programas em uma determi-nada linguagem necessrio definir os smbolos que podem ser utilizados e a forma como devem ser combinados para produzir um programa vli-do. Alm disso, os programadores tambm precisam entender como um programa vlido ser executado pelo computador. Embora existam inmeras linguagens de programao, cada qual com seu prprio conjunto de smbolos e regras para formao e interpretao de programas, possvel e interessante estud-las focando os principais con-

  • 2

    ceitos que lhes so comuns e esclarecendo como eles podem ser utiliza-dos na programao e como podem ser implementados nas linguagens. Conceitos relevantes e especficos existentes em uma linguagem particu-lar tambm devem ser compreendidos pois podem ser um instrumento valioso para melhor entendimento de uma tcnica de programao ou pa-ra futuras evolues e novos projetos de linguagens. Para tornar o aprendizado de um conceito mais efetivo, importante que ele seja utilizado na construo de um programa em uma linguagem de programao que oferea recursos para utilizao do conceito. As trs linguagens (C, C++ e JAVA), que so usadas primordialmente nos exem-plos deste texto, oferecem recursos para a programao da grande maioria dos conceitos abordados aqui. O estudo e a discusso sobre as caractersticas e os mecanismos existentes em linguagens de programao requer entendimento sobre as proprieda-des desejveis em uma linguagem de programao, os papis que podem ser exercidos pela linguagem e o contexto no qual seu projeto foi realiza-do. Nesse captulo apresentada uma introduo ao estudo de Linguagens de Programao. So discutidas as razes para se conhecer profundamente esse tema, o papel das linguagens de programao no processo de desen-volvimento de programas e as principais propriedades desejveis em lin-guagens de programao. Em seguida, so apresentadas noes importan-tes sobre a especificao, implementao e padronizao de uma lingua-gem. Cada um dos paradigmas mais comuns de linguagens de programa-o so brevemente abordados. Por fim, discutida a evoluo e histria dessas linguagens.

    1.1 Razes para Estudar Linguagens de Programao

    Embora qualquer programador reconhea que linguagens de programao so instrumentos fundamentais dentro de sua especialidade, importante destacar quais so os benefcios que um estudo aprofundado de Lingua-gens de Programao pode proporcionar ao estudante. Esses benefcios so apresentados a seguir: a) Maior capacidade de desenvolver solues computacionais para pro-

    blemas. Uma maior compreenso sobre os conceitos de uma LP pode aumentar nossa habilidade em como pensar e resolver problemas. Por exemplo, o conhecimento do conceito de tipos abstratos de dados es-timulam a utilizao desse mtodo de programao mesmo em LPs que no possuem mecanismos especficos para a sua implementao.

  • 3

    b) Maior habilidade ao usar uma LP. O maior entendimento a respeito das funcionalidades e implementao de uma LP possibilita ao pro-gramador construir programas melhores e mais eficientes. Por exem-plo, conhecendo como as LPs so implementadas pode-se entender porque algoritmos recursivos so menos eficientes que os iterativos correspondentes.

    c) Maior capacidade para escolher LPs apropriadas. Conhecer os recur-sos oferecidos por uma linguagem e saber como esses recursos so implementados pode determinar uma boa escolha da linguagem de programao a ser usada em um projeto. Por exemplo, saber que C no realiza checagem dinmica dos ndices de acessos a posies de vetores pode ser decisivo para escolher essa linguagem em aplicaes de tempo real que fazem uso frequente de acessos vetoriais.

    d) Maior habilidade para aprender novas LPs. Por exemplo, programado-res que aprenderam os conceitos de orientao a objetos tem maior fa-cilidade para aprender C++ e JAVA.

    e) Maior habilidade para projetar novas LPs. Muito embora poucos pro-fissionais de computao tenham a oportunidade, ao longo de suas car-reiras, de participar da criao de uma linguagem de programao de propsito geral, no raro se depararem com situaes nas quais ne-cessrio projetar linguagens para um propsito especfico. Por exem-plo, ao construir as interfaces com o usurio de sistemas pode ser ne-cessrio projetar e implementar uma linguagem de comandos para comunicao entre o usurio e o sistema.

    1.2 O Papel das Linguagens de Programao no Processo de Desenvolvimento de Software

    Linguagens de programao foram criadas para tornar mais produtivo o trabalho dos programadores. Logo, em ltima instncia, o objetivo das linguagens de programao tornar mais efetivo o processo de desenvol-vimento de software. importante enfatizar que esse processo existe tan-to para tornar mais produtiva a gerao e manuteno de software quanto para garantir que ele seja produzido atendendo a padres de qualidade. Assim, uma maneira de saber como as linguagens de programao podem apoiar esse processo envolve o conhecimento das propriedades requeridas em um software de qualidade. As principais propriedades desejadas em um software so confiabilidade, manutenibilidade e eficincia. A confiabilidade diz respeito ao atendimento adequado da especificao funcional, da garantia de segurana contra erros e da integridade dos da-dos manipulados pelo software. Uma LP pode promover a confiabilidade

  • 4

    de programas facilitando a existncia de ferramentas computacionais que verifiquem a ocorrncia de erros nos programas. Por exemplo, LPs que requerem a declarao de variveis, tais como C, PASCAL, e MODULA-2, facilitam a identificao de erros de digitao de nomes. Caso um usu-rio digite um nome incorreto, um verificador de erros pode identific-lo porque no foi declarado. A manutenibilidade diz respeito a facilidade de alterao do software. Necessidades de modificao so provenientes de erros de especificao, projeto ou implementao, de alteraes no ambiente tecnolgico onde o software executado e de novas demandas do usurio. Uma LP pode promover a manutenibilidade de programas fornecendo mecanismos que permitam a sua adaptao a diferentes contextos. Por exemplo, a declara-o de constantes em Pascal e Modula-2 facilita a realizao de modifica-es nos programas. Caso um programa utilize uma constante para definir o tamanho mximo de um vetor, basta modificar essa constante para a-daptar todo o programa a um aumento no tamanho mximo do vetor. A eficincia diz respeito ao uso otimizado dos recursos computacionais em termos de tempo de execuo, de espao de memria utilizado e de uso de dispositivos perifricos. Uma LP pode promover a eficincia de programas incentivando o uso de mecanismos computacionalmente efici-entes. Por exemplo, FORTRAN (com exceo de FORTRAN 90) no permite o uso de recurso para tornar mais eficiente o processamento e o consumo de memria. Outro modo de saber como as linguagens de programao podem apoiar o processo de desenvolvimento de software conhecendo como ele reali-zado. O processo de desenvolvimento de software normalmente com-preendido em cinco etapas [PRESSMAN, 1997]:

    1.2.1 Especificao de Requisitos Nessa etapa se identifica o que o software dever realizar em termos de funcionalidades. necessrio especificar o ambiente no qual o software atuar, quais sero as suas atividades, quais os impactos que dever pro-duzir e de que maneira ele dever interagir com os usurios. Em particu-lar, dever-se- especificar os requisitos de desempenho do sistema em termos de tempo de resposta desejado, espao de memria requerido e tambm de interao com outros dispositivos e usurios. Outra atividade importante nessa etapa a realizao de um estudo de viabilidade e custo do software a ser desenvolvido. Esse estudo tem por objetivo responder se a confeco e implantao do software vivel tc-nica, cronolgica e socialmente, bem como determinar, atravs da estima-tiva do custo de desenvolvimento do software, se a sua construo vi-

  • 5

    vel economicamente. A confeco de verses dos manuais do usurio do software tambm uma atividade desta etapa. O estudo de linguagens de programao influencia pouco a realizao dessa etapa. Basicamente, o conhecimento sobre linguagens de progra-mao pode ser usado no estudo de viabilidade para ajudar a responder se possvel desenvolver o software no perodo de tempo desejado.

    1.2.2 Projeto do Software Tendo por base os documentos de especificao de requisitos, pode-se projetar o sistema de programao. O projeto envolve a escolha de um mtodo de projeto e sua aplicao na especificao da arquitetura do software e seus procedimentos, das suas estruturas de dados e de suas in-terfaces. O resultado desta fase um documento de especificao do projeto do sistema, identificando todos os mdulos que compem a arquitetura do sistema, as estruturas de dados utilizadas por cada mdulo, as interfaces de comunicao entre mdulos (interfaces internas), com outros sistemas (interfaces externas) e com as pessoas que o utilizam (interface com o usurio). Tambm faz parte desse documento as descries procedimen-tais de cada mdulo da arquitetura. O principal papel das LPs nessa etapa dar suporte ao mtodo de projeto. Isto possibilita que a implementao de um sistema reflita o seu projeto, evitando adaptaes e distores no projeto e perda de correspondncia. Pode-se observar que algumas linguagens de programao so mais ade-quadas quando se utilizam certos mtodos de projeto. Por exemplo, en-quanto C mais adequada ao mtodo de projeto hierrquico-funcional, JAVA mais adequada ao mtodo orientado a objetos. Existem vrias ferramentas CASE que oferecem suporte s atividades dessa etapa. Muitas dessas ferramentas j geram parte da codificao do software em uma LP.

    1.2.3 Implementao

    A etapa de implementao onde ocorre a programao dos mdulos do software. Obviamente, LPs so essenciais nessa etapa uma vez que os programas devem ser escritos em uma linguagem. Essa etapa a mais atendida por ferramentas, tais como editores de texto que destacam os vocbulos da linguagem e identam automaticamente o texto, analisadores lxicos, sintticos e semnticos de programas e bibliotecas de subprogra-mas e mdulos.

  • 6

    1.2.4 Validao

    O propsito dessa etapa verificar se o sistema satisfaz as exigncias das especificaes de requisitos e de projeto. Geralmente, isto feito testan-do-se o sistema contra as especificaes. Existem trs tipos de testes: tes-te de mdulo, teste de integrao e teste de sistema. No teste de mdulo verificado se ele cumpre o que lhe foi especificado. No teste de integra-o verificado se os mdulos se integram apropriadamente, isto , se eles interagem tal como estabelecido nas especificaes de suas interfa-ces. O teste de sistema averigua se o software cumpre as funcionalidades para o qual foi desenvolvido e atende a todos os demais requisitos de usa-bilidade e eficincia. LPs podem auxiliar a validao de vrios modos. Por exemplo, a natureza de algumas linguagens facilita a construo de depuradores de erros e ambientes nos quais fcil executar mdulos de programa independen-temente da existncia de outros mdulos. Isso pode ser muito valioso para realizar os testes de mdulo e integrao.

    1.2.5 Manuteno

    A ltima etapa do processo de desenvolvimento de software a manuten-o e evoluo do sistema. Para que o ciclo de vida de um software possa ser ampliado necessrio que ele seja capaz de facilitar a correo de er-ros residuais (isto , erros descobertos aps a sua liberao para o usu-rio), adaptar-se a mudanas no seu contexto de aplicao (tal como, um novo ambiente computacional) e atender a demandas por melhoria e in-cluso de servios. LPs que oferecem recursos de modularizao tendem a gerar programas mais fceis de serem mantidos uma vez que as alteraes em um mdulo no interferem nos demais mdulos constituintes do software.

    1.3 Propriedades Desejveis em uma Linguagem de Progra-mao

    A partir da chamada crise do software [PRESSMAN, 1997], o aproveita-mento do tempo do profissional de programao se tornou um conceito central no processo de desenvolvimento de software. Consequentemente, as propriedades desejveis nas LPs devem enfatizar esse aspecto. Discu-tem-se a seguir algumas das principais propriedades desejveis em uma LP:

  • 7

    1.3.1 Legibilidade

    Essa propriedade diz respeito facilidade para se ler e entender um pro-grama. Quanto mais fcil for seguir as instrues de um programa, mais fcil ser entender o que est sendo feito e tambm descobrir erros de programao. LPs que requerem o uso extensivo do comando goto normalmente redu-zem a legibilidade dos programas porque permitem a ocorrncia da cha-mada programao macarrnica ou no estruturada. Nesse tipo de pro-gramao, os programas possuem fluxo de controle que no obedecem a padres regulares. Isto torna difcil acompanhar e entender o que fazem esses programas. Programas em verses antigas de FORTRAN e BASIC, por exemplo, tendiam a ser mal estruturados porque estas verses reque-riam o uso de goto para implementar as estruturas de seleo e repetio. O uso de um mesmo vocbulo da LP para denotar diferentes comporta-mentos dependendo do contexto onde usado tambm prejudicial le-gibilidade. Por exemplo, o vocbulo this pode ser usado em JAVA tanto para referenciar um objeto quanto para fazer uma chamada a uma funo construtora de dentro de outra. Outro exemplo o operador * em C, que tanto pode denotar a operao de multiplicao de nmeros quanto opera-es de manipulao de ponteiros. Isso permite a criao de expresses confusas. Por exemplo, a seguinte linha de cdigo C apresenta o uso do operador * em trs diferentes contextos: *p = (*p)*q; Observe que a operao designada pelo * mais a direita nessa linha de cdigo a operao de multiplicao. Por sua vez, a operao designada pelo * do meio a de retorno do contedo da clula de memria apontada pelo ponteiro p. Por fim, o * mais esquerda denota a operao de retor-no do endereo da clula apontada por p. Efeitos colaterais so mudanas adicionais promovidas no estado do pro-grama (isto , nos valores das variveis do programa) durante a avaliao de uma determinada de expresso ou a execuo de um comando ou sub-programa. O termo adicionais se refere ao fato das mudanas provocadas pelos efeitos colaterais no serem o objetivo principal da expresso, co-mando ou subprograma realizado. Por exemplo, a operao x++ de C tem como efeito principal retornar o valor da varivel x e como efeito colate-ral incrementar o valor dessa varivel. Efeitos colaterais podem ser preju-diciais a legibilidade quando seus resultados no ficam explcitos no tre-cho de programa que utiliza a operao. Observe no exemplo 1.1, em C, que a chamada da funo retornaCinco provoca alterao na varivel global x.

  • 8

    int x = 1; int retornaCinco() { x = x + 3; return 5; } main() { int y; y = retornaCinco (); y = y + x; }

    Exemplo 1. 1- Problema de Legibilidade Causado por Efeito Colateral em C

    Note que esse efeito no fica explcito no trecho de cdigo que chama retornaCinco. Algum que fizesse uma rpida inspeo no cdigo do e-xemplo 1.1 tentando identificar o que o programa faz e apenas olhasse a funo main no conseguiria entender que o valor final de y nove e no seis. Efeitos colaterais podem causar problemas ainda mais graves do que o de legibilidade (por exemplo, podem causar indeterminismo na expres-so x + retornaCinco())1.1. Marcadores de blocos de comandos, tais como o BEGIN({)END(}) de PASCAL e C, tambm podem causar confuses na leitura do programa quando existem vrios comandos de repetio e seleo aninhados. A i-nexistncia de um marcador especfico que indique onde o comando if de C se encerra possibilita a escrita de comandos ifs aninhados difceis de serem entendidos. No exemplo 1.2, embora o else pertena ao if mais in-terno, tem-se a impresso que ele se refere ao if mais externo.

    if (x>1) if (x==2)

    x=3; else

    x=4; Exemplo 1. 2 Problema de Legibilidade Relacionado com Marcadores de Bloco

    ADA reduz este problema usando beginendif e beginendloop. Algumas LPs adotaram posturas altamente questionveis com relao legibilidade. FORTRAN, por exemplo, permite que palavras reservadas como DO, END, INTEGER e REAL sejam tambm nomes de variveis.

    1.1 Esse problema ser discutido em maiores detalhes no captulo 5 desse livro.

  • 9

    1.3.2 Redigibilidade

    Essa propriedade possibilita ao programador se concentrar nos algoritmos centrais do programa, sem se preocupar com aspectos no relevantes para a resoluo do problema. Esta caracterstica a que melhor diferencia as linguagens de mquina (nas quais o programador deve se preocupar prin-cipalmente com detalhes de implementao) e linguagens de programa-o (nas quais o programador se concentra na descrio do algoritmo que resolve o problema). LPs com tipos de dados limitados requerem o uso de estruturas comple-xas. Isto acaba dificultando a redao de programas. Por exemplo, como FORTRAN no possui registros, armazenar dados de empregados de uma firma requer a criao de vetores especficos para cada tipo de dado. Ao redigir um subprograma para ordenar os dados seria necessrio usar v-rias instrues para trocar os elementos correspondentes em cada vetor. LPs que requerem muita programao de entrada e sada e que no dis-pem de mecanismos para o tratamento de erros tendem a obscurecer os algoritmos centrais nos programas.

    A redigibilidade de programas pode conflitar com a legibilidade. C per-mite a redao de comandos complexos, mas que podem no identificar de maneira muito clara a sua funcionalidade. Observe o comando for do exemplo 1.3 e tente identificar o que ele faz.

    void f(char *q, char *p) { for (;*q=*p; q++,p++); }

    Exemplo 1. 3 - Redigibilidade X Legibilidade

    fcil perceber o quo concisa essa implementao. Contudo, o preo a ser pago a falta de entendimento imediato sobre sua funcionalidade. Programadores inexperientes encontraro dificuldades para entender o que esse comando faz, enquanto programadores experientes podero se confundir ao fazer uma rpida leitura.

    1.3.3 Confiabilidade Essa propriedade se relaciona aos mecanismos fornecidos pela LP para incentivar a construo de programas confiveis. LPs que requerem a declarao de dados permitem verificar automatica-mente erros de tipos durante compilao ou execuo. Um compilador de JAVA pode detectar durante a compilao um erro de digitao cometido

  • 10

    por um programador em situaes como a do exemplo 1.4, onde o v foi inadvertidamente trocado por u no trecho v = u + 2; :

    boolean u = true; int v = 0; while (u && v < 9) { v = u + 2; if (v == 6) u = false; }

    Exemplo 1. 4 Declarao de Tipos e Confiabilidade

    LPs que possuem mecanismos para detectar eventos indesejveis e espe-cificar respostas adequadas a tais eventos permitem a construo de pro-gramas mais confiveis. No trecho de cdigo em JAVA, apresentado no exemplo 1.5, poder haver um erro se o valor de i estiver fora dos limites de ndices do vetor a. Caso isto ocorra, o programa interrompe seu fluxo normal de execuo e passa para o trecho de cdigo responsvel pelo tra-tamento desse erro.

    try { System.out.println(a[i]); } catch (IndexOutofBoundsException) { System.out.println(Erro de Indexao); }

    Exemplo 1. 5 - Tratamento de Excees e Confiabilidade

    1.3.4 Eficincia De acordo com as demandas por recursos de um tipo de aplicao, certas LPs so mais recomendadas e outras no devem ser usadas. Aplicaes de automao em tempo real, por exemplo, normalmente requerem o uso de LPs que minimizem o tempo de execuo e de acesso aos dispositivos perifricos, bem como o consumo de espao de memria. Muito embora, hoje, boa parte da responsabilidade em gerar cdigo efici-ente seja transferida para o compilador, atravs da otimizao automtica de cdigo, as caractersticas de uma LP podem determinar se o programa gerado naquela LP ser mais ou menos eficiente. Assim, LPs que reque-rem a verificao de tipos durante a execuo so menos eficientes do que aquelas que no fazem este tipo de requisio. Por exemplo, o mecanismo de tratamento de excees existente em JA-VA impem que os ndices de vetores sejam verificados em todos os a-cessos durante a execuo dos programas. Isso implica na necessidade de se fazer um teste antes de qualquer acesso aos vetores. Por outro lado,

  • 11

    como C no faz esse tipo de exigncia, o cdigo gerado economizar a realizao desse teste e, portanto, ser mais veloz.

    1.3.5 Facilidade de aprendizado

    O programador deve ser capaz de aprender a linguagem com facilidade. LPs com muitas caractersticas e mltiplas maneiras de realizar a mesma funcionalidade, tal como C++, tendem a ser mais difceis de aprender. Por exemplo, num determinado contexto, os seguintes comandos em C ou C++, tm o mesmo efeito:

    c = c + 1; c+=1; c++; ++c;

    Alm disso, outro aspecto negativo causado pelo excesso de caractersti-cas o fato de levar os programadores a conhecerem apenas uma parte da linguagem, o que torna mais difcil a um programador entender o cdigo produzido por outro.

    1.3.6 Ortogonalidade

    Ortogonalidade diz respeito capacidade da LP permitir ao programador combinar seus conceitos bsicos sem que se produzam efeitos anmalos nessa combinao. Assim, uma LP to mais ortogonal quanto menor for o nmero de excees aos seus padres regulares.

    LPs ortogonais so interessantes porque o programador pode prever, com segurana, o comportamento de uma determinada combinao de concei-tos. Isso pode ser feito sem que se tenha de implementar testes para ave-riguao do uso combinado de dois ou mais conceitos, ou mesmo buscar na especificao da LP se existe alguma restrio quela combinao. A falta de ortogonalidade, por sua vez, dificulta o aprendizado da LP e pode estimular a ocorrncia de erros de programao. No exemplo 1.6 mostrada a falta de ortogonalidade de um cdigo JAVA: int x, y = 2, z = 3; byte a, b = 2, c = 3; x = y + z; a = b + c;

    Exemplo 1. 6 - Falta de Ortogonalidade em JAVA

    Embora tanto o tipo int quanto o tipo byte sejam tipos inteiros, a linha de cdigo onde ocorre a soma de tipos int legal enquanto a que soma tipos byte ilegal (tente descobrir porqu). Ora, essa falta de ortogonalidade claramente uma fonte potencial de erros, uma vez que a maioria dos

  • 12

    programadores pensaria que a mesma regra que se aplica ao tipo int se aplicaria aos outros tipos de inteiros. Outro exemplo clssico de falta de ortogonalidade ocorre em PASCAL. Nessa LP, funes podem retornar qualquer tipo de dados com exceo de registros e vetores.

    1.3.7 Reusabilidade

    Outra propriedade desejvel em LPs a reusabilidade de cdigo, isto , a possibilidade de reutilizar o mesmo cdigo para diversas aplicaes. Quanto mais reusvel for um cdigo, maior ser a produtividade de pro-gramao, uma vez que, na construo de novos programas, bastar utili-zar e, eventualmente, adaptar cdigos escritos anteriormente sem que se faa necessrio reconstru-los novamente a partir do zero. LPs podem incentivar a criao de cdigo reusvel de vrias maneiras. A forma mais simples de facilitar a reusabilidade atravs da parametriza-o de subprogramas. Por exemplo, o subprograma em C apresentado no exemplo 1.7 pode ser utilizado em qualquer aplicao na qual se queira trocar os valores de duas variveis inteiras quaisquer. void troca (int *x, int *y) { int z = *x; *x = *y; *y = z; }

    Exemplo 1. 7 - Reuso por Parametrizao de Subprogramas

    Outro mecanismo muito til para permitir o reuso de cdigo a modula-rizao atravs das bibliotecas de subprogramas. A linguagem C oferece inmeras funes de entrada e sada (tais como, printf, scanf e fprintf) como parte de sua biblioteca padro. Essas funes podem ser usadas em qualquer programa sem que o programador necessite reescrev-las.

    1.3.8 Modificabilidade Essa propriedade se refere s facilidades oferecidas pelas LPs para possi-bilitar ao programador alterar o programa em funo de novos requisitos sem que tais modificaes impliquem em mudanas em outras partes do programa. Exemplos de mecanismos que proporcionam boa modificabilidade so o uso de constantes simblicas e a separao entre interface e implementa-o na construo de subprogramas e tipos abstratos de dados.

  • 13

    Em C, vrias constantes simblicas so usadas, tais como NULL e EOF. O comando seguinte cria uma constante simblica em C denotando o n-mero pi com preciso de duas casas decimais.

    const float pi = 3.14; Se em algum momento for constatada a necessidade de maior preciso na definio do nmero pi, basta fazer a alterao nessa mesma linha (inclu-indo mais casas decimais) e todas as ocorrncias da constante pi no pro-grama sero ajustadas para o seu novo valor numrico, sem que seja ne-cessrio realizar alteraes em outras partes do programa onde pi usado.

    1.3.9 Portabilidade

    altamente desejvel que programas escritos em uma LP se comportem da mesma maneira independentemente da ferramenta utilizada para tra-duzir os programas para a linguagem de mquina ou da arquitetura com-putacional (hardware ou sistema operacional) sobre a qual esto sendo executados. Dessa maneira, um mesmo programa ou biblioteca pode ser utilizado em vrios ambientes em diferentes situaes sem que seja necessrio dispen-der tempo de programao para reescrev-los ou adapt-los ao novo am-biente de traduo ou execuo. LPs podem facilitar a obteno de programas portveis atravs da amar-rao rigorosa do comportamento de seus elementos em tempo de projeto da linguagem, no dando liberdade para que os implementadores definam comportamentos distintos para um mesmo elemento. Contudo, essa postura pode impor algumas restries implementao das linguagens, em particular, no que diz respeito busca por eficincia na execuo dos programas. Nesse caso, pode-se optar por sacrificar a completa portabilidade dos programas na LP em benefcio da potenciali-zao de outras propriedades. Mesmo assim, deve-se procurar maximizar a portabilidade permitindo que os programas escritos na LP sejam trans-portados para outros ambientes requerendo apenas poucas modificaes em seu cdigo.

    1.4 Especificao de LPs

    Ao se criar uma LP necessrio definir como se faz para escrever pro-gramas nessa linguagem e como os programas vlidos devem se compor-tar. Essa definio deve ser feita atravs de documentos descritivos que estabeleam de maneira precisa como essas duas atividades devem ser realizadas. Tais documentos formam a especificao da LP. Sem uma es-

  • 14

    pecificao apropriada, implementaes das LPs no podem ter uniformi-dade, fazendo com que programas construdos para uma implementao tenham comportamento bem diferenciado ou mesmo no sejam vlidos em outra implementao. A especificao de uma LP requer a descrio de um lxico, de uma sin-taxe e de uma semntica para a LP. O lxico da LP corresponde ao voca-bulrio que pode ser utilizado para formar sentenas na linguagem. A sintaxe da LP corresponde ao conjunto de regras que determinam quais sentenas podem ser formadas a partir da combinao dos itens lxicos. O lxico e sintaxe esto relacionados com a forma dos programas, isto , como expresses, comandos, declaraes e outros elementos da LP po-dem ser combinados para formar programas vlidos. A semntica da LP descreve como as construes sintaticamente corretas so interpretadas ou executadas. A semntica est relacionada com o sig-nificado dos programas, isto , como eles se comportam quando executa-dos por computadores. Por exemplo, no comando seguinte, em C:

    a = b;

    O lxico da LP estabelece que a, =, b e ; fazem parte do vocabulrio da LP.

    A sintaxe da LP indica que a sentena formada pelo identificador a, o smbolo =, o identificador b e o smbolo ; designa um comando vlido de atribuio.

    A semntica da LP indica que este comando deve ser executado de modo a substituir o valor de a pelo valor atual de b.

    A sintaxe de uma LP influencia como os programas so escritos pelo pro-gramador, lidos por outros programadores e analisados pelo computador. A semntica de uma LP influencia como os programas so criados pelo programador, entendidos por outros programadores e interpretados pelo computador. A sintaxe de uma LP descrita por uma gramtica. Uma notao muito utilizada para descrever gramticas de LPs a BNF (Backus-Naur Form). O exemplo 1.8 apresenta uma gramtica para formao de expresses a-ritmticas elementares, descrita em BNF: ::= ::= ::= .

    ::= ::= 0123456789

  • 15

    ::= + ::= +/*

    Exemplo 1. 8 - Gramtica Simples

    Recomenda-se descrever a semntica de uma LP formalmente. Contudo, descries formais de semntica so freqentemente complexas para ler e escrever. Como resultado, na maior parte das vezes, a semntica de LPs descrita de maneira informal atravs de documentos que explicam em linguagem natural qual o significado dos comandos da LP. Uma outra abordagem muito adotada o enfoque operacional, que consiste em des-crever o significado de um comando atravs da apresentao de um cdi-go equivalente numa linguagem mais elementar. Um problema que ocorre muito frequentemente com LPs a ausncia de uma padronizao. Ao invs de se ter uma especificao nica adotada por todos os implementadores de LPs, surgem vrias implementaes dis-tintas com as suas prprias especificaes. Isso ocorre normalmente quando a linguagem ainda no se encontra totalmente estabelecida. As-sim, os implementadores discordam a respeito de quais elementos devem fazer parte da linguagem e como eles devem se comportar. Muitas vezes essa discordncia provocada pela necessidade de explorar as caracters-ticas especficas do ambiente onde a implementao ser realizada. Contudo, na medida que a linguagem vai se popularizando e amadure-cendo, essa variao de comportamentos acaba por gerar problemas signi-ficativos de portabilidade de programas. Para resolver esses problemas, procura-se estabelecer uma especificao padro nica que deve ser respeitada por todos os implementadores da LP. Variaes podem at continuar a existir, mas um ncleo de elementos comum necessita ser implementado para que a LP esteja em conformida-dade com o padro estabelecido. Assim, os programadores podem escre-ver programas garantidamente portveis, desde que s utilizem os ele-mentos padronizados. Normalmente, a padronizao de uma LP promovida por alguma insti-tuio especializada nesse servio, tais como a ISO (International Stan-dards Organization), o IEEE (Institute of Electrical and Electronics Engi-neers), o ANSI (American National Standards Institute) e o NIST (Nati-onal Institute for Standards and Technology). O processo de padronizao envolve a formao de um grupo de voluntrios especialistas que traba-lham para definir quais elementos devem fazer parte da padronizao. Esse trabalho complexo e demorado, pois envolve a obteno de con-senso entre os participantes do grupo de padronizao. Alm disso, o con-senso geralmente obtido omitindo-se as caractersticas mais polmicas.

  • 16

    Outro problema a definio do momento de padronizao. Se muito ce-do, a falta de experincia com a LP pode produzir um padro inadequado que iniba o seu uso e disseminao. Se muito tarde, a existncia de muitas verses incompatveis com um grande legado de cdigo pode dificultar ou retardar a aceitao do padro pela comunidade.

    1.5 Mtodos de Implementao

    de LPs

    Todo e qualquer programa escrito em uma LP necessita ser traduzido para a linguagem de mquina para ser executado. Para fazer isto necessrio aplicar um programa (ou conjunto de programas) que receba como entra-da o cdigo fonte do programa a ser traduzido e gere o cdigo traduzido na linguagem de mquina. Esse programa tradutor quem determina co-mo os programas na LP sero implementados, isto , como o cdigo fonte traduzido se comportar efetivamente quando executado no computador. Sebesta [SEBESTA, 1999] descreve trs mtodos gerais de implementa-o de LPs (ilustrados na figura 1.1).

    Figura 1. 1 - Mtodos de Implementao de LPs

    1.5.1 Compilao

    O processo de compilao efetua a traduo integral do programa fonte para o cdigo de mquina. Uma vez traduzido, o programa em linguagem de mquina pode ser executado diretamente. A grande vantagem desse mtodo de traduo a otimizao da eficin-cia na execuo dos programas. A execuo rpida porque no se ne-

    Compilao Interpretao Hbrido

    Fonte Fonte Fonte LP LP LP

    Execuo

    L.M.L.M.

    L.M.

    Compilao Compilao

    Interpretao

    Cdigo Intermedirio

    Interpretao

    Execuo

    Execuo

    Dados

    Dados

    Dados

  • 17

    cessita fazer qualquer traduo durante a execuo e porque boa parte das verificaes de erros j podem ser efetuadas durante a traduo. Alm disso, o prprio tradutor tem mais liberdade para realizar otimizaes na gerao do cdigo executvel, uma vez que pode considerar o cdigo fon-te globalmente. Uma outra vantagem do processo de compilao requerer apenas o c-digo executvel para que o programa possa ser executado. Assim, no necessrio possuir o cdigo fonte do programa para sua execuo. A principal desvantagem do mtodo de compilao a no portabilidade do cdigo executvel para mquinas com arquitetura diferenciada daquela na qual ele foi compilado. Por exemplo, um programa em C compilado sobre o ambiente Linux no executado sobre o ambiente Windows e vice-versa. Outro problema se refere depurao. Uma vez que o cdigo executvel normalmente no guarda referncias ao texto do cdigo fonte, qualquer indicao de erro de execuo no pode ser devidamente identificada com a informao do nome da varivel envolvida no erro ou da linha corres-pondente no cdigo fonte que ocasiona o erro. importante mencionar, no entanto, que existem sistemas de desenvolvimento de programas que permitem a depurao de programas compilados. Esses sistemas mantm uma correspondncia entre o cdigo compilado e o cdigo fonte para po-der realizar a execuo passo a passo do cdigo, inspeo de valores de variveis durante a execuo e prestar informaes referentes ao cdigo fonte sobre um eventual erro de execuo.

    1.5.2 Interpretao pura

    No processo de interpretao pura, um programa interpretador age como um simulador de um computador virtual que entende as instrues da LP. Basicamente, cada instruo do cdigo fonte traduzida para a linguagem de mquina quando essa instruo necessita ser executada. Imediatamente aps a traduo, o cdigo gerado executado. Deste modo, em contraste com a compilao, a traduo e a execuo de programas interpretados podem ser vistos como um processo nico, no existindo etapas separadas de traduo e de execuo. A interpretao pura apresenta como vantagens: a facilidade para prototi-pao, visto que se pode executar comandos e partes do programa assim que so construdos, verificando se atuam corretamente; a facilidade de depurao, visto que as mensagens de erro podem se referir diretamente ao cdigo fonte; e a facilidade de escrever programas mais flexveis, visto que o interpretador da LP est presente durante a execuo (permitindo,

  • 18

    por exemplo, a execuo de trechos de programas criados, alterados ou obtidos durante a prpria execuo). A grande desvantagem da interpretao pura em relao compilao a execuo muito mais lenta do programa. A razo para essa lentido de-corre da necessidade do interpretador decodificar comandos complexos da LP, verificar erros do programa e gerar cdigo em linguagem de m-quina durante a prpria execuo do programa. Alm disso, enquanto na compilao os comandos internos de uma repetio s necessitam ser tra-duzidos e verificados uma nica vez, na interpretao pura, de modo ge-ral, esse processo se repete para cada ciclo de execuo da repetio. Outra desvantagem o maior consumo de espao de memria, pois de-vem ser mantidos em memria uma tabela de smbolos, o cdigo fonte e o prprio programa interpretador.

    1.5.3 Hbrido

    Processo que combina tanto a execuo eficiente quanto a portabilidade de programas atravs da aplicao combinada dos dois mtodos anterio-res. A base para o mtodo hbrido a existncia de um cdigo intermedi-rio, mais fcil de ser interpretado e, ao mesmo tempo, no especfico de uma plataforma computacional. O mtodo hbrido dividido, portanto, em duas etapas: compilao para um cdigo intermedirio e interpretao deste cdigo. Embora ainda de execuo mais lenta que o cdigo compilado, a interpre-tao do cdigo intermedirio muito mais rpida que a interpretao pura do cdigo fonte porque as instrues do cdigo intermedirio so muito mais simples que as do cdigo fonte e porque a maior parte das ve-rificaes de erro realizada j na etapa de compilao. Por sua vez, como o cdigo intermedirio no especfico para uma pla-taforma, os programas j compilados para este cdigo podem ser portados para as mais diferentes plataformas sem necessidade de adaptao ou mesmo recompilao, bastando que exista um interpretador do cdigo intermedirio instalado na plataforma onde se deseja executar o progra-ma.

    JAVA adota o mtodo hbrido. O cdigo intermedirio chamado de by-tecode. O interpretador de bytecode a JVM (JAVA Virtual Machine). Cada plataforma computacional necessita possuir a sua prpria JVM para que o programa em bytecode possa ser executado.

  • 19

    1.6 Paradigmas de LPs

    D-se o nome de paradigma a um conjunto de caractersticas que servem para categorizar um grupo de linguagens. Existem diversas classificaes de paradigmas de LPs, sendo a mais comum a que divide os paradigmas de LPs nos paradigmas imperativo, orientado a objetos, funcional e lgi-co. A classificao utilizada aqui adapta a proposta apresentada por Ap-pleby [APPLEBY, 1991]. As nicas alteraes realizadas nessa classifi-cao so a substituio do termo distribudo pelo termo, mais genrico, concorrente e a remoo do paradigma de linguagens de bancos de dados. A figura 1.2 ilustra a classificao adotada aqui:

    Figura 1. 2 - Paradigmas de LPs

    Nessa classificao os paradigmas so subdivididos em duas categorias principais: imperativo e declarativo.

    1.6.1 Paradigma Imperativo

    O paradigma imperativo engloba os paradigmas baseados na idia de computao como um processo que realiza mudanas de estados. Nesse sentido, um estado representa uma configurao qualquer da memria do computador. Programas de LPs que so includas nesse paradigma especi-ficam como uma computao realizada atravs de uma sequncia de alteraes no estado da memria do computador. O foco dos programas no paradigma imperativo se encontra em especifi-car como um processamento deve ser feito no computador. Os conceitos fundamentais so de varivel, valor e atribuio. Variveis so vistas co-mo sendo um conjunto de clulas de memria. Elas possuem um valor associado em um determinado instante do processamento e podem ter seu valor modificado atravs de operaes de atribuio.

    Paradigmas

    Imperativo Declarativo

    Estruturado Orientado a Objetos

    Concorrente Funcional Lgico

  • 20

    O paradigma imperativo subdividido nos paradigmas estruturado, orien-tado a objetos e concorrente.

    1.6.1.1 O Paradigma Estruturado

    As primeiras LPs foram fortemente influenciadas pela programao em linguagem de mquina. Esse tipo de programao se caracterizava pela existncia de uma sequncia monoltica de comandos e pelo uso de des-vios condicionais e incondicionais para determinar o fluxo de controle da execuo do programa. Logo se percebeu que esse estilo de programao estimulava a ocorrncia de erros e reduzia a produtividade do programador. Para contornar essa dificuldade surgiu a programao estruturada. Esse tipo de programao se baseia na idia de desenvolvimento de programas por refinamentos sucessivos (top-down). A programao estruturada consegue organizar o fluxo de controle de execuo dos programas desestimulando o uso de comandos de desvio incondicional e incentivando a diviso dos progra-mas em subprogramas e em blocos aninhados de comandos. PASCAL e C so linguagens que adotam o paradigma estruturado.

    1.6.1.2 O Paradigma Orientado a Objetos Com o avano da computao, os sistemas de software tm se tornado cada vez maiores e mais complexos. O paradigma orientado a objetos o-ferece conceitos que objetivam tornar mais rpido e confivel o desen-volvimento desses sistemas. Enquanto as linguagens que adotam o paradigma estruturado enfocam as abstraes de controle de execuo dos programas, as linguagens que a-dotam o paradigma orientado a objetos enfocam as abstraes de dados como elemento bsico de programao. Classes so abstraes que defi-nem uma estrutura de dados e um conjunto de operaes que podem ser realizadas sobre elas, chamadas mtodos. Objetos so instncias de clas-ses. Outros conceitos importantes nesse paradigma so a herana e o po-limorfismo. Por utilizarem os conceitos do paradigma estruturado na especificao dos mtodos, o paradigma orientado a objetos pode ser considerado uma evoluo do paradigma estruturado. SMALLTALK, C++ e JAVA so linguagens que adotam o paradigma orientado a objetos.

  • 21

    1.6.1.3 O Paradigma Concorrente

    A programao concorrente ocorre quando vrios processos executam simultaneamente e concorrem por recursos. Sistemas concorrentes tm se tornado cada vez mais usados. Eles podem utilizar uma nica unidade de processamento ou vrias unidades em paralelo. Nesse ltimo caso as uni-dades de processamento podem estar localizadas em um mesmo compu-tador ou distribudas entre vrios. Sistemas concorrentes tambm podem compartilhar dados ou dispositivos perifricos. O paradigma concorrente engloba linguagens que oferecem facilidades para o desenvolvimento desses sistemas. ADA provavelmente a lingua-gem mais conhecida que oferece suporte a concorrncia.

    1.6.2 Paradigma Declarativo

    Em contraste com o paradigma imperativo, no qual os programas so es-pecificaes de como o computador deve realizar uma tarefa, no para-digma declarativo os programas so especificaes sobre o que esta ta-refa. No paradigma declarativo, o programador no precisa se preocupar sobre como o computador implementado, nem sobre a maneira pela qual ele melhor utilizado para realizar uma tarefa. A preocupao do programador em descrever de forma abstrata a tarefa a ser resolvida. Tipicamente, programas em linguagens declarativas so especificaes de relaes ou funes. No existem atribuies a variveis dos programas uma vez que as variveis declarativas so de fato incgnitas e no repre-sentam clulas de memria. Os interpretadores ou compiladores das LPs declarativas gerenciam a memria do computador, tornando transparente para o programador a ne-cessidade de alocao e desalocao de memria.

    1.6.2.1 O Paradigma Funcional

    Linguagens funcionais operam apenas sobre funes, as quais recebem listas de valores e retornam um valor. O objetivo da programao funcio-nal definir uma funo que retorne um valor como a resposta do pro-blema. Um programa funcional uma chamada de funo que normal-mente chama outras funes para gerar um valor de retorno. As principais operaes nesse tipo de programao so a composio de funes e a chamada recursiva de funes. Outra caracterstica importante que fun-es so valores de primeira classe que podem ser passados para outras

  • 22

    funes. LISP, HASKELL e ML1.2 so exemplos de linguagens funcio-nais.

    1.6.2.2 O Paradigma Lgico

    Linguagens lgicas so normalmente baseadas em um subconjunto do clculo de predicados. Um predicado define uma relao entre fatos ou entre variveis. Um programa lgico composto por clusulas que defi-nem predicados e relaes factuais. A caracterstica diferencial do para-digma lgico que a execuo dos programas corresponde a um processo de deduo automtica. Assim, quando uma questo formulada, um mecanismo de inferncia tenta deduzir novos fatos a partir dos existentes para verificar a veracida-de da questo. PROLOG o exemplo mais conhecido de linguagem que adota o paradigma lgico.

    1.7 Evoluo das LPs

    Antes do surgimento das LPs, a programao de computadores era feita exclusivamente em linguagem de mquina. Programadores tinham de co-nhecer profundamente a arquitetura da mquina onde o programa seria executado, seu conjunto de instrues e sua forma de funcionamento. Mesmo dominando todo esse conhecimento, a atividade de programao era pouco produtiva porque as instrues das linguagens de mquina so muito simples. As primeiras LPs surgiram no final dos anos 50 e incio dos anos 60 para facilitar o trabalho de programao. Por conta da cultura de programao dessa poca e da limitao de recursos dos computadores, essas lingua-gens foram fortemente influenciadas pelas linguagens de mquina e pela arquitetura de Von Neumman dos computadores. A eficincia computa-cional era o foco principal das LPs porque os recursos como memria e processadores eram escassos. FORTRAN e COBOL so exemplos de lin-guagens que surgiram nessa poca. Na medida que os recursos computacionais se desenvolviam, os compu-tadores iam se tornando mais poderosos e teis. Novamente, a atividade de programao se tornava um gargalo para a disseminao dos sistemas computacionais. No final dos anos 60, as LPs passaram a enfocar a efici-ncia na produtividade dos programadores. Surgiram as LPs que enfati-zavam a programao estruturada. PASCAL e C so exemplos de lingua-gens que surgiram nessa poca.

    1.2 ML no considerada uma linguagem puramente funcional. Ela tambm possui caractersticas de

    uma linguagem imperativa.

  • 23

    Com o aumento da complexidade dos sistemas computacionais, uma nova tcnica de programao passou a ser o foco das LPs no final dos anos 70 e incio dos anos 80 - a abstrao de dados. Essas LPs enfocavam a cons-truo modularizada de programas e bibliotecas e o conceito de tipos abs-tratos de dados. MODULA-2 e ADA so exemplos de linguagens que surgiram nessa poca. Durante os anos 80 e 90 houve uma vasta disseminao do uso de compu-tadores pessoais e das estaes de trabalho. Surge a indstria do software e com ela a necessidade de se produzir e atualizar software rapidamente. O reuso passa a ser um conceito central para a produtividade no desen-volvimento de software. Para atender esse requisito so desenvolvidas as LPs orientadas a objetos. SMALLTALK, EIFFEL, C++ e JAVA so e-xemplos de linguagens que surgiram nessa poca. importante dizer que muitas linguagens foram incorporando novas ca-ractersticas na medida que se constatava a sua necessidade. Assim, ver-ses atuais de FORTRAN e COBOL, por exemplo, j incorporam os con-ceitos de programao estruturada. Cabe dizer ainda que as linguagens declarativas evoluram em paralelo com as imperativas. LISP surgiu no final dos anos 50 e PROLOG no in-cio dos anos 70. O maior interesse no desenvolvimento dessas linguagens tem sido demonstrado no meio acadmico, em particular, nas reas de pesquisa sobre Linguagens de Programao e Inteligncia Artificial. Apresenta-se a seguir uma breve descrio da origem e principais caracte-rsticas de algumas das LPs mais conhecidas.

    1.7.1 Origem de LPs

    FORTRAN (1957): Desenvolvida inicialmente por Backus para com-putadores IBM. Destinou-se a aplicaes numrico-cientficas (carac-terizadas por poucos dados e muita computao). Enfatizava eficincia computacional (por exemplo, no havia alocao dinmica de mem-ria). No enfocava eficincia dos programadores (por exemplo, as es-truturas de controle eram todas baseadas no comando GOTO). Verses atuais de FORTRAN incorporaram avanos das outras LPs.

    LISP (1959): Criada por John McCarthy no MIT. Adota o paradigma funcional. Apropriada para processamento simblico. Ainda hoje a LP mais usada na Inteligncia Artificial. COMMON LISP e SCHEME so dialetos.

  • 24

    ALGOL (1960): Criada por um comit de especialistas. Primeira LP com sintaxe formalmente definida. Importncia terica enorme, tendo influenciado todas as LPs imperativas subsequentes, embora ela pr-pria no tenha sido muito usada (at hoje se usa o termo ALGOL-like).

    COBOL (1960): Criada por comit de especialistas. Primeira LP en-comendada pelo Departamento de Defesa Americano (DoD). Destina-da para aplicaes comerciais (caracterizada por muitos dados e pouca computao). Tentou enfatizar legibilidade (LP mais prxima do in-gls), mas acabou comprometendo redigibilidade.

    BASIC (1964): Criada por Kemeny e Kurtz na Universidade de Dar-mouth. Objetivava ser de fcil aprendizado para uso por estudantes de artes e cincias humanas.

    PASCAL (1971): Criada por Niklaus Wirth. Foi projetada para ser usada no ensino de programao estruturada. Enfocou a simplicidade.

    C (1972): Criada por Dennis Ritchie no Bell Labs. Projetada para ser usada no desenvolvimento de sistemas de programao (em particular, para a implementao do sistema operacional UNIX).

    PROLOG (1972) - Criada por Comerauer e Roussel, na Universida-de de Aix-Marseille, com o auxlio de Kowalski, da Universidade de Edinburgo. Adota o paradigma lgico, sendo bastante usada em Inteli-gncia Artificial.

    SMALLTALK (1972): Criada por Alan Key e Adele Goldberg no Xerox PARC. Primeira LP totalmente orientada a objetos. O ambiente de programao de SMALLTALK introduziu o conceito de interfaces grficas com o usurio que hoje amplamente utilizado.

    ADA (1983): Criada pela empresa Cii-Honeywell Bull, liderada pelo francs Jean Ichbiah, vencedora de licitao promovida pelo DoD para atender demanda de uma linguagem de programao de alto-nvel padronizada. Demandou o maior esforo para o desenvolvimento de uma LP, envolvendo centenas de pessoas durante oito anos. LP muito grande e complexa. Apropriada para programao concorrente e sis-temas de tempo real.

  • 25

    C++ (1985): Criada por Bjarne Stroustrup no Bell Labs. Projetada pa-ra ser uma extenso de C com orientao a objetos. Tinha como requi-sito no implicar em perda de eficincia em relao ao cdigo em C. Responsvel pela rpida aceitao da orientao a objetos. Se tornou uma LP muito complexa.

    JAVA (1995): Criada pela SUN para ser usada na construo de soft-wares para sistemas de controle embutido (tais como eletrodomsti-cos), mas acabou no sendo usada para este fim. Baseou-se fortemente em C++, mas bem mais simples. uma LP orientada a objetos. No utiliza explicitamente o conceito de ponteiros e foi projetada para en-fatizar a portabilidade. Tem se tornado amplamente utilizada por causa da sua confiabilidade e portabilidade, pelo advento da INTERNET e porque os programadores de C e C++ a aprendem facilmente.

    1.8 Consideraes Finais

    Nesse captulo foram apresentados diversos temas importantes para o en-tendimento dos conceitos discutidos no resto desse livro. Em particular, importante ter compreendido como cada uma das propriedades apresenta-das na seo 1.3 podem influenciar o projeto, implementao e uso das LPs. Ter uma boa noo sobre como LPs podem ser especificadas e im-plementadas tambm contribui para a compreenso de diversos tpicos subseqentes. Por fim, vale repetir que o foco desse livro ser na discusso das LPs que se enquadram sobre o paradigma imperativo, isto , linguagens que ado-tam o paradigma estruturado, orientado a objetos ou concorrente. Vale ressaltar tambm que os exemplos sero dados primordialmente nas lin-guagens C, C++ e JAVA.

    1.9 Exerccios

    1. Identifique problemas de legibilidade e redigibilidade nas LPs que co-nhece. Verifique se existem casos nos quais essas propriedades so conflitantes.

    2. Identifique problemas de confiabilidade e eficincia nas LPs que conhece. Verifique se existem casos nos quais essas propriedades so conflitantes.

    3. Identifique problemas de falta de ortogonalidade nas LPs que conhece. Esses problemas comprometem a facilidade de aprendizado da LP?

  • 26

    4. Reusabilidade e modificabilidade muitas vezes contribuem para a me-lhoria uma da outra. D exemplos de situaes nas quais isso ocorre.

    5. Identifique situaes nas quais a busca por eficincia computacional compromete a portabilidade de LPs e vice-versa.

    6. Uma LP sempre pode ser implementada usando tanto o mtodo de compilao quanto o de interpretao? Em caso positivo, discuta se existem LPs que se ajustam melhor a um mtodo de implementao do que a outro. Em caso negativo, apresente um exemplo de uma LP na qual s se pode utilizar um mtodo de implementao e justifique.

    7. Faa uma anlise lxica, sinttica e semntica das seguintes linhas de cdigo C e descreva quais as concluses obtidas:

    int a, i; int b = 2, c =3; a = (b + c) * 2; i = 1 && 2 + 3 | 4;

    8. Enumere e explique quais os principais fatores que influenciaram a evoluo das LPs imperativas.

    9. Induzir a legibilidade, confiabilidade e reuso de programas so algu-mas das propriedades desejveis em Linguagens de Programao. Mostre, atravs de exemplos (um para cada propriedade) retirados de linguagens de programao conhecidas, como elas podem cumprir es-tes papis e justifique os seus exemplos.

  • 27

    Captulo II Amarraes

    !

    Amarrao (binding) um conceito amplamente utilizado no estudo de LPs. Em termos gerais, uma amarrao uma associao entre entidades de programao, tais como entre uma varivel e seu valor ou entre um identificador e um tipo. Nesse captulo se discute o conceito de amarrao enfocando especial-mente as associaes feitas entre identificadores e smbolos da LP com entidades de programao, tais como constantes, variveis, procedimen-tos, funes e tipos. Inicialmente apresentam-se os diversos momentos nos quais podem ocor-rer amarraes. Em seguida, discutem-se as propriedades relacionadas com identificadores. Abordam-se tambm os ambientes de amarrao e as noes de escopo das entidades de programao. Por fim, discute-se co-mo podem ser feitas definies e declaraes dessas entidades.

    2.1 Tempos de Amarrao

    Existem inmeros tipos de amarraes, as quais podem ocorrer em mo-mentos distintos. O momento no qual uma amarrao realizada co-nhecido como tempo de amarrao. A seguir, so apresentadas descries de diferentes tempos de amarrao juntamente com exemplos.

    Tempo de Projeto da LP: Ao se projetar uma LP necessrio de-finir os smbolos e alguns identificadores que podero ser usados para a construo de programas, bem como amarr-los s entidades que representam. Por exemplo, a escolha do smbolo * para denotar a operao de multiplicao em C foi feita durante o projeto da lin-guagem.

    Tempo de Implementao do Tradutor: Algumas amarraes so efetuadas no momento em que se implementa o software res-ponsvel por traduzir o cdigo da LP (em geral, o compilador). Por exemplo, a definio do intervalo de inteiros associado ao tipo int de C realizada durante a implementao do compilador. Isso sig-

  • 28

    nifica que diferentes compiladores podem adotar diferentes interva-los para o tipo int.

    Tempo de Compilao: Um grande nmero de amarraes ocorre no momento em que o programa compilado. So exemplos desse tipo de amarrao em C a associao de uma varivel a um tipo de dados e a associao, em uma expresso do programa, do operador * operao que denota.

    Tempo de Ligao: Amarraes tambm ocorrem no momento em que vrios mdulos previamente compilados necessitam ser inte-grados (ou, no termo mais usado, ligados) para formar um progra-ma executvel. Por exemplo, a amarrao entre a chamada de uma funo da biblioteca padro de C (tal como, printf) e o cdigo compilado correspondente a essa funo realizado em tempo de ligao.

    Tempo de Carga: Outro momento onde ocorrem amarraes du-rante o carregamento do programa executvel na memria do com-putador. Nesse momento, so associadas reas de memria s vari-veis globais e constantes que sero usados pelo programa, assim como so substitudas vrias referncias no cdigo executvel por endereos absolutos de memria.

    Tempo de Execuo: Outro grande nmero de amarraes ocorre durante a prpria execuo do programa. Exemplos desse tipo de amarrao so a associao de um valor a uma varivel ou a asso-ciao de reas de memria s variveis locais de uma funo em C.

    Costuma-se afirmar tambm que uma amarrao esttica se ela ocorre antes da execuo do programa e permanece inalterada ao longo de toda a execuo. J se a amarrao ocorre ou alterada durante a execuo do programa, ela chamada de amarrao dinmica. O entendimento sobre amarraes e seus respectivos tempos colabora muito para o entendimento da semntica de LPs. Como durante a pro-gramao s se realizam amarraes entre identificadores e entidades de computao, vamos nos concentrar nelas a partir de agora. Comearemos discutindo identificadores, abordaremos ambientes de amarrao e con-cluiremos estudando declaraes e definies.

    2.2 Identificadores

    Identificadores so cadeias de caracteres definidos pelos programadores para servirem de referncia s entidades de computao. A escolha apro-

  • 29

    priada de identificadores e smbolos facilita o entendimento dos progra-mas.

    O uso de identificadores tambm possibilita definir uma entidade em um ponto do programa e posteriormente utilizar aquele identificador para se referir quela entidade em vrios outros lugares. Alm de aumentar a re-digibilidade dos programas, isso faz com que o programa seja mais facil-mente modificvel, uma vez que, se a implementao da entidade deve ser alterada, a mudana afeta apenas a parte do programa na qual ela foi amarrada ao identificador e no as partes nas quais o identificador foi u-sado. A sintaxe para formao de identificadores em LPs pode variar. Uma forma comum apresentada a seguir (em BNF): ::= | ::= | ::= | |

    Exemplo 2. 1 - Regras Sintticas para Formao de Identificadores

    Algumas LPs limitam o nmero mximo de caracteres que podem ser uti-lizados. Outras no impem limites ou permitem que se criem nomes com tamanho ilimitado, mas fazem distines apenas at um nmero determi-nado de caracteres. Algumas LPs definem o limite na sua definio, en-quanto outras deixam para o implementador do compilador ou interpreta-dor da LP definir o tamanho mximo. LPs podem ser case sensitive, isto , podem fazer distines entre identificadores escritos com letras maisculas e minsculas (C, MODU-LA-2, C++ e JAVA) ou no (PASCAL). As LPs que adotam a abordagem no sensitiva permitem que uma mesma entidade seja referenciada pelo mesmo nome escrito de vrias maneiras distintas. Isto tende a provocar programas menos legveis, visto que o programador pode abusar do uso das variaes, dificultando o reconhecimento da amarrao entre o identi-ficador e a entidade que referencia. Por outro lado, as LPs que adotam a abordagem sensitiva permitem que um mesmo nome identifique vrias entidades distintas, podendo gerar confuses no entendimento do progra-ma, alm de forar o programador a lembrar como descreveu a entidade em termos do formato de seu identificador. Identificadores devem ser formados por nomes significativos, isto , de-vem prover informao a respeito do significado das entidades que deno-tam. Em particular, identificadores devem refletir o significado das enti-dades do domnio do problema e no da forma como elas so implemen-tadas. Por exemplo, sempre melhor definir um identificador chamado

  • 30

    palavra do que um chamado lista_de_caracteres, mesmo que o identifi-cador esteja associado a uma entidade implementada dessa forma. Identificadores que sejam visveis ao longo de partes substanciais do pro-grama, e que no sejam muito usados, devem ter significado bvio e po-dem ser relativamente longos. Identificadores visveis apenas em peque-nos trechos do programa, mas muito usados, podem ser curtos. Tipica-mente, nesses casos, deve-se usar abreviaes ou acrnimos ou nomes convencionais, tais como, i, j e p. Em geral, deve-se evitar formar identificadores que se diferem de forma sutil, como por exemplo, identificadores que se diferem apenas pela escri-ta em letra maiscula e minscula ou que se diferem apenas pelo uso da letra o maiscula e o dgito zero. Alm disso, importante tentar manter um estilo consistente na formao de identificadores, embora isso nem sempre seja possvel, uma vez que programas so frequentemente com-postos por fragmentos de diferentes origens.

    2.2.1 Identificadores Especiais Alguns identificadores podem ter significado especial para a LP [SE-BESTA, 1998]. Alguns podem ser vocbulos reservados, isto , so smbolos da LP que no podem ser usados pelo programador para a criao de identificadores de entidades. Os identificadores int, char, float, if, break de C so exemplos de vocbulos reservados. Outros identificadores podem ser vocbulos chave, isto , s so smbolos da LP quando usados em um determinado contexto. Esse tipo de identifi-cador pode ser muito ruim para a legibilidade de programas. O vocbulo INTEGER um vocbulo chave em FORTRAN (veja o exemplo 2.2).

    INTEGER R INTEGER = 7

    Exemplo 2. 2 - Vocbulos Chave

    Na primeira linha do exemplo 2.2, o identificador INTEGER usado para declarar a varivel R como do tipo inteiro. J na segunda linha, esse mesmo identificador denota uma varivel. Por fim, identificadores podem ser vocbulos pr-definidos, isto , tem significados pr-definidos, mas podem ser redefinidos pelo programador. Por exemplo, as funes fopen e fclose so exemplos de identificadores pr-definidos na biblioteca padro de C, mas que podem ser redefinidos pelo programador.

  • 31

    2.3 Ambientes de Amarrao

    A interpretao de comandos e expresses, tais como a = 5 ou g(a + 1), depende do que denotam os identificadores utilizados nesses comandos e expresses. A maioria das LPs permite que um mesmo identificador seja declarado em vrias partes do programa denotando, presumivelmente, diferentes entidades. O conceito de ambiente (environment) utilizado para determinar o que os identificadores denotam ao longo do programa. Um ambiente cor-responde a um conjunto de amarraes. Cada expresso e comando in-terpretado num determinado ambiente e todos os identificadores que o-correm devem ter amarraes nesse ambiente. Expresses e comandos idnticos em diferentes partes de um programa podem ser interpretados diferentemente se seus ambientes so distintos. Por outro lado, em geral, s permitida uma amarrao por identificador dentro de um determinado ambiente. Uma exceo a essa ltima regra ocorre em C++, como ilustrado no exemplo 2.3.

    int a = 13; void f() { int b = a; int a = 2; b = b + a; }

    Exemplo 2. 3 - Amarrao de Identificador a Duas Entidades Distintas no Mesmo Ambiente

    Enquanto o identificador a na primeira linha da funo f do exemplo 2.3 designa a varivel global, esse mesmo identificador nas segunda e terceira linhas designa a varivel local. Apenas em uma LP muito elementar todas amarraes afetam o ambiente de todo o programa. Em geral, uma amarrao tem um determinado esco-po de visibilidade, isto , a regio do programa onde a entidade amarrada visvel. O escopo de visibilidade de uma LP pode ser esttico ou din-mico. No escopo esttico, o ambiente de amarrao determinado pela organi-zao textual do programa. Assim, de maneira geral, as entidades de computao so amarradas em tempo de compilao. No escopo dinmico, o ambiente de amarrao determinado em funo da sequncia de ativao (chamada) dos mdulos do programa, a qual s determinada em tempo de execuo. Em outras palavras, o fluxo de controle do programa que determina as amarraes s entidades de computao.

  • 32

    2.3.1 Escopo Esttico

    O conceito de bloco fundamental para o entendimento do escopo estti-co. Um bloco delimita o escopo de qualquer amarrao que ele possa con-ter. Normalmente, um bloco um subprograma ou um trecho de cdigo delimitado atravs de marcadores, tais como, as chaves ({ e }) de C, C++ e JAVA ou os vocbulos begin e end introduzidos por ALGOL-60 e adotados por PASCAL e ADA. A estrutura de blocos de uma LP a relao textual entre blocos. A figura 2.1 ilustra uma classificao dos tipos de estruturas, tal como apresentada por Watt [WATT, 1990]:

    Figura 2. 1 - Estruturas de Blocos (adaptada de Watt [WATT, 1990]) Na estrutura monoltica todo o programa composto por um nico bloco. Todas as amarraes tm como escopo de visibilidade o programa inteiro. Essa estrutura de blocos a mais elementar possvel e no apropriada para programas grandes, uma vez que todas as amarraes de identifica-dores devem ser agrupadas num mesmo lugar. Isso faz com que o pro-gramador tenha de interromper frequentemente a anlise de trechos do programa e desviar sua ateno para o lugar onde pode consultar o signi-ficado dos identificadores usados nesses trechos. Mais ainda, isso dificul-ta o trabalho simultneo de vrios programadores em um mesmo progra-ma visto que os identificadores criados por um deles devem ser necessari-amente distintos dos identificadores criados pelos outros. Verses antigas de BASIC e COBOL adotam essa estrutura. A estrutura de blocos no aninhada considerada um avano em relao estrutura de blocos monoltica, uma vez que o programa dividido em vrios blocos. Nessa estrutura, o escopo de visibilidade dos identificado-res o bloco onde foram criados. Esses identificadores so chamados de locais. Os identificadores criados fora do bloco so chamados de globais, uma vez que seu escopo de visibilidade todo o programa. Uma desvan-tagem associada estrutura de blocos no aninhada que qualquer identi-

    x x

    y

    z

    w

    x

    y

    z

    w

    x

    Bloco Monoltico Blocos No Aninhados Blocos Aninhados

  • 33

    ficador que no pode ser local forado a ser global e ter todo o progra-ma como escopo, mesmo que seja acessado por poucos blocos. Outra desvantagem a exigncia de que todos os identificadores globais tenham identificadores distintos. FORTRAN adota esse tipo de estrutura. Todos subprogramas so separados e cada um atua como um bloco. A estrutura aninhada considerada um avano ainda maior. LPs como PASCAL, MODULA-2 e ADA adotam essa estrutura. So, por isso, chamadas LPs ALGOL-like uma vez que foi ALGOL a primeira lin-guagem a utiliz-la. Qualquer bloco pode ser aninhado dentro de outro bloco e localizado em qualquer lugar que seja conveniente. Identificado-res podem ser amarrados dentro de cada bloco. Normalmente, para des-cobrir qual entidade est amarrada a um identificador, deve-se procurar a declarao da entidade no bloco onde usada. Se no a encontrar, deve-se procurar no bloco mais externo imediato e assim por diante. Entidades podem se tornar inacessveis quando se usa o mesmo identifi-cador para denotar diferentes entidades em blocos aninhados. Isso ocorre em C, como mostra o exemplo 2.4.

    main() { int i = 0, x = 10; while (i++ < 100) { float x = 3.231;

    printf(x = %f\n, x*i); } }

    Exemplo 2. 4 - Ocultamento de Entidade em Blocos Aninhados

    No exemplo 2.4, a varivel x inteira criada no bloco mais externo no visvel dentro do bloco mais interno porque neste bloco foi criada uma outra varivel de tipo ponto flutuante com o mesmo identificador x. Com o intuito de evitar confuses, JAVA no permite que um mesmo identificador seja utilizado para designar entidades distintas em blocos aninhados. J em algumas LPs, como ADA, permitido usar o nome do bloco para acessar a entidade que fica oculta quando outra entidade as-sociada ao mesmo identificador em um bloco aninhado interno. Isso chamado de referncia seletiva. O exemplo 2.5 ilustra essa situao.

    procedure A is x : integer; procedure B is y : integer; procedure C is x : integer;

  • 34

    begin x := A.x; end C; begin null; end B; begin

    null; end A;

    Exemplo 2. 5 - Referncia Seletiva em ADA

    No exemplo 2.5, a referncia seletiva A.x dentro do bloco C permite que a varivel x do bloco A seja acessada. Observe que a referncia x dentro de C designa a varivel x do prprio bloco C, como seria de se esperar. Em certas situaes, contudo, a estrutura aninhada pode requerer que uma varivel seja declarada globalmente, embora seja usada por poucos blo-cos.

    Figura 2. 2 - Aninhamento de Blocos

    Na figura 2.2.a, o bloco D deve ser repetido dentro dos blocos A e C para que ele possa ser usado nica e exclusivamente por esses dois blocos. Uma alternativa para a no repetio do cdigo seria elevar o bloco D para o mesmo nvel de amarrao de A e C (ver figura 2.2.b). Nesse caso, D seria visvel por esses blocos. Contudo, D tambm passaria a ser visvel por P e B, o que pode no ser interessante. Outra opo seria permitir de-clarar que um bloco faz uso de outro bloco criado dentro de um terceiro. Por exemplo, poder-se-ia declarar que o bloco A utiliza o bloco D criado dentro do bloco C. C utiliza uma abordagem mista na qual os blocos definidos por funes adotam uma estrutura no aninhada e os blocos internos s funes ado-tam uma estrutura aninhada. Nesse caso, o que pode ser reusado (as fun-es) ou compartilhado (as variveis globais) se torna visvel para todos.

    P

    A B C

    D E D

    P

    A B C

    E

    D

    a b

  • 35

    J o que no pode ser reusado (os blocos internos) so aninhados. Obser-ve como isso feito no exemplo 2.6.

    int x = 10; int y = 15; void f() { if (y x) { int z = x + y; } } void g() { int w; w = x; } main() { f(); x = x + 3; g(); }

    Exemplo 2. 6 - Estrutura de Blocos de C

    Observe no exemplo 2.6 que qualquer funo pode usar a varivel global x e chamar qualquer outra funo. Observe tambm que dentro do bloco definido na funo f existe um bloco interno aninhado associado ao co-mando if. Observe que mesmo nessa abordagem, mais uma vez, as vari-veis globais e funes se tornam visveis para blocos que no as utilizam. Pelas regras de escopo de C, a funo g teria permisso para utilizar a va-rivel global y e chamar a funo f.

    2.3.2 Escopo Dinmico

    No escopo dinmico as entidades so amarradas aos identificadores de acordo com o fluxo de controle do programa. APL, SNOBOL4 e verses iniciais de LISP adotam este tipo de escopo. Considere o exemplo 2.7, escrito numa LP hipottica: procedimento sub() { inteiro x = 1; procedimento sub1() {

    escreva( x); }

    procedimento sub2() { inteiro x = 3; sub1(); }

  • 36

    sub2(); sub1(); }

    Exemplo 2. 7 - Escopo Dinmico

    Quando sub chama sub2 e este chama sub1, o valor escrito de x por sub1 3, isto , x uma referncia varivel criada em sub2. Quando sub chama sub1 diretamente, o valor escrito de x por sub1 1, isto , x uma referncia varivel criada em sub. LPs que adotam o escopo dinmico apresentam os seguintes problemas:

    1. perda de eficincia pois a checagem de tipos tem de ser feita du-rante a execuo;

    2. legibilidade do programa reduzida pois a sequncia de chama-das de subprogramas deve ser conhecida para determinar o sig-nificado das referncias a variveis no locais;

    3. acesso menos eficiente s variveis porque necessrio seguir a cadeia de chamadas de subprogramas para identificar as refe-rncias no locais;

    4. confiabilidade do programa reduzida pois variveis locais po-dem ser acessadas por qualquer subprograma chamado subse-quentemente no processo.

    Como consequncia desses problemas, a maioria das LPs atuais no ado-tam a abordagem de escopo dinmico.

    2.4 Definies e Declaraes

    Definies e declaraes so frases de programa elaboradas para produzir amarraes. Definies produzem amarraes entre identificadores e en-tidades criadas na prpria definio. Declaraes produzem amarraes entre identificadores e entidades j criadas ou que ainda o sero. Algumas LPs, tais como C, C++ e JAVA, permitem que sejam feitas de-claraes e definies dentro de blocos. Enquanto C requer que elas se-jam feitas imediatamente aps o marcador ( { ) de incio do bloco e antes de qualquer comando executvel, C++ e JAVA permitem que elas sejam feitas em qualquer ponto do bloco. J PASCAL no permite que sejam feitas declaraes e definies dentro dos blocos internos, apenas na rea destinada a amarraes no programa e nos subprogramas. O exemplo 2.8 mostra uma funo f em C++ na qual so definidas as variveis a e b.

    void f() { int a = 1; a = a + 3; int b = 0;

  • 37

    b = b + a; }

    Exemplo 2. 8 - Localizao de Definies de Variveis em C++

    Observe que a varivel b definida aps a realizao do comando de atri-buio varivel a. Note que um compilador de C acusaria erro ao com-pilar essa funo, uma vez que em C todas as amarraes devem ocorrer no incio do bloco.

    2.4.1 Declaraes de Constantes

    Uma declarao de constante amarra um identificador a um valor pr-existente que no pode ser alterado ao longo da execuo do programa. Isso pode ser feito em C++ tal como na seguinte linha de cdigo: const float pi = 3.14; Nessa linha criada uma constante de nome pi. Essa mesma declarao vlida em C. Contudo, a definio de C s requer que os compiladores avisem ao programador de tentativas de alteraes de constantes, permi-tindo assim que eles ignorem a definio e aceitem alteraes de valores das constantes!!! Por essa razo, programadores C continuam utilizando o mecanismo tradicional de macros quando querem criar constantes em C: #define pi 3.14 Com esse mecanismo todas as referncias a pi no cdigo sero substitu-das por 3.14, antes do incio da compilao, tendo efeito equivalente a definio de pi como constante. No entanto, pode ser vantajoso usar const ao invs de define em C porque esse ltimo mecanismo no reconhece regras de escopo (a constante ser reconhecida do ponto de declarao at o final do programa). Em caso de uso de const, a constante s ser reconhecida dentro do escopo de visibi-lidade definido pelo seu ambiente de amarrao. Algumas linguagens, como PASCAL e MODULA-2, requerem que cons-tantes tenham seus valores definidos estaticamente (em tempo de compi-lao). J ADA, C++ e JAVA permitem que sejam usados valores calcu-lados dinamicamente (em tempo de execuo do programa). Essa uma outra vantagem do uso de const em relao a define. O mecanismo de macros somente permite a declarao de constantes estticas. JAVA utili-za a palavra final para declarar constantes, tal como ilustrado no exemplo 2.92.1.

    2.1 A palavra static utilizada no exemplo 2.9 utilizada para indicar que a constante um atributo de classe (isto ,

    um atributo comum para todos os objetos da classe). As declaraes sem static provocam a criao de atributos constantes individuais para cada objeto da classe.

  • 38

    final int const1 = 9; static final int const2 = 39; final int const3 = (int)(Math.random()*20); static final const4 = (int)(Math.random()*20);

    Exemplo 2. 9 - Declarao de Constantes em JAVA

    Enquanto as duas primeiras linhas do exemplo 2.9 ilustram a criao de constantes estticas, as duas ltimas ilustram a criao de constantes di-nmicas. Math.random uma funo calculada em tempo de execuo que gera um nmero aleatrio. JAVA tambm permite a inicializao de constantes em ponto distinto da declarao. No exemplo 2.10, mostrada uma situao onde isso ocorre. Nesse exemplo, a constante j inicializada no mtodo Construtor.

    final int j; Construtor () { j = 1; }

    Exemplo 2. 10 - Inicializao de Constante em JAVA

    2.4.2 Definies e Declaraes de Tipos Uma definio de tipo amarra um identificador a um tipo criado na pr-pria definio. As definies de struct, union, enum em C so definies de tipo, tal como visto no exemplo 2.11.

    Exemplo 2. 11 - Definies de Tipos em C

    Uma declarao de tipo amarra um identificador a um tipo definido em outro ponto do programa. A primeira linha do exemplo 2.12 (em C) indi-ca que o identificador data est amarrado a um tipo estrutura definido em outro ponto do programa. As duas linhas restantes mostram o uso de ty-pedef na produo de declaraes de tipo, amarrando respectivamente os identificadores curvatura e aniversario aos tipos union angulo e struct data.

    struct data; typedef union angulo curvatura; typedef struct data aniversario;

    Exemplo 2. 12 - Declaraes de Tipos em C

    struct data { int d, m, a; };

    union angulo { int graus; float rad; };

    enum dia_util { seg, ter, qua, qui, sex };

  • 39

    Observe que, com o uso de typedef, no foi criado um novo tipo, ou seja, produz-se simplesmente um novo identificador para designar tipos previ-amente definidos. Por exemplo, possvel usar uma varivel do tipo uni-on angulo onde se espera uma varivel do tipo curvatura e vice-versa.

    2.4.3 Definies e Declaraes de Variveis Definies de variveis so as mais comuns em LPs. Uma definio de varivel um trecho de programa onde ocorre uma amarrao determi-nando a criao de uma varivel, isto , a alocao de um conjunto de c-lulas de memria e sua associao varivel definida naquele trecho. Ve-ja alguns exemplos de definies em C:

    int k; union angulo ang; struct data d; Variveis podem ser definidas em uma mesma frase para economizar di-gitao e espao do programa, aumentando a redigibilidade. A seguinte linha em C mostra um exemplo de como isso pode ser feito: int *p, i, j, k, v[10]; Observe nessa linha que so definidas trs variveis inteiras (i, j, k), uma varivel ponteiro para inteiro (p) e um vetor de inteiros com 10 elementos (v). Se, por um lado, construes como essa aumentam a redigibilidade do programa, por outro lado, ao misturar a definio de variveis de dife-rentes tipos, elas reduzem a legibilidade e podem provocar erros. Portan-to, aconselhvel que s se faam definies de variveis de um nico tipo em uma mesma frase do programa. Uma vantagem de se definir variveis em frases separadas, mesmo que de um nico tipo, permitir a insero de comentrios explicativos a respei-to das variveis ao lado de cada definio, aumentando a legibilidade. Uma varivel pode ser inicializada durante a sua definio. O exemplo 2.13 mostra isso sendo feito em C.

    int i = 0; char virgula = ', '; float f, g = 3.59; int j, k, l = 0, m=23;

    Exemplo 2. 13 - Inicializao de Variveis em C Durante a Definio

    As duas ltimas linhas do exemplo 2.13 mostram como combinar defini-es em uma mesma frase nas quais algumas variveis so inicializadas (no caso: g, l e m) e outras no (no caso: f, j e k). Certas linguagens oferecem inicializao implcita (tambm conhecida como inicializao default) de variveis. Em C e C++, variveis alo-cadas estaticamente (isto , variveis globais) so inicializadas com zero

  • 40

    do tipo apropriado. Isso significa que, se as variveis definidas no exem-plo 2.13 forem globais, as variveis j e k sero inicializadas automatica-mente com o valor 0 e a varivel f ser inicializada com o valor 0.0. J variveis alocadas dinamicamente (isto , variveis locais e variveis alo-cadas explicitamente na memria livre) no so inicializadas, ou seja, tm valores indefinidos (lixo). JAVA adota uma outra poltica. Variveis de-finidas como atributos de classe podem ser inicializadas implicitamente e variveis locais aos mtodos, no. Tambm comum se permitir inicializar explicitamente variveis atravs do uso de expresses. De modo similar ao mecanismo de inicializao implcita, em C e C++, as variveis alocadas estaticamente s permitem a inicializao com expresses estticas, isto , expresses que podem ter seu valor calculado em tempo de compilao. J as variveis alocadas dinamicamente podem ser inicializadas com expresses calculadas em tempo de execuo. O nico requisito exigido que os valores necess-rios para o clculo da expresso sejam conhecidos no momento da criao da varivel. O exemplo 2.14 mostra a inicializao, em C++, de uma va-rivel (k) atravs do uso de uma expresso dinmica.

    void f(int x) { int i; int j = 3; i = x + 2; int k = i * j * x; }

    Exemplo 2. 14 - Inicializao com Uso de Expresso Dinmica

    Variveis compostas tambm podem ser inicializadas em sua definio. No caso de C e C++, os valores usados na inicializao devem ser lista-dos em ordem para que haja correspondncia com os elementos da vari-vel composta. A linha seguinte mostra a inicializao explcita de um ve-tor de inteiros em C.

    int v[3] = { 1, 2, 3 }; Uma declarao de varivel serve para indicar que a varivel correspon-dente quele identificador definida em outro mdulo de cdigo ou para amarrar um identificador a uma varivel existente. C utiliza declaraes de variveis para indicar que uma varivel definida em um mdulo ex-terno. Isso significa que o compilador no deve gerar cdigo para alocar espao de memria para essa varivel (isso ser feito pelo mdulo exter-no), mas poder utilizar a declarao para verificar o uso apropriado da varivel externa nas operaes do programa. extern int a;

  • 41

    C++ permite que declaraes de variveis sejam feitas amarrando um i-dentificador a uma varivel j existente. Uma desvantagem dessa aborda-gem permitir a produo de sinnimos (aliases), tornando mais dif-cil entender os programas e podendo provocar erros de programao. O exemplo 2.15 mostra uma situao na qual isso ocorre. Observe que o incremento da varivel j implica em alterar implicitamente o valor da va-rivel r para 11.

    int r = 10; int &j = r; j++;

    Exemplo 2. 15 - Declarao de Varivel

    2.4.4 Definies e Declaraes de Subprogramas Subprogramas se compem de cabealho e corpo. No cabealho so es-pecificados o identificador do subprograma, sua lista de parmetros e o tipo de retorno (se for o caso). No corpo definido o algoritmo que im-plementa o subprograma e tambm especificado o valor de retorno (se for o caso). Uma definio de subprograma contm a especificao do cabealho e do corpo do subprograma. O exemplo 2.16 ilustra um subprograma em C:

    int soma (int a, int b) { return a + b; }

    Exemplo 2. 16 - Definio de Subprograma em C

    Uma declarao de subprograma contm apenas o cabealho do subpro-grama. Ela indica que a definio do subprograma ocorre em outro trecho do cdigo ou em outro mdulo. Declaraes de subprogramas so usadas para permitir a verificao do uso apropriado do subprograma durante a compilao. O exemplo 2.17 mostra o uso de uma declarao de subpro-grama em C.

    int incr (int); void f(void) { int k = incr(10); } int incr (int x) { x++; return x; }

    Exemplo 2. 17 - Declarao de Subprograma em C

  • 42

    A primeira linha de cdigo do exemplo 2.17 uma declarao do subpro-grama incr. Em C, s necessrio dar nomes aos parmetros na definio do subprograma, bastando especificar o seu tipo na declarao. Observe que no corpo da funo f ocorre uma chamada a incr, que s definida posteriormente. O compilador pode verificar se a chamada a incr est cor-reta em f porque a declarao de incr foi antecipada2.2.

    2.4.5 Composio de Definies Definies podem ser compostas a partir de outras definies ou a partir delas mesmas. Definies compostas podem ser sequenciais ou recursi-vas.

    2.4.5.1 Definies Sequenciais

    Definies sequenciais se utilizam de outras definies estabelecidas an-teriormente no programa. Elas permitem que as amarraes produzidas em uma definio sejam usadas nas demais. O exemplo 2.18 mostra a o-corrncia de definies sequenciais em um cdigo C.

    struct funcionario { char nome [30]; int matricula; float salario; }; struct empresa { struct funcionario listafunc [1000]; int numfunc; float faturamento; }; int m = 3; int n = m;

    Exemplo 2. 18 - Definies Sequenciais em C

    No exemplo 2.18, a definio do tipo struct empresa utiliza a definio do tipo struct funcionario e a definio da varivel n utiliza a definio da varivel m. Definies sequenciais de subprogramas normalmente envolvem chama-das a outros subprogramas. Contudo, algumas LPs fornecem uma forma

    2.2 No caso especfico do exemplo 2.17, onde a definio do subprograma se encontra no mesmo arquivo onde o

    subprograma usado, um compilador poderia dispensar a declarao de incr. Para tanto, o compilador deveria varrer previamente o cdigo identificando todos os cabealhos de subprogramas para posteriormente realizar as verificaes de uso.

  • 43

    menos comum de definio sequencial de subprogramas. Nessas LPs, o lado direito da definio sequencial pode ser qualquer expresso que pro-duza um valor subprograma. ML uma linguagem que oferece esse tipo de recurso. O exemplo 2.19 mostra a definio sequencial das funes impar e jogo em ML.

    val par = fn (n: int) => (n mod 2 = 0) val negacao = fn (t: bool) => if t then false else true val impar = negacao o par val jogo = if x < y then par else impar

    Exemplo 2. 19 - Definies Sequenciais em ML

    Observe que a funo impar definida a partir das funes par e nega-cao, j definidas anteriormente. Observe tambm que a definio de im-par no envolve a chamada dos subprogramas negacao e par. De fato, a definio de impar dada atravs da especificao de uma expresso que utiliza o operador de composio de funes (o) aplicado sobre os valores par e negacao. Note, por fim, que a funo jogo definida de maneira similar. Se no momento da criao de jogo, o valor associado a x for infe-rior ao valor associado a y, jogo se referir funo par. Caso contrrio, se referir funo impar. Tais possibilidades so eliminadas em LPs onde definies de funes e procedimentos so a nica forma de amarrao de um identificador a uma funo ou procedimento.

    2.4.5.2 Definies Recursivas

    Definies recursivas so aquelas que utilizam as prprias amarraes que produzem. Algumas verses de LPs antigas (tal como, FORTRAN e COBOL) no suportam recurso e, como conseqncia, se enfraquecem. As LPs mais modernas suportam recurso, em geral, restringindo-a a ti-pos e definies de procedimentos e funes, que so, de fato, os modos mais teis de recurso. Idealmente, tipos recursivos devem ser oferecidos pelas LPs de maneira indiscriminada. Contudo, em linguagens que utilizam explicitamente o conceito de ponteiros (tal como C), a definio de tipos recursivos res-trita, atravs de uma regra sinttica, a tipos que envolvem esses elemen-tos. O exemplo 2.20 mostra um tipo recursivo struct lista sendo definido em C:

    struct lista { int elemento; struct lista * proxima; };

  • 44

    Exemplo 2. 20 - Tipo Recursivo em C

    Definies de funes tambm podem ser recursivas em C. O exemplo 2.21 mostra a definio recursiva da funo potencia em C.

    float potencia (float x, int n) { if (n == 0) then { return 1.0; } else if (n < 0) { return 1.0/ potencia (x, -n); } else { return x * potencia (x, n - 1); }

    } Exemplo 2. 21 - Definio Recursiva de Funo em C

    Definies de funes em C tambm podem ser mutuamente recursivas. O exemplo 2.22 mostra as definies mutuamente recursivas, em C, das funes primeira e segunda.

    void segunda (int); void primeira (int n) { if (n < 0) return; segunda (n 1); } void segunda (int n) { if (n < 0) return; primeira (n 1); }

    Exemplo 2. 22 - Definies Mutuamente Recursivas em C

    Existem desvantagens em tratar declaraes como automaticamente re-cursivas. Suponha que se queira redefinir a funo strcmp de C. O pro-gramador poderia tentar redefinir essa funo utilizando a verso original de strcmp, tal como ilustrado no exemplo 2.23. int strcmp (char *p, char *q) { return !strcmp (p, q); }

    Exemplo 2. 23 - Erro em Definio de Funo strcmp em C