Você está na página 1de 100

te

cni

TÉCNICAS DE PROGRAMAÇÃO
As técnicas de programação exercem papel

cas
fundamental na computação, pois possibilitam
aos profissionais dessa área aprender e
desenvolver uma programação. À medida Cassiana Fagundes da Silva
que o conhecimento sobre os conceitos e as
funcionalidades das linguagens de programação

de
aumenta, o programador desenvolve, também,
suas habilidades e passa a ter maior capacidade
de entender o comportamento dos programas,
bem como mais facilidade para aprender novas
linguagens.

pro
Cassiana Fagundes da Silva
gra
Código Logístico Fundação Biblioteca Nacional
ISBN 978-85-387-6614-8

ma
cao
59310 9 788538 766148
Técnicas de
Programação

Cassiana Fagundes da Silva

IESDE BRASIL
2020
© 2020 – IESDE BRASIL S/A.
É proibida a reprodução, mesmo parcial, por qualquer processo, sem autorização por escrito da autora e do
detentor dos direitos autorais.
Projeto de capa: IESDE BRASIL S/A. Imagem da capa: Rawpixel/Envato Elements

CIP-BRASIL. CATALOGAÇÃO NA PUBLICAÇÃO


SINDICATO NACIONAL DOS EDITORES DE LIVROS, RJ
S579t

Silva, Cassiana Fagundes da


Técnicas de programação / Cassiana Fagundes da Silva. - 1. ed. - Curi-
tiba [PR] : IESDE, 2020.
96 p. : il.
Inclui bibliografia
ISBN 978-85-387-6614-8

1. Linguagem de programação (Computadores). I. Título.


CDD: 005.13
20-63503
CDU: 004.43

Todos os direitos reservados.

IESDE BRASIL S/A.


Al. Dr. Carlos de Carvalho, 1.482. CEP: 80730-200
Batel – Curitiba – PR
0800 708 88 88 – www.iesde.com.br
Cassiana Fagundes Doutoranda em Engenharia da Produção e Sistemas,
pela Pontifícia Universidade Católica do Paraná (PUCPR),
da Silva é mestre em Computação Aplicada, pela Universidade
do Vale do Rio dos Sinos (UNISINOS/RS), e graduada
em Ciência da Computação, pela Universidade de Santa
Cruz do Sul (UNISC/RS). Professora no ensino superior,
ministrando disciplinas de Linguagens de Programação,
Estrutura de Dados, Sistemas Operacionais, Engenharia
de Software, Análise e Modelagem de Sistemas,
Inteligência Artificial, Inteligência de Negócios, entre
outras.
Vídeos
em
QR code!
Agora é possível acessar os vídeos do livro por
meio de QR codes (códigos de barras) presentes
no início de cada seção de capítulo.

Acesse os vídeos automaticamente, direcionando


a câmera fotográfica de seu smartphone ou tablet
para o QR code.

Em alguns dispositivos é necessário ter instalado


um leitor de QR code, que pode ser adquirido
gratuitamente em lojas de aplicativos.
SUMÁRIO
1 Introdução a linguagens de programação  9
1.1 Conceitos de linguagens de programação   9
1.2 Evolução das linguagens de programação   15
1.3 Razões para estudar linguagens de programação   20
1.4 Tradutores de linguagens de programação   23

2 Desenvolvendo um programa  29
2.1 Análise léxica e sintática  30
2.2 Nomes e variáveis   33
2.3 Tipos de dados   36
2.4 Expressões e sentenças de atribuição   45

3 Estruturas de seleção de controle  53


3.1 Sentenças de seleção  54
3.2 Sentenças de iteração   57
3.3 Desvio incondicional   61
3.4 Comandos protegidos   62

4 Modularização 66
4.1 Fundamentos de subprogramas   67
4.2 Métodos de passagem de parâmetros   70
4.3 Subprogramas sobrecarregados e genéricos   73
4.4 Semântica de chamadas e retornos   75

5 Orientação a objetos  80
5.1 Conceitos de abstração   80
5.2 Tipos abstratos de dados e encapsulamento   82
5.3 Implementação de construções orientadas a objetos   86
5.4 Metodologias de desenvolvimento top down e bottom up   89

Gabarito   94
APRESENTAÇÃO
As técnicas de programação exercem papel fundamental na computação,
pois possibilitam aos profissionais dessa área aprender e desenvolver
uma programação. À medida que o conhecimento sobre os conceitos e as
funcionalidades das linguagens de programação aumenta, o programador
desenvolve, também, suas habilidades e passa a ter maior capacidade de
entender o comportamento dos programas, bem como mais facilidade para
aprender novas linguagens.
Considerando essa relevância, no primeiro capítulo, serão abordados os
conceitos de linguagem de programação, de modo a entender sua evolução
histórica e as razões pelas quais se deve estudar e compreender seus diversos
tipos. Os domínios e métodos de implementação de linguagens também são
discutidos para que o leitor entenda qual é o melhor paradigma a ser usado
nos diversos ambientes.
O segundo capítulo apresentará as estruturas básicas de um programa
em desenvolvimento, destacando a importância da análise léxica e sintática,
a declaração de variáveis e os tipos de dados. Também serão ilustradas as
expressões e sentenças de atribuições usadas na criação de um programa.
O terceiro capítulo propõe reflexões sobre as estruturas de seleção de
controle e seus respectivos tipos, de maneira que o leitor saiba aplicar e
identificar qual das estruturas é mais adequada no desenvolvimento de um
programa.
Diante da importância de aprimorar continuamente o desenvolvimento de
programas, o quarto capítulo visa estabelecer os conceitos de subprogramas
ou modularização nas linguagens de programação, ou seja, quando o
programa é dividido em partes distintas, tornando-o mais legível e de fácil
manutenção para os programadores.
No último capítulo, as características principais do desenvolvimento de
programas orientados a objetos são destacadas, além da modularização e do
desenvolvimento por meio das metodologias top down e bottom up.
Espera-se que este livro favoreça pesquisas e o aprofundamento nos
conhecimentos das técnicas de programação. Boa leitura!
1
Introdução a linguagens
de programação
Diariamente, vários programas são desenvolvidos e disponibi-
lizados no mercado para uso geral ou específico. A criação desses
programas somente torna-se possível por meio das linguagens de
programação que, há décadas, vêm sendo usadas por profissionais
de computação. É por meio das linguagens de programação que se
pode fazer um computador seguir instruções para realizar qualquer
processo.
Vale lembrar que, inicialmente, as linguagens de programação
eram bastante simples, uma vez que os computadores tinham limi-
tações no que diz respeito a suas configurações físicas de proces-
samento e memória. Porém, com os avanços tecnológicos, novas
linguagens vêm sendo criadas para atender às necessidades dos
usuários. Desse modo, o objetivo deste capítulo é apresentar uma
reflexão sobre as linguagens de programação (conceitos, evolução
e especificações) embasada em pesquisa bibliográfica da área,
para favorecer uma compreensão abrangente sobre elas e os pa-
radigmas que as classificam.

1.1 Conceitos de linguagens de programação


Vídeo As linguagens de programação surgiram juntamente com os pri-
meiros computadores e, ao longo dos anos, têm evoluído e melhorado
em relação aos recursos e às formas de implementação. Sendo assim,
tornaram-se amplamente conhecidas por profissionais da área da
computação que são também, muitas vezes, usuários de linguagens e
de ambientes de programação.

É importante ressaltar que para utilizar uma linguagem, primeira-


mente, ela necessita ter sido projetada e implementada. Por isso, para

Introdução a linguagens de programação 9


entender melhor os conceitos de uma linguagem de programação, con-
vém, antes, compreender o que é um programa.

Um programa se manifesta como um documento que especifica


uma sequência de operações a serem executadas. Pode ocorrer, ainda,
de ele efetivamente considerar as operações especificadas durante a
sua execução.

Nesse sentido, entende-se um programa como uma máquina


abstrata que manipula e produz dados. Resumidamente, é a descrição
da máquina, por meio do documento, e a própria máquina quando em
execução. Portanto, todo programa deve ser implementado em deter-
minado mecanismo físico (computador) para que sua execução possa
ser simulada fisicamente.

Assim, uma linguagem de programação define os recursos dispo-


níveis e as formas de construir as máquinas abstratas específicas, de
modo a serem simuladas corretamente nos computadores.

Coerentes com essa perspectiva, De Melo e Da Silva (2003) defi-


nem linguagem de programação como um conjunto de recursos que
podem ser compostos para construir programas específicos ou, ainda,
um conjunto de regras de composição que garantem que todos os pro-
gramas possam ser implementados com qualidade nos computadores.
Nesse contexto, para que linguagens de programação sejam projeta-
das, características, como requisitos, expressividade, paradigma, im-
plementação e eficiência, precisam ser respeitadas.

No caso dos requisitos para a criação de uma linguagem, é impor-


tante questionar a real necessidade dessa criação, bem como quais
problemas serão resolvidos por meio dela. A expressividade irá tratar
os elementos da linguagem que proverão os requisitos desejados. Da
mesma forma, os paradigmas definem como resolver os problemas:
algebricamente, logicamente, por uma sequência de operações, entre
outros. Na implementação, é validado se os requisitos podem ser im-
plementados. Por fim, esses requisitos são avaliados em sua eficiência.

Além dos critérios descritos para a projeção de novas linguagens de


programação, é importante entender quais os critérios relevantes para
sua avaliação. Essa avaliação pode ser aplicada não apenas por progra-
madores, mas também por usuários ao escolherem uma linguagem a
ser estudada ou usada.

10 Técnicas de Programação
As linguagens de programação podem ser classificadas conforme
seus níveis, isto é, níveis mais baixos e níveis mais altos interpretados
pelo processador. As de baixo nível se caracterizam por um conjunto de
circuitos, e as operações dos programas são controladas de forma mais
primitiva, baseando-se no sistema binário de numeração para represen-
tação e operação dos dados. São chamadas também de linguagens de
máquina, principalmente por sua forma de representação e execução.

As linguagens de alto nível são mais similares à linguagem natural,


ou seja, aquela utilizada pelas pessoas na comunicação e na escrita. Po-
rém adotam palavras reservadas – IF, WHILE etc. –, além de permitirem
várias formas de manipulação de dados através dos tipos de dados
existentes (inteiro, real, lógico etc.).

Sebesta (2018) cita como critérios ou propriedades desejáveis para


as linguagens de programação, independentemente de seu nível: legi-
bilidade, redigibilidade, confiabilidade, eficiência, facilidade de aprendi-
zado, ortogonalidade, reusabilidade, modificabilidade e portabilidade.

A legibilidade de uma linguagem de programação diz respeito à


facilidade da leitura e da compreensão de um programa. Quanto mais
fácil o entendimento da estrutura de um programa, maior será o enten-
dimento de suas instruções e, principalmente, a facilidade na correção
de determinados erros.

Linguagens como Basic e Fortran usavam em sua estrutura o co- 1


1
mando goto , que possibilitava a implementação das estruturas de se- O comando goto é usado em
linguagem de programação para
leção e repetição. Por meio dele, tornava-se possível alternar os fluxos
desvio de fluxos de comandos,
de comandos do programa, bem como desviar determinadas instru- isto é, com ele torna-se possível
ções. Porém, com o uso excessivo desse comando, a legibilidade do pular de um trecho de código
para outro.
código tornava-se reduzida, devido à quantidade de desvios realizados.

Não obstante, o uso de um mesmo vocabulário para determinar


comportamentos distintos de instruções também prejudica a facilida-
de de entendimento. Isso acontece na linguagem de programação Java
com a utilização do comando this, o qual é usado como referência de
um objeto ou como uma chamada a uma determinada função. É impor-
tante observar, também, o uso de marcadores como o BEGIN-END, da
linguagem Pascal, e o abre e fecha chaves { - }, da linguagem C. Esses
marcadores podem causar confusões e dificultar o entendimento do
programa quando, na implementação, existe uma grande quantidade

Introdução a linguagens de programação 11


de comandos de repetição e seleção aninhados. Isso ocorre porque
a correspondência entre os marcadores torna-se difícil em relação à
abertura e ao fechamento dos blocos de comandos.

A redigibilidade, por sua vez, possibilita ao programador concentrar-se


nos algoritmos centrais do programa, sem precisar se preocupar com as-
2 pectos irrelevantes para a resolução do problema. Esse critério é o que
mais permite diferenciar as linguagens de máquina e as linguagens de
Incrementos e decrementos em
linguagens de programação são programação, pois, na primeira, era necessário que o programador se
bastante usados em estruturas preocupasse com detalhes de implementação e, na segunda, com a des-
repetitivas como variáveis de
crição do algoritmo para a resolução do problema em questão.
controle. Um exemplo de um
incremento, na linguagem Em determinadas linguagens de programação, como a C, a redi-
de programação C, é c++,
equivalente ao comando gibilidade, muitas vezes, acaba sendo conflitante com a legibilidade.
c:= c +1. O mesmo para o Isso ocorre principalmente na forma de descrever os incrementos e
decremento, apenas diminuindo 2
decrementos de uma estrutura de repetição for e na utilização de
em 1 unidade.
ponteiros.

A confiabilidade, outro item desejável em uma linguagem de pro-


gramação, está relacionada à construção de programas aceitáveis e
Saiba mais confiáveis computacionalmente. Um exemplo são as linguagens que
Ponteiros são bastante se utilizam de declarações de tipos, ou seja, quando verificam automa-
usados em linguagens de
programação estruturada, ticamente os tipos durante a compilação ou execução, as linguagens
pois são variáveis que tendem a ter maior confiabilidade em relação aos erros de digitação.
ocupam uma determinada
posição de memória e, ao A eficiência relaciona-se com o tempo de execução de determinado
mesmo tempo, suportam
armazenamento de ende-
programa. Em aplicações de automação e engenharia em tempo real, o
reços de outras variáveis. tempo é um fator determinante, sendo necessária uma linguagem que
A notação para definição
de uma variável do tipo
permita maior otimização de acesso a periféricos e consumo de memória.
ponteiro é por meio de
Na atualidade, com os avanços tecnológicos de hardware e software,
um asterisco que traduz o
que está sendo apontado, a eficiência torna-se responsabilidade do compilador, por meio da oti-
por exemplo: float *x é um
mização automática do código. Linguagens que utilizam a verificação
ponteiro para um tipo de
dado float. de tipos de dados no processo de execução tornam-se menos eficien-
Saiba mais com a leitura a
tes, se comparadas às que não utilizam essa requisição.
seguir, a partir da página 49:

SAUTER, E.; AZEVEDO, F. S. de; Segundo o critério de facilidade de aprendizado, todo programa-
KONZEN, P. H. de A. (orgs.). dor deve ser capaz de aprender uma linguagem nova com facilidade.
Computação científica em
linguagem C: um livro colaborativo. Nesse sentido, linguagens que necessitam de muitas características e
Universidade Federal do Rio Grande várias formas de usar a mesma funcionalidade tornam-se mais difíceis
do Sul, 9 jan. 2020. Disponível em:
https://www.ufrgs.br/reamat/ de serem aprendidas. Além disso, nesses casos, a maioria dos usuários
ComputacaoCientifica/livro/livro. conhece uma parte da linguagem, dificultando o entendimento de códi-
pdf. Acesso em: 11 mar. 2020.
gos desenvolvidos por outros programadores ou usuários.

12 Técnicas de Programação
A ortogonalidade está relacionada às combinações de conceitos
básicos que o programador é capaz de criar, sem a produção de efei-
tos anômalos nessa combinação. Segundo Varejão (2004), uma lingua-
gem de programação é mais ortogonal quanto menor for o número de
exceções aos seus padrões regulares.

Outra propriedade considerada muito importante é a reusabi-


lidade de código, ou seja, a possibilidade de reusar o mesmo códi-
go fonte para mais de uma aplicação. Normalmente, diz-se que um
código é reusável quando pode ser aproveitado em vários outros
programas/códigos por meio de uma adaptação, sem a necessidade
de construção do zero. Além disso, quando reusados, os códigos já
foram testados e garantem menos tempo de depuração de erros.

Por outro lado, a modificabilidade trata da facilidade de o pro-


gramador alterar o programa em função de novos requisitos esta-
belecidos no desenvolvimento. Não obstante, é necessário que
essas alterações não influenciem modificações em outras partes do
programa.

Já a portabilidade possibilita que os programas desenvolvidos se


comportem de modo independente em relação à ferramenta usada
para sua tradução à linguagem de máquina ou da arquitetura com-
putacional sobre a qual estão sendo executados. Entende-se, nesse
contexto, que um programa pode ser usado em vários ambientes e
em diferentes situações sem despender tempo de programação para
reescrevê-lo ou adaptá-lo ao novo ambiente de tradução e execução.

Além desses critérios, outro ponto a ser destacado ao se trabalhar


com linguagens de programação são os paradigmas aos quais per-
tencem. Paradigmas de programação são conjuntos de características
que podem ser usados para categorizar determinado grupo de lin-
guagens. São divididos em duas categorias: imperativo e declarativo.

O paradigma imperativo aborda os conceitos da computação


relativos às mudanças de estado, ou seja, esse paradigma foca a
forma de processamento via computador de determinada funcio-
nalidade/ação, através do uso de variáveis, atribuições etc. Ainda,
uma vez que sua programação está vinculada a uma sequência de
comandos e desvios, encontra-se nesse paradigma uma subdivi-
são: paradigma estruturado, paradigma orientado a objetos (OO) e
paradigma concorrente.

Introdução a linguagens de programação 13


O paradigma estruturado foi bastante usado, principalmente, para
melhorar a comunicação com a linguagem de máquina, uma vez que faz
uso de desvios e fluxos condicionais que possibilitam o controle da execu-
ção do programa. O paradigma orientado a objetos, por sua vez, surgiu
com o intuito de trazer mais rapidez ao processo de desenvolvimento de
software, devido às suas características de portabilidade e reuso.

No paradigma OO, o foco está na abstração de dados como ele-


mentos básicos de programação, diferentemente do paradigma estru-
turado, em que o foco estava nas abstrações de controle da execução
Leitura dos programas. Dentre as linguagens mais conhecidas e usadas no pa-
radigma OO estão a Smalltalk (totalmente OO), C++, Java, C#, VB.NET,
Python, entre outras.

O paradigma concorrente, última subdivisão do paradigma impera-


tivo, se caracteriza por executar vários processos compartilhando recur-
sos simultaneamente. Nele, são desenvolvidos sistemas que permitem
compartilhar dados ou dispositivos periféricos e, para isso, são usadas
as linguagens Ada e Java, por oferecerem maior suporte à concorrência.
Para saber mais sobre os Em contrapartida ao paradigma imperativo, o paradigma
paradigmas de programa-
ção, sugere-se a leitura
declarativo é definido como as especificações sobre as quais é deter-
do capítulo 3, da obra a minada a tarefa. Nesse paradigma, o programador não precisa ter co-
seguir:
nhecimento sobre como o computador é implementado, assim como
BARANAUSKAS, M. C. C.
Procedimento, função, objeto ou
sobre a melhor forma de realizar a tarefa. Cabe ao programador ape-
lógica? Linguagens de programação nas descrever claramente a tarefa que será resolvida.
vistas pelos seus paradigmas. In:
VALENTE, J. A. (org.). Computadores O paradigma declarativo pode ser subdivido em outros dois, cha-
e conhecimento: repensando
mados de paradigmas funcional e lógico. O paradigma funcional ope-
a educação. 2. ed. Campinas:
Unicamp, 1998, cap. 3, p. 55-76. ra apenas sobre funções, que recebem listas de valores e retornam um
Disponível em:
determinado valor. Varejão (2004, p. 19) diz que esse paradigma “visa
https://www.nied.unicamp.
br/biblioteca/computadores- definir uma função que retorna um valor como a resposta do proble-
e-conhecimento-repensando-
ma”. Como exemplos desse paradigma de programação, citam-se as
educacao/. Acesso em: 5 mar. 2020.
linguagens Lisp, ML e Haskell.
Glossário Por outro lado, os paradigmas definidos como lógicos são baseados
predicado: é toda a relação em cálculos de predicados. Nesse sentido, ao se desenvolver um pro-
existente entre as constantes ou grama no paradigma lógico, esse é sempre composto por cláusulas
variáveis de um programa.
que definem os predicados e as suas relações (VAREJÃO, 2004).

A linguagem de programação mais conhecida, no paradigma lógico,


é chamada de Prolog – bastante utilizada na construção de programas
de Inteligência Artificial.

14 Técnicas de Programação
1.2 Evolução das linguagens de programação
Vídeo Antes das linguagens de programação, a programação era realiza-
da através da linguagem de máquina. Assim, os programadores pre-
cisavam entender exatamente cada um dos comandos referentes à
arquitetura da máquina para que determinada tarefa pudesse ser ini-
ciada e executada. Nota-se que a quantidade de conhecimento para
a programação era bastante alta, e a programação em si tornava-se
pouco produtiva devido a essas dificuldades com instruções e coman-
dos de máquina.

Como linguagem de máquina, entende-se a representação de todas as instituições


ou operações que compõem determinado programa. A base da linguagem de má-
quina é o sistema binário, pois é por meio dele que o hardware do sistema entende
as instruções a serem executadas.

As primeiras linguagens de programação surgiram no final da dé-


cada de 1950 e eram diretamente influenciadas pelas linguagens de
máquina e pela arquitetura dos computadores de John Von Neumann,
conforme ilustrado na Figura 1.

Figura 1
Arquitetura de Von Neumann

Memória
(armazena tanto instruções quanto dados)

Resultados de Instruções e dados


operações

Unidade lógica e Unidade de


Dispositivos de
aritmética controle
entrada e saída

Fonte: Sebesta, 2018, p. 39.

Introdução a linguagens de programação 15


Nessa época, o foco das linguagens era a eficiência computacio-
nal devido à escassez dos recursos de memória e processamento
dos computadores. As linguagens de programação mais conhecidas
e usadas foram Fortran e Cobol.

Artigo

https://www.scielo.br/scielo.php?script=sci_arttext&pid=S0103-40141996000100022

Para compreender a contribuição de Von Neumann às arquiteturas digitais


dos computadores e aos princípios da programação, recomenda-se a leitura
do artigo Von Neumann: suas contribuições à Computação, de Tomasz Kowal-
towski, publicado na revista Estudos Avançados, em 1996.

Acesso em: 5 mar. 2020.

À medida que novos recursos computacionais (hardware) eram


desenvolvidos, os computadores tornavam-se mais úteis e com me-
lhor desempenho na execução de suas atividades. Nesse período, as
linguagens de programação começaram a ser classificadas conforme
seu paradigma e eram divididas em: imperativa (estruturada, orien-
tada a objetos ou concorrente) e declarativa (lógica ou funcional).

Ao final da década de 1950, paralelo ao paradigma estruturado


da época, criou-se o paradigma imperativo, por meio da linguagem
de programação Lisp. Ao final dos anos 1960, por sua vez, as lingua-
gens de programação apresentaram-se mais produtivas e eficientes
aos programadores, em decorrência da utilização de um paradigma
estruturado, isto é, de uma linguagem de alto nível como Pascal e C.

Vale ressaltar que muitas linguagens criadas nas décadas de


1950 e 1960 foram evoluindo e incorporando novas características,
conforme as necessidades encontradas no desenvolvimento de pro-
gramas. Assim, linguagens de programação, como Fortran e Cobol,
passaram a ser usadas também no paradigma estruturado.

16 Técnicas de Programação
Por outro lado, com o desenvolvimento dos sistemas computa-
cionais ao final da década de 1970 e início da década de 1980, as
linguagens de programação apresentaram aumento em sua comple-
xidade de resolução de problemas. O paradigma declarativo, com a
linguagem Prolog, também era bastante utilizado na resolução de
problemas que envolviam Inteligência Artificial. Nessa época, por-
tanto, as linguagens de programação já permitiam o uso de modu-
larizações e bibliotecas nos programas desenvolvidos, bem como já
começavam a aparecer os conceitos de abstrações de dados. São
exemplos de linguagens da época a Modula-2 e ADA.

Por sua vez, nas décadas de 1980 e 1990, os computadores pas-


saram a ser categorizados como de uso pessoal ou estações de
trabalho, atingindo um número maior de pessoas. A indústria de
software então começou a ser difundida, uma vez que existiam de-
mandas para sua criação e manutenção. Através dessa indústria,
tornou-se possível a aplicação dos conceitos de reuso de softwa-
res, aplicados às linguagens de programação orientadas a objetos,
como Smalltalk, Eiffel, C++ e Java. O reuso de software tornava pos-
sível aumentar a produtividade e eficiência no desenvolvimento
dos softwares.

A partir de 2000, as linguagens de programação aderiram a um


paradigma mais voltado à orientação a objetos. Expansões da lin-
guagem Java foram desenvolvidas, assim como novas linguagens
(Ruby, Lua, Phyton, C#...) passaram a fazer parte da vida de muitos
programadores, primeiro, por suas facilidades de aprendizado e, se-
gundo, por questões de desempenho nas instruções a serem execu-
tadas (SEBESTA, 2018).

A Figura 2, a seguir, demonstra a evolução histórica das lingua-


gens, segundo o autor, e demonstra como suas expansões vêm sen-
do aprimoradas a partir da década de 1950.

Introdução a linguagens de programação 17


Figura 2
Evolução histórica das linguagens de programação

1957 Fortran I FLOW-MATIC


58 Fortran II ALGOL 58
59 LISP
60 ALGOL 60 APL COBOL
61
62 Fortran IV CPL
63 SIMULA I SNOBOL
64 BASIC PL/I
65
66 ALGOL W
SIMULA 67
67
ALGOL 68
68
69 BCPL
70 B
Pascal C
71
72
73 Prolog
74
Scheme
75
76
MODULA-2
77
78 Fortran 77 awk ML
79
Smalltalk 80
80
81
82 ICON
Ada 83 Miranda
83
84 COMMON LISP
C++
85
86 Per I
87 MODULA-3 Haskell
Obero n QuickBASIC
88
ANSI C (C89)
89 Eiffel Visual BASIC
Fortran 90
90
91 Python
92
93
Lua PHP Java
94 Ruby
95 Fortran 95 Ada 95
96
Javascript
97
98
C9 9
99
00 C# Python 2.0
Visual Basic.NE T
01
02
Fortran 2003
03
Ruby 1.8 Java 5.0
04
05 Ada 2005
06 C# 2.0
Java 6.0
07 C# 3.0 Python 3.0
08 Fortran 2008 Ruby 1.9
09 C# 4.0
Java 7.0
10
11
12 C# 5.0
13
14
Java 8.0

Fonte: Sebesta, 2018, p. 35.

18 Técnicas de Programação
Na figura, nota-se que Fortran, desenvolvida por John W. Backus, 4
em 1957, para computadores da International Business Machines
4
A IBM, empresa dos Estados
Corporation (IBM) , foi uma das primeiras linguagens de programa- Unidos atuante na área da
ção criada. Apresentava como característica a eficiência computacional, tecnologia da informação, é re-
conhecida por sua longa história
pois não usava alocação dinâmica de memória.
iniciada desde 1911. Atualmen-
Posteriormente, nos anos 1958 e 1959, surgiram as linguagens de te, desenvolve e comercializa
hardware e software.
programação Algol e Lisp. Algol foi considerada a primeira linguagem a
utilizar uma sintaxe formalmente definida. Lisp, por sua vez, criada por
John McCarthy, no Massachusetts Institute of Technology (MIT), através
do seu paradigma funcional e com processamento simbólico, era mais
Curiosidade
usada na área de Inteligência Artificial, assim como ocorre atualmente.
JavaScript é uma lingua-
A linguagem de programação Cobol, na década de 1960, foi desen- gem de programação
que permite implementar
volvida para ser usada em aplicações comerciais e se caracterizava por itens complexos em
ter muitos dados e pouca computação. Os princípios de legibilidade páginas web. É utilizada
sempre que uma página
foram implantados em sua criação, porém acabaram afetando sua web faz mais do que sim-
redigibilidade e comprometendo seu entendimento. plesmente mostrar uma
informação estática, com
No ano de 1964, na Universidade de Darmouth, foi desenvolvida conteúdo que se atualiza
a cada intervalo, mapas
a linguagem Basic por John Kemeny e Thomas Kurtz. Essa linguagem interativos ou gráficos
apresentava um fácil aprendizado e era muito usada por estudantes 2D/3D animados etc.

dos cursos de Ciências Humanas e Artes. Saiba mais em: https://developer.


mozilla.org/pt-BR/docs/Learn/
Há também linguagens usadas por muitos anos, que servem como JavaScript/First_steps/O_que_e_
JavaScript. Acesso em: 12 mar.
base para outras linguagens, como C e Pascal, criadas em 1971. A lingua- 2020.
gem C surgiu com o propósito de ser utilizada no desenvolvimento de
sistemas de programação, em particular na criação do sistema operacio-
nal Unix, desenvolvido por Dennis Ritchie. A linguagem Pascal, por sua
vez, foi desenvolvida para ser uma das linguagens de programação es-
truturada; suas sintaxe e semântica eram bastante simples e intuitivas.

Em 1973, a linguagem declarativa Prolog surgiu para ser aplicada,


através do paradigma lógico, aos problemas de Inteligência Artificial. Já,
em 1980, os conceitos de orientação a objetos e as interfaces gráficas
de usuários (GUI) começaram a ser inseridos por meio da linguagem
Smalltalk, criada por Alan Key e Adele Goldberg.

A linguagem Ada surgiu para atender às demandas de uma lingua-


gem de programação de alto nível, em 1983. Era bastante complexa
e apropriada para a programação concorrente e sistemas de tempo
real. Continuando com a orientação a objetos, em 1985, a linguagem
C++, projetada para ser uma expansão da linguagem C, foi desenvolvi-

Introdução a linguagens de programação 19


da por Bjarne Stroustrup. Foi através dessa linguagem que a orientação
a objetos passou a ser aceita no mercado.

Na sequência, a linguagem Java passou a ser adotada, em 1995, na


construção de sistemas de controle embutido, embora seu fim tenha
sido diretamente aplicado a sistemas corporativos e comerciais. Sua
base de criação foi a linguagem C++ e apresentava muita confiabilidade
Saiba mais
e portabilidade, principalmente pelo uso da Internet já neste período.
A linguagem de programação
Lua é bastante usada no Após o surgimento da linguagem Java, outras linguagens como Lua,
desenvolvimento de jogos. PHP e Ruby foram desenvolvidas. Lua, por ser uma linguagem de script,
Por ser baseada em scripts,
traz benefícios na criação do possibilita maior integração com aplicações industriais e outros tipos
script do jogo. Para saber mais, de linguagens – uma delas é a Ruby, por exemplo, considerada uma
recomenda-se ler: https://www. linguagem interpretada multiparadigma e de tipagem dinâmica. Já a
lua.org/doc/wjogos04.pdf.
Acesso em: 6 mar. 2020. linguagem PHP é bastante atuante no desenvolvimento de aplicações
com conteúdos dinâmicos na web, ao lado do servidor.

Nota-se que, com o passar dos anos, principalmente após 2000,


poucas foram as linguagens criadas. Surgiram, sim, expansões e me-
lhorias das linguagens já existentes, tais como Java 6 – 7, entre outras.

Assim, dentro do leque de linguagens de programação existentes,


é necessário o entendimento do programa a ser desenvolvido para,
então, escolher qual melhor paradigma e linguagem a serem usados.

1.3 Razões para estudar linguagens


Vídeo de programação
As linguagens de programação devem servir para que o trabalho
dos programadores seja realizado de modo mais produtivo e eficaz.
Assim, entende-se que, através das linguagens de programação, o pro-
cesso de desenvolvimento de software torna-se mais efetivo e produ-
tivo, uma vez que possibilita aos programadores e demais envolvidos
uma padronização de desenvolvimento e fácil manutenção dos pro-
gramas quando necessário. Nesse sentido, entende-se que essas lin-
guagens são fundamentais dentro da sua especialidade e vários são os
benefícios de estudá-las. Varejão (2004, p. 3) cita como razões para o
estudo das linguagens de programação:
•• Maior capacidade de desenvolver soluções computacionais para
problemas.

20 Técnicas de Programação
•• Maior habilidade ao usar uma linguagem de programação.
•• Maior capacidade para escolher linguagens de programação
apropriadas.
•• Maior habilidade para aprender novas linguagens de
programação.
•• Maior habilidade para projetar novas linguagens de programação.

A capacidade de desenvolver soluções computacionais ou, como


afirma Sebesta (2018), de aumentar a expressão de ideias é decorrente
da compreensão e profundidade intelectual utilizadas na comunicação.
Isso implica dizer que quanto menor as limitações de pensamento,
maior será a facilidade de abstração e interpretação de problemas do
mundo real para o mundo computacional.

Em relação às habilidades adquiridas, ao se utilizar uma linguagem


de programação, é importante frisar que quanto mais experiência o
programador adquirir no processo de desenvolvimento, maior será
sua capacidade na construção de códigos-fonte com modularização,
recursividade e outros recursos que a maioria dos programadores ex-
perientes adota para melhor desempenho do código.

Assim, esse benefício acaba auxiliando na escolha de linguagens


de programação apropriadas para a resolução de determinados pro-
blemas. Em muitos casos, quando lhes é permitido escolher qual lin-
guagem utilizar em um novo projeto de criação, os programadores
continuam a usar aquela com a qual estão mais acostumados, mesmo
que seja pouco adequada à necessidade. Diante disso, entende-se que
quanto mais os programadores estiverem familiarizados com outros
tipos de linguagem, mais acertada será a escolha.

Sobre o uso do paradigma de orientação a objetos, os programado-


res que já dominam seus conceitos são capazes de aprender, mais rapi-
damente, outras linguagens nesse mesmo formato. Além disso, segundo
Sebesta (2000 apud SCHÜTZ, 2003, p. 2), “programadores que entendem
o conceito de abstração de dados terão mais facilidade para aprender
como construir tipos de dados abstratos em Java do que aqueles que
não estão absolutamente familiarizados com tal exigência”.

Ainda, para o autor, é primordial que os programadores saibam o


vocabulário e os conceitos fundamentais das linguagens, pois, assim, é
possível ler e entender os manuais e sua literatura de venda de lingua-
gens e de compiladores (SEBESTA, 2018, p. 17).

Introdução a linguagens de programação 21


Outro ponto a ser destacado é a possibilidade de participação ou de
criação de uma nova linguagem de programação de propósito geral. Ao se
desenvolver as interfaces gráficas com o usuário de sistemas, por exem-
plo, muitas vezes, é necessário projetar e implementar uma linguagem de
comandos para comunicação entre os envolvidos – no caso, o usuário e o
sistema. Dessa forma, o conhecimento das linguagens de programação
tanto por parte dos programadores como dos usuários torna-os mais ca-
pazes de entender e utilizar os recursos disponíveis.

Artigo

https://revistas.unifacs.br/index.php/rsc/article/download/5133/3488

Sugere-se a leitura do artigo Análise comparativa de linguagens de


programação, dos autores Rodrigo Duarte Seabra, Isabela Neves Drummond
e Fernando Coelho Gomes, publicado em 2018, na Revista de Sistemas
e Computação, que trata sobre uma análise comparativa das linguagens
de programação em relação aos seus paradigmas, a partir de problemas
clássicos da área.
Acesso em: 6 mar. 2020.

Além das cinco razões para o estudo das linguagens de progra-


mação citadas por Varejão (2004), outras duas são apresentadas por
Sebesta (2018), a saber: entender melhor a importância da implemen-
tação e o avanço global da computação. A primeira pode ser aborda-
da pelo princípio de que o aprendizado dos conceitos de programação
é fundamental e necessário para discutir as questões envolvidas em
suas implementações. Outro ponto a destacar por agregar esse conhe-
cimento é que determinados erros de programação somente são iden-
Glossário
tificados e corrigidos por programadores que dominam os detalhes da
recursividade: “recursividade
linguagem. Programadores que pouco sabem a respeito de recursão,
ou função recursiva significa
a invocação de si mesmo. Ou por exemplo, não imaginam que um algoritmo recursivo é muito mais
seja, é uma função que após lento do que um interativo equivalente.
executar o seu bloco de instrução
invoca a si mesma novamente” A segunda razão, sobre o avanço global da computação, envolve
(RECURSIVIDADE..., 2020). assumir que nem sempre é possível entender e identificar que as lin-
guagens de programação mais populares são as melhores disponíveis.
Muitos usuários, por exemplo, acreditam que seria melhor que a lin-
guagem Algol 60 tivesse substituído a Fortran na década de 1960, devi-
do à sua elegância e ao melhor controle de suas instruções.

De modo geral, se os programadores forem mais bem informados,


maior será a probabilidade de escolherem, para seu projeto, melhores
linguagens sobrepostas às linguagens ruins.

22 Técnicas de Programação
1.4 Tradutores de linguagens de programação
Vídeo Os tradutores de linguagens de programação são fundamentais no
desenvolvimento de um programa. Isso porque a linguagem escolhida
pelo programador, independentemente de qual seja, geralmente precisa
ser traduzida para uma linguagem de máquina e, consequentemente, ser
entendida e executada pelo computador. A transformação de uma lingua-
gem de programação em linguagem de máquina acontece pela submissão
do código-fonte desenvolvido para tradução. Posteriormente, esse código
é transformado em linguagem de máquina, possibilitando o entendimen-
to, por parte do computador, das instruções que precisam ser executadas.

A forma como os programas serão implementados nas linguagens de


programação está relacionada à determinação do programa tradutor, isto
é, como o código-fonte traduzido se comportará efetivamente quando
executado no computador. Para Sebesta (2018), os métodos de imple-
mentação e tradutores de linguagens de programação são divididos em:
compilação, interpretação pura e sistemas de implementação híbridos.

1.4.1 Compilação
O método de compilação consiste no processo em Figura 3
que os programas são traduzidos para a linguagem Processo de compilação
de máquina e, então, executados diretamente no Programa-fonte
computador. Esse método realiza a tradução integral
do programa-fonte ou código-fonte para o código da Analisador
léxico
máquina, de modo que o programa passa a ser exe-
Unidades léxicas
cutado diretamente após esse processo.
Analisador
Segundo Sebesta (2018), o processo de compila- sintático

ção e a execução do programa ocorrem em fases di- Árvores de análise sintática

ferentes, conforme ilustrado na Figura 3. Tabela de Analisador Otimização


símbolos sintático (opcional)
As principais fases do processo de compilação
são analisador léxico, analisador sintático e gerador Código intermediário

de código. O primeiro é responsável por verificar os Gerador de


caracteres escritos no código-fonte e transformá- código

-los em unidades léxicas, que são representados por Linguagem de máquina


Dados de entrada
identificadores, palavras reservadas, operadores e
Computador
símbolos de pontuação usados na linguagem de pro-
gramação. Além disso, os comentários existentes no
Resultados
código-fonte são ignorados nesta fase. Fonte: Sebesta, 2018, p. 47.

Introdução a linguagens de programação 23


O analisador sintático, segundo Branco e Tamae (2008, p. 3),
“é responsável por verificar se a sequência de símbolos contida no
código-fonte compõe um programa válido ou não”. O gerador de código
intermediário, por sua vez, “é responsável por gerar uma representa-
ção intermediária ao código final, a partir da árvore sintática e da tabela
de símbolos, tal que essa representação se aproxime do código-alvo”
(FOLEISS, 2009, p. 17).

A vantagem desse método é a otimização da eficiência na execu-


ção dos programas. A velocidade na execução é decorrente das veri-
ficações de erro serem efetuadas durante a tradução do programa. O
tradutor também apresenta maior autonomia para trazer otimizações
na geração dos códigos executáveis, pois considera o código-fonte de
forma global.

Além disso, quando se trata do método de compilação também é


possível que um código seja executado apenas com o seu executável, ou
seja, não é necessário que o código-fonte do programa esteja junto para
funcionamento. No entanto, a execução de um programa apenas por
um código executável pode apresentar desvantagens, pois nem sempre
será compatível com a plataforma, arquitetura de hardware, que irá exe-
cutá-lo. Caso o programador tenha escrito um programa em linguagem
C, e esse código tiver sido compilado em um ambiente de software livre,
sistema operacional Linux, pode não ocorrer a sua execução em um am-
biente proprietário, sistema operacional Windows, ou vice-versa.

1.4.2 Interpretação pura


Na interpretação pura, um programa interpretador age como si-
mulador de um computador virtual que compreende as instruções da
linguagem de programação. Assim, cada instrução do código-fonte é
traduzida para a linguagem de máquina para ser executada. Posterior-
mente, a tradução do código é executada.

Nesse método, em comparação à compilação, as traduções e execu-


ções dos programas interpretados ocorrem de forma única, e não em
fases separadas. Essa interpretação é a única possibilidade de maior
facilidade na prototipação, pois todas as mensagens de erro podem
referenciar unidades de código-fonte. Outras vantagens desse méto-
do são as facilidades da depuração e escrita de programas flexíveis.
A Figura 4 ilustra esse método:

24 Técnicas de Programação
Figura 4
Processo de interpretação pura

Programa-fonte

Dados de
entrada

Interpretador

Resultado
Fonte: Sebesta, 2018, p. 49.

Nota-se, na Figura 4, que o programa-fonte submete os dados de


entrada, inseridos pelo usuário, para que o interpretador realize as
validações de sintaxe dos comandos e, então, apresente o resultado
do processamento do código-fonte.

Entre as desvantagens do método de interpretação pura há a ve-


locidade de execução do programa. Esse problema é decorrente da
necessidade de o interpretador decodificar determinados comandos
complexos, verificando os possíveis erros e aumentando o consumo
de memória.

1.4.3 Sistemas de implementação híbridos


Para Sebesta (2018), vários sistemas de implementação híbridos
são uma junção entre a compilação e interpretadores puros. Nesse
método, é feita uma tradução dos programas em linguagem de alto
nível para uma linguagem intermediária criada a fim de facilitar a
interpretação.

No método de sistemas de implementações híbridas, são con-


sideradas duas etapas: compilação para o código intermediário e
interpretação do código. Sobre elas, Varejão (2004, p. 16) explica:
a interpretação do código intermediário é muito mais rápida
que a interpretação pura do código-fonte, porque as instruções

Introdução a linguagens de programação 25


do código intermediário são muito mais simples que as do códi-
go-fonte e porque a maior parte das verificações de erro é reali-
zada já na etapa de compilação... Como o código intermediário
não é específico para uma plataforma, os programas já compi-
lados para esse código podem ser portados para as mais dife-
rentes plataformas sem necessidade de adaptação ou mesmo
recompilação, bastando que exista um interpretador do código
intermediário instalado na plataforma em que se deseja execu-
tar o programa.

Para melhor entendimento de como funcionam esses sistemas,


pode-se considerar o fato de que as primeiras implementações de
Java eram todas híbridas. O formato intermediário bytecode permite
maior portabilidade para qualquer máquina que tenha um interpre-
tador de bytecodes e um sistema de tempo de execução associado.
A figura a seguir ilustra esse raciocínio:

Figura 5
Sistemas de implementação híbridos

Dados de
Árvores entrada
Código
Unidades de análise
intermediário
léxicas sintática

Gerador
Analisador Analisador
Programa-fonte de código Interpretador Resultado
léxico sintático
intermediário

Fonte: Adaptada de Sebesta, 2018, p. 50.

A figura mostra o funcionamento de um sistema de implementação


híbrido, onde o código-fonte é submetido ao analisador léxico que ve-
rifica a sintaxe da linguagem de programação e cria unidades léxicas
para os caracteres escritos no código. Posteriormente, essas unidades
são submetidas ao analisador sintático que a representa através de
uma árvore de análise sintática para, então, através do gerador de códi-
go intermediário, ser criado um código reconhecido pelo interpretador
para a leitura dos dados e o processamento deles.

Nesse sentido, toda plataforma computacional necessita ter a


sua própria máquina virtual Java para que a execução do programa
seja realizada.

26 Técnicas de Programação
CONSIDERAÇÕES FINAIS
As linguagens de programação encontram-se presentes no cotidiano,
seja através dos softwares utilizados na realização de determinadas tare-
fas no computador ou em programas embutidos em aparelhos eletroele-
trônicos ou industriais.
Embora tenham surgido há décadas e sido classificadas em vários pa-
radigmas, nota-se que determinadas linguagens de programação apre-
sentaram maior aderência e aplicabilidade do que outras. Essa aderência
esteve muito relacionada às qualidades de cada linguagem, isto é, progra-
madores têm buscado linguagens que apresentem maior portabilidade,
flexibilidade, reusabilidade e outras características impactantes nos siste-
mas computacionais utilizados por diversos tipos de usuários e sistemas
operacionais.
Além disso, com a evolução tecnológica dos hardwares, torna-se
possível expandir as linguagens de programação existentes, pois o pro-
cessamento e desempenho dos processadores possibilitam mais inde-
pendência em relação aos seus métodos de implementações e aos seus
tradutores para a linguagem de máquina.
Diante disso, os ambientes de programação são fundamentais para
os sistemas de desenvolvimento de software, nos quais a linguagem de
programação é um dos componentes do processo.

ATIVIDADES
1. Qual é a importância da linguagem de programação para o desenvol-
vimento de um programa?

2. Quais são as razões para se estudar as linguagens de programação?

3. Descreva a diferença entre os paradigmas declarativo e imperativo.

4. Quais são os métodos de implementação das linguagens de progra-


mação?

REFERÊNCIAS
BRANCO,@dia, G. A. Jr.; TAMAE, R. Y. Uma breve introdução ao estudo e implementação
de compiladores. Revista Científica Eletrônica de Psicologia, ano V, n. 8, fev. 2008.
Disponível em: http://faef.revista.inf.br/imagens_arquivos/arquivos_destaque/
RHXqIjJHvJQhhCK_2013-5-28-11-13-48.pdf. Acesso em: 13 mar. 2020.
DE MELO, A. C. V.; DA SILVA, F. S. C. Princípios de linguagens de programação. São Paulo:
Editora Blucher, 2003.

Introdução a linguagens de programação 27


FOLEISS, J. H. et al. SCC: um compilador C como ferramenta de ensino de compiladores.
In: Workshop sobre Educação em Arquitetura de Computadores – WEAC 2009,
p. 15-22. Disponível em: http://docplayer.com.br/37006644-Scc-um-compilador-c-como-
ferramenta-de-ensino-de-compiladores.html. Acesso em: 13 mar. 2020.
RECURSIVIDADE. eXcript: dicionário técnico de programação. Disponível em: http://excript.
com/dicionario/indice.html. Acesso em: 12 mar. 2020.
SEBESTA, R. W. Conceitos de linguagens de programação. 4. ed. Porto Alegre: Bookman,
2000. In: SCHÜTZ, F. Programação orientada a comportamentos baseada no modelo de atores.
Florianópolis, 2003. 90f. Dissertação (Mestrado em Ciência da Computação) – Centro
Tecnológico, Universidade Federal de Santa Catarina. Disponível em: https://repositorio.
ufsc.br/xmlui/handle/123456789/86260. Acesso em: 6 mar. 2020.
SEBESTA, R. W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman, 2018.
VAREJÃO, F. M. Linguagem de programação: conceitos e técnicas. Rio de Janeiro: Elsevier, 2004.

28 Técnicas de Programação
2
Desenvolvendo um programa
Você já percebeu que, a cada dia, o número de aplicativos
para celular ou computadores aumenta exponencialmente?
Esses aplicativos também podem ser definidos como progra-
mas, os quais são um conjunto de instruções e comandos exe-
cutado logicamente em um determinado computador, para um
fim específico.
Para que um programa possa ser executado em alguma
máquina, é necessário que a linguagem de programação esco-
lhida cumpra uma sequência de etapas ou fases. Por exemplo,
é preciso ter uma sintaxe de fácil compreensão, assim como a
semântica suportar vários tipos de dados, estruturas básicas de
desenvolvimento, entre outros conceitos e métodos de imple-
mentação imprescindíveis a uma linguagem de programação.
Além disso, outro ponto importante ao desenvolver um pro-
grama diz respeito à manipulação de dados. Na operação de
algum programa, vários tipos de dados são inseridos e a lingua-
gem de programação adotada deve suportar essa diversidade
para garantir uma boa computação deles.
Entende-se que a tarefa de um desenvolvedor de linguagem
de programação não é trivial, bem como a de um utilizador de
linguagem de programação. Nesse sentido, é importante que
todo e qualquer programa, independentemente de sua lingua-
gem, seja construído de maneira clara, objetiva e concisa para
sua utilização por todos os envolvidos.

Desenvolvendo um programa 29
2.1 Análise léxica e sintática
Vídeo O entendimento de conceitos como análise léxica e sintática é de
suma importância na construção de um programa, independentemente
de sua linguagem de programação. Você já ouviu falar deles?

Caso não, vale destacar que toda linguagem de programação


apresenta uma descrição vista sob dois aspectos: sintaxe e semânti-
ca. A sintaxe pode ser entendida como um conjunto de regras que
permite identificar quais construções são corretas, enquanto a se-
mântica trata de como as construções da linguagem devem ser exe-
cutadas e interpretadas.

Sebesta (2018) afirma que os maiores problemas encontrados na


descrição sintática e semântica de uma linguagem de programação es-
tão relacionados à quantidade de pessoas que utilizarão essa lingua-
gem e quais serão seus entendimentos sobre ela.

Figura 1
Sintaxe e semântica de uma linguagem de programação

photovibes/Shutterstock

Nesse contexto, é importante que os usuários das linguagens


de programação, para criar seus programas, entendam-nas quan-
do consultarem seus manuais de referência. Por isso, é preciso
que os conceitos de sintaxe e semântica sejam bem definidos e
compreendidos.

30 Técnicas de Programação
Para Sebesta (2018), a sintaxe de uma linguagem de programação
é a forma de suas expressões, instruções e unidades de programa-
ção. Por sua vez, a semântica é entendida como o significado dessas
expressões, instruções e unidades de programação. Ambos os termos
estão diretamente relacionados e, quando bem projetada a lingua-
gem de programação, a semântica segue a sintaxe. Um exemplo é a
expressão escrita na linguagem Pascal:
x:=y
Vê-se que a sintaxe é responsável por verificar se o comando de atri-
buição está correto, e a semântica por realizar a substituição do valor
de x pelo valor de y.

Outro exemplo, na linguagem C, é descrito no comando de uma es-


trutura de seleção da linguagem:

if (<expressão>) <instrução> Glossário

Novamente, a sintaxe verifica se o comando está correto, e a semân- compilador: “é o programa


de sistema que traduz um
tica analisa o valor da expressão – se verdadeiro, a instrução/comando programa descrito em uma
é selecionada para a execução. linguagem de alto nível para um
programa equivalente em outra
Ainda pensando no desenvolvimento de um programa, veja o tre- linguagem, como o código de
cho de um código-fonte e como a busca por erros sintáticos é realizada máquina para um processador”.
(RICARTE, 2008, p. 8)
por um compilador ou interpretador:

Figura 2
Trecho de código-fonte desenvolvido em linguagem de programação C

1. int x=0, aux, A [4]; float y#;


2. aux = ‘0’
3. for (x=0, x<4; x++
4. {
5. A[x] = aux++;
6. }

Fonte: Elaborada pela autora.

Quando um código é elaborado, a responsabilidade de um compi-


lador é apontar os erros encontrados na linguagem de programação,
isto é, os comandos que não representam corretamente a sintaxe da
linguagem adotada. Na Figura 2, vê-se que, durante a análise da com-
pilação, os seguintes erros foram identificados em relação a problemas
de léxico, sintaxe e semântica:

Desenvolvendo um programa 31
•• Em relação à análise léxica, foi percorrido o trecho de código e
analisado os vocabulários (x, y, for, =, (, <, int, ++, aux,
A []). Erro léxico foi identificado na variável y#.
•• Na análise sintática, são verificadas as combinações dos tokens
que formam o programa, por exemplo, o comando for → for
(expr1; expr2; expr3) {comandos}. Na linguagem de
programação C, o comando for precisa respeitar uma sintaxe
para que o compilador entenda o que faz parte do vocabulário
da linguagem, como as expressões utilizadas nas estruturas de
repetição.
•• No exemplo, os erros são apontados em relação à estrutura do
comando ; for(x=0,... ), uma vez que as expressões pre-
cisam estar dentro de parênteses e separadas por ponto e vír-
gula. Como observa-se na Figura 2, terceira linha, não existe um
fechamento de parênteses e as expressões estão separadas por
vírgula e ponto e vírgula.
•• Já a análise semântica do trecho de código apresentado busca os
tipos semelhantes em comandos com, por exemplo, a atribuição
e seus respectivos identificadores declarados. Na situação em
Leitura
questão, erros não foram encontrados, pois a semântica estava
Sugere-se conhecer a
dissertação de Diego coerente com o especificado.
Roberto Gonçalves de
Pontes, intitulada Geração Sebesta (2018) defende que a análise léxica deve ser separada da
de rótulo de privacidade análise sintática por razões de simplicidade, eficiência e portabilidade.
por palavras-chaves e
casamento de padrões A simplicidade é decorrente de as técnicas de análise léxica serem
(2016), que “discute mais fáceis, se comparadas à análise sintática, de modo que mantê-las
como o conteúdo das
políticas de privacidade divididas é mais viável. Além disso, quando detalhes de baixo nível são
pode ser apresentado de removidos de um analisador léxico, este se torna menor e mais limpo
maneira mais sintética
para o usuário, com as de se utilizar.
informações sobre a
coleta e a utilização dos Já a eficiência trata da otimização do analisador léxico, que necessi-
dados sendo exibidas em ta de uma grande quantidade de tempo de compilação, tornando inviá-
uma tabela, denominada
Rótulo de Privacidade”. vel a sua otimização. A portabilidade, por sua vez, aborda os arquivos
São Carlos, 2016. Universidade de entrada lidos, de maneira que o analisador sintático seja indepen-
Federal de São Carlos. Disponível dente da plataforma.
em: https://repositorio.
ufscar.br/bitstream/handle/ Pode-se dizer que a análise léxica é uma junção de padrões, tam-
ufscar/8730/DissDRGP.
pdf?sequence=1&isAllowed=y. bém chamada de casamento de padrões, em que o analisador léxico
Acesso em: 17 abr. 2020. tenta encontrar uma subcadeia de caracteres idêntica ao padrão in-
formado. O casamento de padrões vem sendo usado há muitos anos,

32 Técnicas de Programação
tendo sua primeira aplicabilidade nos editores de texto chamados ed,
introduzidos no sistema operacional UNIX.

Um analisador léxico é sempre utilizado em conjunto com um ana-


lisador sintático. O primeiro realiza uma varredura na análise sintática
de todo o programa desenvolvido e, então, um programa de entrada
para um compilador surge com uma única cadeia de caracteres.

2.2 Nomes e variáveis


Vídeo No desenvolvimento de um programa, vale destacar a importância
dos nomes e das variáveis utilizados no código-fonte. Os nomes dos
atributos são características das funcionalidades do programa. Por
exemplo, se o programa em desenvolvimento trata de um cadastro de
clientes de um departamento, atributos como nome_funcionario,
endereço, cidade e telefone são necessários. O fato de adotar nomes
representativos às atividades que serão realizadas permite que outro
desenvolvedor entenda não somente a sintaxe, mas, também, a se-
mântica do programa e o raciocínio do programador.

Em linguagens de programação, para nomes é atri- Glossário


buído um uso mais amplo do que simplesmente o nome: cadeia de caracteres
nome dado a uma variável. Associam-se nomes a rótu- utilizada para identificar uma
entidade de um programa.
los, rotinas, parâmetros formais e outras construções
necessárias ao desenvolvimento do programa.

As primeiras linguagens de programação adota- Curiosidade


vam como nomes apenas um caractere. Isso porque Dependendo da nomenclatura
adotada ou do autor usado
elas se baseavam em equações matemáticas que
como referencial, vê-se que o
usavam apenas um caractere para representar as termo nome é associado com o
notações formais, como x, y, a, b. identificador.

Com o tempo, porém, os nomes passaram a ser


compostos por uma cadeia com um limite longo de caracteres, adicio-
nando sublinhados (_) que representam os espaços em branco na es-
crita da língua portuguesa.

Hoje, as linguagens de programação possibilitam maior concate-


nação e conexões entre os nomes usados – inclusive, algumas delas
fazem distinção entre letras maiúsculas e minúsculas na definição do
nome. Além disso, a mudança da linguagem de máquina para as lin-

Desenvolvendo um programa 33
guagens atuais se caracteriza pela substituição dos endereços numéri-
cos de memórias por nomes, tornando as linguagens mais legíveis, de
fácil entendimento e escrita.

Como exemplo, tem-se os seguintes nomes: Contador,


contador, CONTADOR. Os três são entendidos de modo diferente
pelo compilador adotado na linguagem de programação C++ e, para
alguns autores, essa diferenciação é vista como um grande proble-
ma de legibilidade.

Algumas linguagens permitem que seus nomes sejam declarados


com essa distinção, enquanto outras utilizam as duas formas de nomes
predefinidos, como é o caso da linguagem Java.

Dessa forma, algumas regras são criadas para o uso de nomes, de


modo que respeitem as palavras especiais da linguagem. Estas são
usadas para definir as palavras reservadas, ou seja, aquelas emprega-
das para tornar os programas legíveis ao dar nome às ações a serem
executadas.

Assim, segundo Sebesta (2018, p. 178), “uma palavra reservada é


especial e não pode ser usada como um nome”. Alguns exemplos de
palavras reservadas são ilustrados no Quadro 1.

Quadro 1
Exemplos de palavras reservadas

if for while

repeat int float

struct boolean caractere

Fonte: Elaborado pela autora.

Nesse sentido, os nomes são utilizados para representar uma va-


riável no desenvolvimento de um programa. As variáveis são com-
postas por nome, endereço, tipo, valor, tempo de vida e escopo de
visibilidade.

Os nomes das variáveis são, geralmente, atribuídos pelo programa-


dor e são representativos para o entendimento do problema. Ao dar
nomenclatura a uma determinada variável, regras precisam ser segui-
das, tais como:

34 Técnicas de Programação
•• Não deve iniciar com número.
•• Não deve ter caracteres especiais { ( + - * / \ ; . , ? .
•• Não deve apresentar espaços em branco.
•• Não pode usar hífen ou acentuação.
•• Pode conter letras maiúsculas, minúsculas, números, subscrito
ou underline (_).

O Quadro 2 ilustra nomes válidos e inválidos para serem atribuídos


a uma variável.

Quadro 2
Exemplos de nomes válidos e inválidos de variáveis

Nomes válidos Nomes inválidos

Nota 1Nota

nota_1 nota 1

email @e-mail

Cadastro1 Cadastro1º

Endereco endereço

Fonte: Elaborado pela autora.

O endereço da variável é sua posição na memória da primeira cé-


lula ocupada pela variável. A variável de nome cidade, por exemplo,
ocupa a primeira célula do endereço de memória FF00.

O tipo de dado de uma variável especifica o conjunto de valores Glossário

que ela pode assumir – se for um número decimal, por exemplo, será valor: termo usado como
representação de valores. Em
atribuído à variável um tipo de dado inteiro. linguagens de programação,
valores significam que estão
Já o valor de uma variável pode ser alterado à medida que ela é atua-
sendo representados dados.
lizada. Em outras palavras, uma variável pode iniciar a sua execução
com um determinado valor e, conforme as instruções/comandos do
programa forem executadas, esse valor pode ser alterado.

O tempo de vida de uma variável corresponde ao período de sua


existência e está diretamente relacionado ao tempo em que há células
de memória alocadas na variável. Assim, o tempo de vida é diferente
quando as variáveis são globais ou locais.

Desenvolvendo um programa 35
Para uma variável global, o tempo de vida é todo o período de
execução do programa em que foi declarada. Em contrapartida,
em variáveis locais, o tempo de vida corresponde ao período em
Atenção que o bloco de comando no qual as variáveis foram declaradas é

É importante não confundir executado.


escopo de visibilidade de uma
Já o escopo de visibilidade descreve o trecho do programa em
variável com seu tempo de vida.
Varejão (2004, p. 86) afirma que, que a variável foi referenciada.
“em determinadas situações,
uma variável pode estar alocada Outro aspecto importante a destacar no uso de variáveis é que,
num ponto de execução do em determinadas circunstâncias, valores precisam ser armazena-
programa, mas não ser acessível dos, e não alterados, durante a execução da computação. Para isso,
naquele ponto”.
são utilizadas as constantes, entidades de programas para guardar
esses valores. Um exemplo de constante é o pi, que sempre apre-
senta o valor de 3,1415.

As constantes são valores predeterminados que devem aparecer


dentro de um programa. Como as variáveis, as constantes são com-
postas por nome, endereço, valor, tipo, tempo de vida e escopo de
visibilidade.

Podendo ser definidas na própria linguagem de programação,


ou então criadas pelo usuário ou programador, o que diferencia as
constantes é o fato de que, quando predefinidas, são referenciadas
por símbolos ou identificadores associados aos valores dos tipos de
dados da linguagem de programação. Por sua vez, quando definidas
pelos usuários, as declarações precisam ter um nome associado ao
programa (VAREJÃO, 2004).

É importante esclarecer que as constantes declaradas pelos


usuários tornam-se mais legíveis e permitem maior modificabilida-
de ao programa.

2.3 Tipos de dados


Vídeo Em linguagens de programação, os tipos de dados são fundamen-
tais, pois possibilitam a representação de valores nos códigos pro-
duzidos. Nesse sentido, cada linguagem adota um conjunto próprio
de tipos e valores que permite a representação dos dados utilizados.

36 Técnicas de Programação
Nesse contexto, é válido questionar: como define-se um valor? Tudo
que se avalia durante o processo de computação pode ser entendido
como um valor, ou seja, o que for armazenado, ou incorporado a uma
estrutura de dados do programa, ou então passado como argumento
para uma função ou um procedimento, entre outros. Alguns exemplos
são apresentados na Tabela 1.

Tabela 1
Exemplos de valores na linguagem de programação C

21 3.98 029

“Joao” ‘s’ 0x1F

Fonte: Elaborada pela autora.

Todo valor é acompanhado de um respectivo tipo de dado, isto é, de


um conjunto de valores que exibe comportamento uniforme nas ope-
rações associadas com o tipo de dado. Por exemplo, {true, false}
representa um tipo de dado chamado booleano, de cardinalidade 2,
pois o número de tipos existentes nele é apenas 2.

Assim, ao utilizar uma linguagem de programação, sempre é im-


portante compreender seus tipos de dados e, principalmente, a fai-
xa de valores que esses tipos assumem. Da mesma forma, importa
compreender as operações definidas para os valores desses respec-
tivos tipos.

Para melhor entender como esse processo funciona, inicialmente,


é preciso refletir sobre as duas categorias nas quais os tipos de dados
são divididos e quais os aspectos sintáticos e semânticos de cada um
deles – a saber: primitivos e compostos. Para cada uma dessas catego-
rias, outras subcategorias são identificadas para melhor uso de valores
e operações entre os valores.

2.3.1 Tipos primitivos


Os tipos primitivos, também chamados de atômicos, são os valores
que não podem derivar outros valores de tipos mais simplificados. São
norteadores das linguagens de programação, pois servem como base
para a definição de novos tipos a serem construídos.

Desenvolvendo um programa 37
Considerando que os primitivos são definidos na implementa-
ção de uma linguagem de programação, determinadas limitações
de hardware podem impactar nesse processo. Um exemplo dessa
variação é verificado na linguagem de programação C, em que, para
as variações de hardware de 16, 32 ou 64 bits, o tipo int modifica a
sua faixa de valores ou intervalo. Esses tipos podem ser classificados
em: inteiro, caractere, booleano, decimal, ponto flutuante, enumera-
do e intervalos inteiros.

Um tipo inteiro ou numérico corresponde a um intervalo do con-


junto dos números inteiros. Normalmente, em uma linguagem de
programação, existem vários inteiros, decorrentes das operações
que podem ser fornecidas em relação ao hardware da máquina uti-
lizado no desenvolvimento do programa.

Na linguagem de programação Pascal, um exemplo do uso de


tipos de dados inteiros e decimais é:

var x: integer;

y: float;

Percebe-se que x e y são as variáveis declaradas com os respectivos


tipos de dados numéricos. Na linguagem de programação C, os tipos
são enunciados sempre à frente do nome da variável, como pode ser
visto no exemplo:

int x, y;

Outro tipo de dado primitivo bastante usado nas linguagens de pro-


gramação é conhecido como não numérico. Ele trata de representar
valores que não são numéricos, como é o caso do tipo booleano e do
caractere.

Valores de tipo caractere são armazenados como códigos numéri-


cos, porém algumas linguagens de programação adotam um tipo pri-
mitivo no qual os valores correspondem aos símbolos de uma tabela
padrão de caracteres. No caso da linguagem Pascal, o tipo caractere é
oferecido como sendo char.

Tabelas com códigos numéricos para caracteres podem ser vistas


pelo padrão ASCII e UNICODE. A mais utilizada para padronização de
valores é a ASCII, conforme vê-se a seguir:

38 Técnicas de Programação
Dec Hex Oct Chr Dec Hex Oct HTML Chr Dec Hex Oct HTML Chr Dec Hex Oct HTML Chr
0 0 000 NULL 32 20 040 &#032; Space 64 40 100 &#064; @ 96 60 140 &#096; `
Tabela 2

1 1 001 Start of Header 33 21 041 &#033; ! 65 41 101 &#065; A 97 61 141 &#097; a


2 2 002 Start of Text 34 22 042 &#034; “ 66 42 102 &#066; B 98 62 142 &#098; b
3 3 003 End of Text 35 23 043 &#035; # 67 43 103 &#067; C 99 63 143 &#099; c
Tabela ASCII padrão

End of
4 4 004 36 24 044 &#036; $ 68 44 104 &#068; D 100 64 144 &#100; d
Transmission
5 5 005 Enquiry 37 25 045 &#037; % 69 45 105 &#069; E 101 65 145 &#101; e
6 6 006 Acknowledgment 38 26 046 &#038; & 70 46 106 &#070; F 102 66 146 &#102; f
7 7 007 Bell 39 27 047 &#039; ‘ 71 47 107 &#071; G 103 67 147 &#103; g
8 8 010 Backspace 40 28 050 &#040; ( 72 48 110 &#072; H 104 68 150 &#104; h
9 9 011 Horizontal Tab 41 29 051 &#041; ) 73 49 111 &#073; I 105 69 151 &#105; i
10 A 012 Line feed 42 2A 052 &#042; * 74 4A 112 &#074; J 106 6A 152 &#106; j
11 B 013 Vertical Tab 43 2B 053 &#043; + 75 4B 113 &#075; K 107 6B 153 &#107; k
12 C 014 Form feed 44 2C 054 &#044; , 76 4C 114 &#076; L 108 6C 154 &#108; l
13 D 015 Carriage return 45 2D 055 &#045; - 77 4D 115 &#077; M 109 6D 155 &#109; m
14 E 016 Shift Out 46 2E 056 &#046; . 78 4E 116 &#078; N 110 6E 156 &#110; n
15 F 017 Shift In 47 2F 057 &#047; / 79 4F 117 &#079; O 111 6F 157 &#111; o
16 10 020 Data Link Escape 48 30 060 &#048; 0 80 50 120 &#080; P 112 70 160 &#112; p
17 11 021 Device Control 1 49 31 061 &#049; 1 81 51 121 &#081; Q 113 71 161 &#113; q
18 12 022 Device Control 2 50 32 062 &#050; 2 82 52 122 &#082; R 114 72 162 &#114; r
(Continua)

Desenvolvendo um programa
39
40
Técnicas de Programação
Dec Hex Oct Chr Dec Hex Oct HTML Chr Dec Hex Oct HTML Chr Dec Hex Oct HTML Chr
Device
19 13 023 51 33 063 &#051; 3 83 53 123 &#083; S 115 73 163 &#115; s
Control 3

Fonte: Varejão, 2004, p. 50.


Device
20 14 024 52 34 064 &#052; 4 84 54 124 &#084; T 116 74 164 &#116; t
Control 4
21 15 025 Negative Ack. 53 35 065 &#053; 5 85 55 125 &#085; U 117 75 165 &#117; u
Synchronous
22 16 026 54 36 066 &#054; 6 86 56 126 &#086; V 118 76 166 &#118; v
idle
End of Trans.
23 17 027 55 37 067 &#055; 7 87 57 127 &#087; W 119 77 167 &#119; w
Block
24 18 030 Cancel 56 38 070 &#056; 8 88 58 130 &#088; X 120 78 170 &#120; x
End of
25 19 031 57 39 071 &#057; 9 89 59 131 &#089; Y 121 79 171 &#121; y
Medium
26 1A 032 Substitute 58 3A 072 &#058; : 90 5A 132 &#090; Z 122 7A 172 &#122; z
27 1B 033 Escape 59 3B 073 &#059; ; 91 5B 133 &#091; [ 123 7B 173 &#123; {
File
28 1C 034 60 3C 074 &#060; < 92 5C 134 &#092; \ 124 7C 174 &#124; |
Separator
Group
29 1D 035 61 3D 075 &#061; = 93 5D 135 &#093; ] 125 7D 175 &#125; }
Separator
Record
30 1E 036 62 3E 076 &#062; > 94 5E 136 &#094; ^ 126 7E 176 &#126; ~
Separator
Unit
31 1F 037 63 3F 077 &#063; ? 95 5F 137 &#095; _ 127 7F 177 &#127; Del
Separator
O tipo primitivo chamado booleano é o mais simples em todas as
linguagens de programação, pois apresenta apenas dois valores, os
quais correspondem a verdadeiro e falso. Sendo assim, sua cardina-
lidade é do tipo 2.

Em relação ao tipo de dado decimal, o booleano armazena um nú-


mero fixo de dígitos decimais. A localização do ponto decimal é esta-
belecida de maneira arbitrária pela linguagem de programação, pelo
hardware ou pelo programador, em alguma posição das células de me-
mória que armazena o seu valor.

Em programações comerciais, o tipo decimal é muito usado, já que


é possível armazenar os valores de modo preciso, mesmo com um in-
tervalo restrito de conjunto de valores. Esse conjunto reduzido e o des-
perdício de memória para representação do tipo de dado são algumas
das desvantagens do tipo decimal.

Os tipos de dados definidos como pontos flutuantes são responsá-


veis por modelar os números reais, e sua representação é finita, como
em pi.

As linguagens de programação mais atuais utilizam a representação


do hardware para o ponto flutuante de duas formas: float e double. E a
maioria delas acaba adotando o padrão IEEE 754.

Artigo

https://www.lia.ufc.br/~valdisio/download/ieee.pdf

No artigo Padrão IEEE 754 para aritmética binária de ponto flutuante, de


Gerardo Valdisio Rodrigues Viana, publicado na Revista CT, é possível
observar a contribuição do padrão IEEE 754 para o uso de ponto flutuante
nas linguagens de programação.

Acesso em: 17 abr. 2020.

Nota-se que a cardinalidade dos tipos double e float é limitada


pelo número de bits usado em cada uma das representações.

Os tipos enumerados permitem ao programador especificar novos


tipos primitivos, enumerando os identificadores que denotarão os va-
lores do novo tipo. Em linguagem de programação C, os enumerados
podem ser apresentados como:

enum mes_letivo {mar, abr, mai, jun, jul};

Desenvolvendo um programa 41
Os tipos de dados enumerados são usados para melhorar a legibi-
lidade e confiabilidade do código. Nesse caso, a primeira é aumentada
porque os identificadores de valores são mais facilmente reconhecidos
do que códigos numéricos; já a segunda é aumentada por conta dos
valores fora da enumeração, não sendo válidos. Assim, a cardinalida-
de de um tipo enumerado corresponde ao número de identificadores
usados na enumeração.

Já os tipos de intervalo inteiros, por sua vez, herdam as operações


dos inteiros. A variável intervalo pode ser atribuída a variáveis inteiras,
e vice-versa. Analisando estritamente, as inteiras podem ser considera-
das como um subtipo de dados inteiros. As vantagens deste são pra-
ticamente as mesmas dos tipos enumerados. A legibilidade sempre é
aumentada a partir do momento em que fica mais claro qual intervalo
de valores o tipo pode assumir (VAREJÃO, 2004).

2.3.2 Tipos compostos


Os tipos compostos são definidos por tipos mais simples, como os
vetores, as listas, os arquivos, e, segundo Sebesta (2018), são forma-
dos por produtos cartesianos, mapeamentos, uniões e tipos recursivos
usados para classificar e explicar os tipos de compostos.

O produto cartesiano é formado por um conjunto de valores de


tipos de dados diferentes e, nas linguagens de programação, como
Pascal, Cobol, C e Ada, é conhecido como registros. É possível represen-
tar isso com o seguinte trecho de código na linguagem C:
struct cadastro {
char nome [30];
char endereco [30];
char cidade [10];
};
struct funcionário {
struct cadastro nempregado;
Glossário float salario;

tupla: utilizada para agrupar } func;


e organizar uma sequência de
valores, isto é, um conjunto de Na segunda struct, chamada de funcionário, os identificadores
valores/itens em um único valor nempregado e salario são considerados seletores que permitem
composto, como uma data de
nascimento. acessar os componentes da tupla, fazendo com que o programador
não necessite lembrar a ordem dos componentes.

42 Técnicas de Programação
Quando se trabalha com produtos cartesianos em linguagem de
programação, ao se referenciar os componentes de uma determina-
da tupla, é preciso seguir uma notação. De acordo com a linguagem
de programação, para acessar o campo endereço, por exemplo, é
necessário usar:

func.nempregado.endereco

Em linguagens de programação orientadas a objetos, os produtos


cartesianos são representados por meio das classes, e seu modelo de
implementação é com base no armazenamento de valores do produto
em posições adjacentes da memória.

As uniões consistem na junção de valores de tipos distintos para for-


mar um novo tipo de dados, e são classificadas como livres e disjuntas.
As primeiras apresentam intersecção entre o conjunto de valores dos
tipos que compõem a união. Nesse sentido, a união resultante sempre
apresentará como resultado um único valor correspondente a valores
comuns aos vários tipos.

Na linguagem de programação, uma união livre pode ser exemplifi-


cada, conforme descrito por Varejão (2004):
union medida {
int centímetros;
float metros;
};
union medida medicao;
float altura;
medicao.centimetros = 180;
altura = medicao.metros;

printf (“\n altura : %f metros \n”, altura);

Nesse exemplo, nota-se que foi atribuído um valor de


180 centímetros à variável medicao e, na sequência, é utilizada a
variável de medição em metros, não havendo, por sua vez, um valor
a ela atribuído. Essas situações podem trazer consequências impre-
visíveis ao resultado do programa.

Assim, o modelo de implementação de uniões livres consiste, nor-


malmente, em reservar espaço suficiente em memória para abrigar o
componente da união que necessita de mais espaço e compartilhá-lo
com os demais.

Desenvolvendo um programa 43
As uniões disjuntas, por outro lado, não possibilitam intersecção
entre o conjunto de variáveis dos tipos que formam a união. Para isso,
um campo de identificação chamado tag é usado com o intuito de iden-
tificar qual o tipo originário do valor da união disjunta (VAREJÃO, 2004).

Em Pascal, uma união disjunta pode ser representada da seguinte


forma:
TYPE Representacao = (decimal, fracionaria);
Numero = RECORD CASE Tag: Representacao OF
decimal: (val: REAL);
fracionaria: (numerado, denominador: INTEGER);

END;

Vale ressaltar que o modelo de implementação das uniões disjuntas


é idêntico ao das uniões livres.

Sobre os tipos compostos chamados de mapeamentos, trata-se dos


conjuntos de valores correspondentes a todos os valores possíveis dos
mapeamentos de um tipo de dados A em outro B. Muitos entendem o
conceito de mapeamento quando o relacionam aos produtos cartesia-
nos, pois um produto cartesiano de #A elementos pode conter cada
elemento, assumindo qualquer valor do tipo B, por exemplo.

Há mapeamentos finitos e mapeamentos por funções. No caso dos


primeiros, são representados por um conjunto de domínio finito, sen-
do possível citar, como exemplo, os vetores, pois, normalmente, eles
são declarados e utilizados com um tamanho finito de posições.

Tabela 3
Mapeamentos finitos

10 11 13 15 ... 30 34 40

0 1 2 3 ... 4 5 6

Fonte: Elaborada pela autora.

A maior parte das linguagens de programação, ao trabalhar com


mapeamentos finitos e, por sua vez, vetores, sempre restringe o con-
junto índices a um intervalo de inteiros. Ou seja, na Tabela 3, o vetor
pode ser declarado com 7 posições, e o conjunto de índices criados
inicia na posição 0 e finaliza na posição 6.

O mapeamento por funções, como é possível supor, é realizado por


funções. Cabe destacar que uma função implementa um mapeamento

44 Técnicas de Programação
por meio de um algoritmo, o qual toma qualquer valor em uma função
e o computa em outra.

Faz parte do conjunto de tipos compostos, também, o tipo recursivo,


que se caracteriza por valores compostos. Nesse sentido, é possível afir-
mar que um recursivo é definido em termos de si próprio. Como exem-
plo de tipos recursivos é possível citar as listas, utilizadas em estrutura de
dados para armazenamento de um conjunto maior de valores.

2.4 Expressões e sentenças de atribuição


Vídeo As expressões e sentenças de atribuição são muito utilizadas em
qualquer desenvolvimento de programa, independentemente da lingua-
gem de programação adotada. Por meio das expressões, pode-se reali-
zar cálculos e resolver problemas que usam representações aritméticas.
Para isso, é importante entender a ordem de avaliação dos operadores e
seus operandos, bem como conhecer as sobrecargas de operadores que
são conhecidos por terem mais de uma funcionalidade.

Com base nesse entendimento, torna-se mais fácil aplicar às senten-


ças de atribuições as diversas expressões, como aritmética, booleana
e relacional.

2.4.1 Expressões aritméticas


As avaliações realizadas por meio das expressões aritméticas nas
linguagens de programação são bastante semelhantes às aplicadas na
matemática, que contemplam operadores, operandos, parênteses e
funções. Esses operadores, quando usados em expressões, podem ser
vistos de duas formas: unário ou binário. Na primeira, existe apenas
um único operando; na segunda, são dois operandos.

Para Sebesta (2018), a finalidade de uma expressão aritmética é espe-


cificar uma computação ou um cálculo aritmético. Porém, em analogia às
expressões da matemática, a avaliação de operadores em relação à prece-
dência, à associatividade e aos parênteses também precisa ser respeitada.

Sobre a precedência, é importante destacar, em parte, a ordem


de avaliação de operadores. Para melhor entendimento, veja o
exemplo:

x + y * c

Desenvolvendo um programa 45
As variáveis apresentam, hipoteticamente, valores como 3, 2 e 10,
respectivamente. O resultado dessa expressão está relacionado ao
modo como a avaliação dos operadores é realizada. Por exemplo,
da esquerda para a direita, será feita a adição e, posteriormente,
a multiplicação, obtendo-se 50 como resultado; já da direita para a
esquerda, o resultado será diferente, pois, primeiro, será realizada a
multiplicação e, então, a adição com o valor resultante de 60.

Assim como na matemática, quando se realizam expressões arit-


méticas em linguagens de programação, é importante entender as
regras de precedência de operadores, pois, por meio delas, é avalia-
da a forma como as operações serão executadas.

Nesse sentido, as regras de precedência se baseiam na hierar-


quia de prioridade do operador, conforme a visão deste. Em lingua-
gens de programação, a exponenciação tem maior prioridade de
precedência, seguida da multiplicação e divisão, em níveis iguais, e
da adição e subtração binária no mesmo nível, conforme ilustrado
na Tabela 4.

Tabela 4
Precedência geral de operadores aritméticos

Ordem Operação Símbolo

1ª Parênteses ( )

2ª Potenciação **

Multiplicação, divisão, resto e divisão


3ª *, /, mod, div
inteira

4ª Adição, subtração +, –

Fonte: Elaborada pela autora.

Analisando as ordens apresentadas na tabela, nota-se que as pri-


meiras expressões a serem resolvidas serão os parênteses mais in-
ternos, seguidos da multiplicação e divisão, e assim sucessivamente.
No entanto, sempre que houver necessidade de alteração de ordem
de execução das operações, é necessário o uso de parênteses. Na pro-
gramação como um todo, isso é bastante comum, pois o programador,
por meio do uso de parênteses, pode definir qual operação será reali-
zada primeiro. Observe a seguinte expressão aritmética:

46 Técnicas de Programação
(2+3) **2 * (5–2) + 7
5**2 * 3 + 7
25 * 3 + 7
75 + 7
82

Essa expressão é avaliada pelo computador considerando, primei-


ramente, os parênteses mais internos, seguidos da potenciação, da
multiplicação e, por fim, da soma. Caso a ordem de precedência seja
ignorada, o resultado dessa expressão será totalmente diferente.

Outra observação refere-se a quando se apresentam duas


expressões aritméticas com operadores de mesmo nível de precedên-
cia. Nesse sentido, para saber qual precisa ser avaliado primeiro, é ne-
cessário observar a regra da associatividade da linguagem.

Essa regra estabelece que um operador pode tanto ter associativi-


dade à esquerda como à direita, significando que a primeira ocorrência
será avaliada antes ou a ocorrência mais à direita será avaliada primei-
ro, respectivamente (SEBESTA, 2018).

Nas linguagens de programação definidas pelo paradigma impe-


Leitura
rativo, essa associatividade ocorre da esquerda para a direita, exceto
quando a expressão apresenta o operador de exponenciação, de modo
que se associa da direita para a esquerda. Veja a expressão:

A – B + C

O operador esquerdo será avaliado primeiro para que, posterior-


mente, o direito seja verificado.

2.4.2 Operadores sobrecarregados Sugere-se ler Princípios


de linguagens de
Operadores sobrecarregados são aqueles que podem ser utilizados programação, que
para mais de uma funcionalidade na linguagem de programação, como aborda a sobrecarga de
operadores comum nas
o + que, além de representar a adição, pode ser utilizado para conca- diversas linguagens de
tenar cadeias de caracteres. No entanto, ao desenvolver um programa programação. Esse livro
permite entender que
com o uso de operadores sobrecarregados, é importante não afetar a cada linguagem tem sua
legibilidade e confiabilidade do código. forma de representar e
abordar os problemas
Na linguagem C, um operador que pode mostrar determinados por ela causados.

perigos é o & (e comercial), uma vez que, quando usado como opera- MELO, A. C. V. de; SILVA, F. S. C. da.
São Paulo: Blucher, 2003, p. 68-72.
dor binário, representa e especifica uma operação AND lógica. Já se

Desenvolvendo um programa 47
empregado como operador unário, o seu significado é diferente, pois
torna-se o endereço de uma variável em tipos ponteiros.

Ao analisar todas as linguagens de programação, porém, vê-se


que elas apresentam algum tipo de problema de sobrecarga de ope-
radores. Isso se baseia, segundo Sebesta (2018, p. 276), “somente no
fato do compilador saber dizer se o operador pretende ser binário
ou unário”.

2.4.3 Expressões relacionais e booleanos


As linguagens de programação não apresentam apenas expressões
aritméticas na resolução de problemas. Muitas vezes, é necessário o
uso de expressões relacionais, booleanas ou lógicas para garantir o
funcionamento do que está sendo solicitado.

As relacionais são caracterizadas por fazerem uso de operado-


res relacionais, e sua principal funcionalidade é a comparação en-
tre valores de dois operandos. Define-se uma expressão relacional,
portanto, quando se apresentam dois operadores e um operador
relacional.

A sintaxe dos operadores relacionais, para a maioria das linguagens


de programação, pode ser visualizada na tabela a seguir:

Tabela 5
Operadores relacionais

Operação C Java Ada

Igual == == =

Diferente != != /=

Maior que > > >

Menor que < < <

Maior que ou igual >= >= >=

Menor que ou igual <= <= <=

Fonte: Elaborada pela autora.

Cabe ressaltar que os operadores relacionais apresentam me-


nor precedência se comparados aos aritméticos. Isso significa que,
no exemplo x + 3 > 2 * y, as expressões aritméticas serão ava-

48 Técnicas de Programação
liadas primeiro, isto é, serão calculados os valores das expressões
x + 3 e 2 * y para, então, verificar-se a operação maior.

Já as expressões booleanas são compostas por variáveis, cons-


tantes, relacionais e, em operadores booleanos, com operações de
AND (e), OR (ou), NOT (negação) e OR exclusivo.

Os operadores booleanos ou lógicos apresentam precedência hie-


rárquica (mais alta e mais baixa). Para Sebesta (2018, p. 282), “as ope-
rações aritméticas podem ser operandos de expressões relacionais, e
estas podem ser operandos de expressões booleanas, as três catego-
rias de operadores devem ser colocadas em níveis de precedência rela-
tivos entre si”. Assim, as operações booleanas serão sempre avaliadas
após as operações aritméticas, ou seja, sua precedência é mais baixa.

2.4.4 Sentenças de atribuição


As sentenças de atribuição, ou instruções de atribuição, são funda-
mentais para o desenvolvimento de um programa, independentemen-
te da linguagem de programação adotada. Isso porque, por meio das
atribuições, torna-se possível alterar a dinâmica entre as vinculações
de valores a variáveis.

As atribuições podem ser classificadas como simples, alvos múlti-


plos e alvos condicionais, operadores de atribuição compostos e ope-
radores de atribuição unários.

As simples são as mais usadas nas linguagens de programação, pois


a maioria dos desenvolvedores necessita de uma atribuição para reali-
zar um determinado cálculo.

Nas linguagens de programação imperativas, como C, Java e C++, a


notação utilizada para a atribuição de um valor a uma variável ou ex-
pressão é o símbolo de igualdade (=), por exemplo:

A = B = C

Nesse exemplo, está sendo definido A para o valor booleano da ex-


pressão relacional B = C. Pensando matematicamente, essa instrução
de atribuição parece estar mostrando a expressão igual entre si, po-
rém, quando os operadores relacionais são usados para representar a
igualdade, esta é feita por dois símbolos de igual (==). Dessa forma, não
apenas distinguem-se as diferenças entre as linguagens, como também
não são gerados problemas de sobrecarga de operadores.

Desenvolvendo um programa 49
Os alvos múltiplos, por sua vez, possibilitam a atribuição de um va-
lor a mais de uma variável, como na instrução:

SALARIO, TOTAL = 0

Nesse exemplo, o valor zero está sendo atribuído a duas variáveis.


Para os programadores, essa facilidade permite otimizar a quantidade
de linhas de código, mas, em relação à otimização do código-fonte, isso
não interfere em nada.

Sobre os alvos condicionais, estes são usados dentro de uma


condição, como vê-se a seguir, em um exemplo na linguagem Java
(SEBESTA, 2018, p. 285):

bandeira ? cont1 : conta2 : 0;

Essa instrução é equivalente à seguinte condicional:

if (bandeira) cont1 = 0 i else cont2 = 0;

Já os operadores de atribuição compostos são uma forma de des-


crever uma atribuição por meio de abreviação. Dada a atribuição
a = a + b, percebe-se que, de maneira abreviada, sua sintaxe seria
assim apresentada: a + = b.
Nesse método, nota-se que a variável destino, no caso a, também
aparece como primeiro operando no lado direito da expressão. Sendo
assim, torna-se viável a aplicação de uma atribuição composta, do con-
trário, não seria possível.
Por fim, os operadores de atribuição unários também possibilitam
atribuições abreviadas. Estas são mais usadas em operações que com-
binam incrementos e decrementos, por meio dos operadores ++ e --,
respectivamente.

Para melhor entendimento dessa técnica, é possível representar na


instrução a seguir:

soma = ++ cont;

O significado dessa instrução ++ cont é equivalente ao incremento


de uma unidade à variável cont para, posteriormente, ser atribuída
Glossário à soma, pois a forma de declaração dessa instrução é definida como
operador prefixado: pode prefixada. Poderia, também, ser declarado de outra forma na lingua-
ser entendido como aquele que gem de programação, por exemplo:
precede seus operandos.
cont = cont + 1;
soma = cont;

50 Técnicas de Programação
Se o operador for pós-fixado, no entanto, a instrução é apresentada
da seguinte forma:
soma = cont++;

Nesse caso, a atribuição do valor de cont à soma irá acontecer pri-


meiro, para somente então ser realizado o incremento de 1 unidade à
variável cont. Outra forma de declaração é apresentada a seguir:
soma = cont;
soma = cont + 1;

Vale ressaltar que os operadores de incremento e decremento são


bastante usados como atribuição unária para formar expressões utili-
zando matrizes.

CONSIDERAÇÕES FINAIS
O desenvolvimento de um programa nem sempre pode ser conside-
rado uma tarefa trivial. Uma sequência de regras precisa ser estabeleci-
da e entendida, com o objetivo de facilitar a criação de programas aos
programadores/desenvolvedores.
Entre os primeiros cuidados de uma linguagem de programação es-
tão a sintaxe e a semântica, ou seja, a forma notacional da linguagem e
como essa é compilada ou interpretada (ou ambas) pelo computador,
para transformar linguagens de alto nível em baixo nível (linguagem de
máquina).
Dessa forma, entende-se que, ao se desenvolver um programa, sem-
pre é importante que variáveis sejam declaradas para que possam ser
executadas no tempo de vida do programa e, principalmente, possam ar-
mazenar valores, permitindo apresentá-los aos usuários. Além disso, para
cada variável usada, é necessário que tipos de dados lhe sejam atribuídos,
pois eles permitem que as variáveis possam armazenar na memória do
computador uma faixa de valores.
Além disso, foi apresentada a importância de entender como as ex-
pressões podem ser avaliadas pelos programadores e pelo computador
no momento da execução. A ordem de avaliação das expressões aritméti-
cas, relacionais e booleanas é muito similar à encontrada na matemática, e
atende ao mesmo propósito. No entanto, tratando-se de algumas lingua-
gens de programação, determinados operadores podem ser usados com
mais de uma funcionalidade no código-fonte, gerando uma sobrecarga de
operador. Para isso, é necessário que o programador crie estratégias para
sua melhor utilização.

Desenvolvendo um programa 51
ATIVIDADES
1. Qual a importância da sintaxe no desenvolvimento de uma linguagem
de programação?

2. O que são variáveis em linguagens de programação?

3. Como os tipos primitivos são classificados?

4. Qual a importância da precedência de operadores?

REFERÊNCIAS
RICARTE, I. Introdução à compilação. Rio de Janeiro: Elsiever, 2008.
SEBESTA, R. W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman,
2018.
VAREJÃO, F. M. Linguagem de programação: conceitos e técnicas. Rio de Janeiro: Elsevier,
2004.

52 Técnicas de Programação
3
Estruturas de seleção
de controle
No desenvolvimento de um programa, é importante que de-
terminadas estruturas sejam seguidas, pois é por meio delas
que se torna possível a execução de instruções e comandos
no computador. Porém, nessas estruturas, é necessário que
variáveis sejam declaradas, bem como tipos de dados sejam
atribuídos, independentemente da linguagem de programação
escolhida para o desenvolvimento.
Não obstante, além dessas variáveis e dos tipos de dados,
é preciso que o programa utilize determinadas estruturas para
a resolução de seus problemas, e, dentro delas, encontram-se
as estruturas de seleção e controle (DE MELO; DA SILVA, 2003).
Essas estruturas são muito utilizadas pelos mais diversos
programadores ao redor do mundo, uma vez que permitem
maior controle e flexibilização dos comandos executados du-
rante o tempo de vida do programa. Ou seja, pelo uso da es-
trutura de seleção, o programador pode definir qual bloco de
comandos executar, desviando, assim, o fluxo de execução dos
comandos escritos.
O mesmo acontece na estrutura de controle que garante
maior domínio da quantidade de repetições que determinado
trecho de código deve executar. Dessa forma, os programas
desenvolvidos apresentam maior agilidade e desempenho em
seus processos de execução.

Estruturas de seleção de controle 53


3.1 Sentenças de seleção
Vídeo As sentenças de seleção são fundamentais em todo o desenvolvimen-
to de uma programação, porque tornam possível escolher entre dois ou
mais caminhos a serem executados no tempo de vida de um programa.

Em outras palavras, diz-se que as sentenças de seleção são tam-


bém conhecidas como estruturas de seleção, aplicadas para que o
Figura 1 programador possa ter mais de uma opção de instrução a ser execu-
Sentença de fluxo
tada no programa. O trecho do código-fonte pode ser direcionado,
por exemplo, para um conjunto de instruções/comandos, caso
sua condição seja verdadeira, ou, então, para outra
direção.

As sentenças de seleção são, geralmente, conhecidas


por sua classificação em duas categorias gerais, deno-
minadas seleção bidirecional e seleção n-direcional, ou
múltipla.

As seleções bidirecionais visam adotar um conjunto


de considerações do projeto, além de permitir um ani-
nhamento do uso de seletores.
So
ng
_a b As questões de projeto, nas seleções bidirecionais,
out
_sum
me r/Shutterstock referem-se ao modo como determinada expressão pode vir a con-
trolar um seletor. Uma questão de projeto pode estar vinculada a como
esse controle acontece: se por meio de instruções únicas, instruções
Glossário
compostas ou de uma sequência de instruções associadas, por exemplo.
seletores: são utilizados para
realizar o controle de uma deter- Figura 2
minada expressão. Por exemplo, Seleções bidirecionais
uma condição pode ser definida
Tatiana Stulbo/Shutterstock

como um seletor, pois permite


que decisões sejam tomadas
mediante o seu resultado.

54 Técnicas de Programação
Diante disso, para Sebesta (2018), as questões de projeto podem ser
resumidas da seguinte forma:

Uma instrução
única, uma
Qual é a forma ou Como o significado
sequência de
o tipo da seleção dos seletores
instruções ou
que controla a aninhados pode
uma instrução
seleção? ser especificado?
composta pode ser
selecionada?

Com base nas considerações do autor, é importante, primeira-


mente, entender a semântica de um seletor bidirecional. Para isso, é
necessário analisar a seguinte expressão, comumente adotada nas lin-
guagens imperativas (Pascal, C, Fortran etc.):

IF (expressão booleana) instrução

Nesse exemplo, a semântica mostra que a instrução somente será


executada se a avaliação do resultado da expressão booleana for ver-
dadeira. Assim, as questões de projeto para a linguagem Fortran, no
exemplo apresentado, são as seguintes: a expressão do controle do
seletor é do tipo booleano e somente uma única instrução é selecioná-
vel. Na linguagem Fortran, por exemplo, o aninhamento lógico não era
permitido, como acontece nas linguagens Pascal e C.

Porém, ao observar uma expressão que adota um seletor bidirecio-


nal, tem-se como expressão:

IF (expressão booleana) then

Instrução

ELSE

Instrução

Nesse sentido, a semântica de um seletor bidirecional sinaliza que


a cláusula then (denominada pela palavra reservada then) somente é
executada se a expressão for avaliada como verdadeira; caso contrário,
passa a ser executada a cláusula ELSE e, consequentemente, a instru-
ção abaixo dela.

Estruturas de seleção de controle 55


Cabe ressaltar que, desde a década de 1960, as linguagens imperati-
vas têm incorporado, segundo Sebesta (2018), as instruções de seleção
bidirecional. O que as diferencia é a sintaxe, pois algumas adotam a
cláusula then enquanto outras não o fazem, porém a forma de execu-
ção das instruções é a mesma.

Ainda, os seletores bidirecionais podem ser usados de maneira ani-


nhada, ou seja, quando há mais de uma expressão IF em sequência,
conforme ilustrado:

IF (peso == 70)

IF (altura == 180)

Resultado = 0;

ELSE

Resultado = 1;

Essa instrução pode ser entendida de duas formas: 1) consideran-


do a cláusula ELSE coincidente com a primeira cláusula then, ou 2)
considerando-a coincidente com a segunda cláusula. Vale ressaltar,
nesse exemplo, que a palavra reservada then não consta nas instru-
ções, por questões relacionadas à sintaxe da linguagem.

Nas instruções que utilizam seletores bidirecionais aninhados, é


necessário considerar os recuos da estrutura da linguagem, isto é, a
cláusula ELSE pertence à primeira cláusula then. Esses recuos melho-
ram a visibilidade do programador, ao desenvolver o programa, embo-
ra não apresentem nenhum efeito sobre a semântica das linguagens
de programação. Outro ponto importante a ser observado, quando se
adota uma quantidade maior de seletores bidirecionais nas instruções,
refere-se às palavras especiais e ao fechamento de seleção. Observe
o conjunto de instruções que segue, conforme Sebesta (2018, p. 298):

IF A > B then

soma:= soma + A;

cont:= cont + 1;

ELSE

soma:= soma + B;

contb:= contb + 1;

end IF;

56 Técnicas de Programação
Nesse exemplo, nota-se que existe uma palavra reservada denomi-
nada end IF, que é usada quando a cláusula then é um composto.
Sendo assim, uma vez que a palavra reservada end IF permite a fina-
lização das instruções do IF aninhado, fica claro que a cláusula ELSE
coincide com o then interno.

Outro exemplo de fechamento de seleção pode ser ilustrado no tre-


cho de código a seguir, adaptado de Sebesta (2018):

IF soma = 0 then

IF cont = 0 then

Resultado:= 0;

end IF;

ELSE

Resultado:= 1;

end IF;

Nesse exemplo, nota-se que existem IF aninhados e que o primeiro


end IF trata-se do seletor bidirecional interno, enquanto o segundo
refere-se ao fechamento do primeiro IF.

3.2 Sentenças de iteração


Vídeo As sentenças de iteração, quando usadas em qualquer linguagem
de programação, servem para que uma determinada instrução/coman-
do seja executada zero, uma ou muitas vezes. Por esse método de re-
petição, torna-se viável, aos programadores, executar
Figura 3
trechos de códigos repetidamente, evitando que todas as Matrizes para cálculos
computacionais
instruções sejam executadas de modo sequencial, o que
tornaria o desempenho dos computadores bastan-
te limitado.

Cabe ressaltar que as primeiras instruções


iterativas nas linguagens de programação,
para Sebesta (2018), surgiram para melhorar
o uso de matrizes, uma vez que as principais
tock

computações executadas no início do uso


ters

dos computadores eram totalmente voltadas


hut
/S
im

aos cálculos matemáticos.


Ch

Estruturas de seleção de controle 57


Ainda segundo o autor (2018, p. 306), “diversas categorias de instru-
Curiosidade
ções de controle foram desenvolvidas. E as principais estão definidas
Para melhor entender o meca-
nismo de controle de um laço, de acordo como os projetistas respondiam as questões de projetos
a esse é atribuído um corpo, básicas”. Essas categorias estavam diretamente relacionadas à forma
o qual se denomina corpo do como a iteração era controlada, assim como onde o mecanismo de
laço. Este é responsável por
um conjunto de instruções controle deveria aparecer no laço de repetição.
que testa a iteração no início
O controle do laço era tratado pela lógica, pela contagem ou pela
ou ao final. Quando a iteração
é testada no início, chama-se combinação de ambas. Já o mecanismo de controle ocorria pela parte
pré-teste, e quando é testada ao superior e inferior do laço de repetição utilizado.
final, chama-se pós-teste. Em
linguagens de programação, Em relação às instruções iterativas que adotam a categoria conta-
são exemplos o comando While gem como forma de controle, podem utilizar uma variável de laço que
(enquanto) com teste no início e
ao final da execução. mantém o valor da contagem e especificar os valores inicial e terminal
dessa variável, além da forma como eles serão realizados. Entende-se,
então, que os parâmetros de um laço são compostos por especificação
Glossário
inicial e terminal e por tamanho do passo.
tamanho do passo: entendido
como a diferença entre os valores Ainda, as sentenças de iteração podem ser divididas em laços con-
sequenciais da iteração, ou seja, trolados por controlador e laços controlados logicamente. No primeiro
se a iteração é incrementada de caso, as linguagens imperativas, como Pascal e C, utilizam o comando
uma, duas ou mais unidades no
momento de sua repetição. for para representar esse laço controlado por controlador. A forma
geral da instrução for da linguagem C é definida como:

for (expressão_1; expressão_2; expressão_3)

corpo do laço

O corpo do laço pode ser apenas uma instrução, um conjunto de


instruções compostas ou uma instrução nula. Vale destacar que, na lin-
guagem C, a instrução do comando for é mais flexível, se comparada
às demais linguagens, pois cada uma das instruções pode compreen-
der instruções múltiplas que, por sua vez, permitem variáveis de laço
múltiplas, representadas por qualquer tipo.

Como exemplo do uso das instruções múltiplas, vê-se o seguinte


trecho de código para o for, apresentado por Sebesta (2018, p. 313):

for (cont1 = 0, cont2 = 0.0;

cont1 <= 10 && cont2 <= 100.0;

soma = ++ cont1 + cont2, cont2 =*= 2.5);

58 Técnicas de Programação
Nesse exemplo, a instrução for não precisa e não tem um corpo do
laço, pois todas as ações desejadas são apresentadas dentro da pró-
pria instrução (parênteses), e não dentro de seu laço. Por outro lado, Figura 4
quando as instruções são controladas logicamente, normalmente, são Laço de repetição

executadas repetitivamente, de modo que o controle se baseia


em expressão booleana, em vez de um contador. Nesse sentido,
esse tipo de controle torna-se mais geral, pois todo laço de conta-
gem pode ser construído por meio de um laço lógico, porém o
oposto não procede.

Dentre os laços lógicos existentes nas linguagens de progra-


mação imperativas, tem-se como exemplo o while e o do while,
conforme representado a seguir:

while (expressão)

corpo do laço

do

corpo do laço

while (expressão)

Essas duas formas são exemplificadas pelos seguintes trechos de


código, na linguagem de programação C:

int contador = 0;

while(contador < 5)

printf(“contador = %d\n”, contador);

contador += 1;

int contador = 0;

do {

printf(“contador = %d\n”, contador);

contador += 1;

} while(contador < 5);

Estruturas de seleção de controle 59


Nota-se, nesses exemplos, que todas as variáveis são do tipo inteiro
e o contador é usado para iniciar o laço lógico.

Os laços localizados pelo usuário, em determinadas situações, são


convenientes para o programador, pois possibilitam a escolha de uma
localização do controle do laço que não seja no topo ou na base.

Para esse tipo de mecanismo de controle, algumas questões de


f=projeto, segundo Sebesta (2018, p. 316), precisam ser levadas em
consideração:

Deve-se permitir
que o mecanismo Somente um
O mecanismo corpo do laço deve
apareça em um
condicional deve ser finalizado ou
laço controlado ou
ser uma parte laços envolventes
somente em um
integrante da também podem
laço sem qualquer
saída? ser finalizados?
outro controle?

Linguagens de programação como Ada apresentam instruções sem


qualquer tipo de controle de iteração. Dessa forma, os laços se tornam
finitos, a menos que controles sejam adicionados pelo programador.

Por sua vez, nas linguagens de programação C e C++, mecanismos


de controle são incluídos pelo comando continue, que os transfere
para o mecanismo de controle do laço envolvente de menor tamanho.
A ideia dessa estrutura é pular o resto das instruções de laço na ite-
ração anual, sem finalizar a sua estrutura, conforme trecho de código
Curiosidade apresentado por Sebesta (2018, p. 317):

“Todas as instruções contro- while (soma < 1000) {


ladas por usuários são mais
importantes em linguagens getnext (valor);
orientadas a objetos, pois através
dessas os usuários constroem if (valor < 0 ) continue;
rotineiramente tipos de dados
soma += valor;
abstratos para estrutura de
dados” (SEBESTA, 2018, p. 318). }

60 Técnicas de Programação
3.3 Desvio incondicional
Vídeo O desvio incondicional, ao ser adotado no desenvolvimento de um
programa, estabelece-se na forma que o controle da exceção será
transferido para algum lugar determinado no código. Desde o início
das linguagens de programação, na década de 1960, foi questionado
se os desvios incondicionais deveriam fazer parte de qualquer lingua-
gem de alto nível, ou se seu uso deveria ser apenas restrito.

Para Sebesta (2018), o desvio incondicional é uma instrução para


controlar o fluxo de execução de instruções de um programa. No
entanto, ao utilizá-lo, pode-se criar problemas decorrentes da capa-
cidade de um desvio forçar qualquer instrução do programa a seguir
outra sequência de instrução. Os desvios incondicionais são conhe-
cidos, também, pela instrução goto, que apresenta grande flexibili-
dade, pois, por meio dela, outras estruturas de seleção ainda podem
ser construídas com a adição de um seletor.

O ideal no uso de desvios incondicionais em linguagens de pro-


gramação é que apareçam com maior legibilidade nos trechos de có-
digo onde a ordem de execução das instruções seja quase a mesma
em que aparecem no programa.

Cabe ressaltar que nem todas as linguagens de programação uti-


lizam o desvio incondicional goto, como é o caso de Modula-2 e Java.
No entanto, as linguagens C, Pascal e Algol 60 adotam rótulos que
identificam esses desvios nos trechos de códigos.

Em contrapartida, outras linguagens, como Algol 60 e C, empre-


gam formas de rótulos como identificadores, enquanto Pascal e
Fortran recorrem a constantes inteiras, sem sinal para rótulos. Já a
linguagem Ada usa sua forma identificadora como parte-alvo de sua
instrução goto, porém, quando os rótulos aparecem na instrução,
é necessário o uso do símbolo <<OUT>> como forma delimitadora,
conforme o exemplo:

goto TERMINOU

...

<<TERMINOU>> SOMA := SOMA + PROX;

Estruturas de seleção de controle 61


Nota-se que, com o uso dos símbolos << >>, os rótulos são mais
fáceis de serem localizados dentro do programa, principalmente quando
ele necessita ser lido. Na maioria das outras linguagens, esses rótulos são
anexados por meio do uso de dois-pontos, como apresentado a seguir:

terminou: soma := soma + prox

Observa-se que, nesse exemplo, com a utilização dos dois-pontos, o


entendimento do programa é menos legível, pois os rótulos não estão
claramente identificados.

Vale ressaltar que a implementação de rótulos variáveis, indepen-


dentemente da linguagem de programação, é bastante complexa e
que, para ser realizada, as variáveis de rótulos precisam estar vincula-
das a um determinado valor.

3.4 Comandos protegidos


Vídeo Segundo a metodologia criada por Dijkstra (1976), os comandos pro-
tegidos foram criados para que diferentes alternativas de estrutura de
seleção e laços suportassem instruções de controle que assegurassem
a exatidão no desenvolvimento, em vez de recorrer à verificação ou ao
teste completo de programas.

Glossário Nesse contexto, os comandos protegidos são a base de dois me-


CSP (Communicating canismos linguísticos para programação concorrente, desenvolvidos
Sequential Processes): é depois para programação concorrente em duas linguagens: CSP e Ada.
uma linguagem de especificação
formal, desenvolvida para A notação utilizada na construção de seleção de Dijkstra (1976)
modelar aplicações concorrentes, apresenta a seguinte forma:
paralelas e distribuídas.
if <expressão booleana > -> <instrução>

[ ] <expressão booleana > -> <instrução>

[ ] ...

[ ] <expressão booleana > -> <instrução>

fi

Nota-se, na construção dessa seleção, que a palavra reservada fi


é usada para fechamento, enquanto a abertura é grifada de trás para
a frente com if. Embora a aparência dessa seleção seja semelhante
à de uma seleção múltipla, sua semântica é totalmente diferente. To-
das as expressões booleanas são avaliadas cada vez que se alcança a

62 Técnicas de Programação
construção durante a execução. Assim, se mais de uma expressão for
verdadeira, uma das instruções correspondentes será não determinis-
ticamente escolhida para a execução. Caso nenhuma expressão seja
verdadeira, haverá um erro em tempo de execução que acarretará o
término do programa.

A semântica dos comandos protegidos é, portanto, difícil de ser


compreendida, se comparada com as demais semânticas de outros
comandos. Uma das alternativas encontradas para melhorar o en-
tendimento da abordagem seletora de Dijkstra (1976) é a adoção de
um fluxograma (Figura 5) cujo objetivo é refletir sobre a dificuldade de
captar a semântica dos comandos protegidos.

Figura 5
Fluxograma de abordagem usada como instrução seletora

Avalie todas as expressões


booleanas

V
Todas são
Erro em tempo de execução
falsas

V
Exatamente uma é
verdadeira

F Execute a instrução
associada Curiosidade
Escolha aleatoriamente uma A seleção de Dijkstra é muito va-
das expressões booleanas liosa quando aplicada à constru-
verdadeiras ção de programas que realizam
a manutenção de interrupções,
sendo que essas apresentam a
Fonte: Adaptada de Dijkstra, 1976 apud Sebesta, 2018, p. 322.
mesma prioridade.

Estruturas de seleção de controle 63


A notação da estrutura de laço, proposta por Dijkstra (1976), pode
ser apresentada da seguinte forma:

do <expressão booleana > -> <instrução>

[ ] <expressão booleana > -> <instrução>

[ ] ...

[ ] <expressão booleana > -> <instrução>

od

Nessa estrutura, a semântica de todas as expressões booleanas é


avaliada em cada iteração. Caso mais de uma expressão seja verdadei-
ra, uma das instruções associadas é não deterministicamente escolhi-
da para ser executada, sendo as expressões novamente avaliadas na
sequência. No entanto, caso todas as expressões sejam falsas, o laço é
finalizado.

Sendo assim, os comandos protegidos de Dijkstra são interessan-


tes, em parte, porque ilustram como a sintaxe e a semântica das instru-
ções podem ter impacto sobre a verificação do programa, e vice-versa.
Vale ressaltar que a verificação do programa é virtualmente impossível
quando as instruções goto são utilizadas, mas ela se torna uma forma
simplificadora quando laços lógicos e seleções, adotados pela lingua-
gem de programação Pascal, são empregados, bem como quando ape-
nas comandos protegidos são usados.

CONSIDERAÇÕES FINAIS
Neste capítulo, uma variedade de seleções e estruturas foi discutida, a
nível de controle. As instruções de controle das linguagens de programa-
ção imperativas são definidas em várias categorias, como seleção, seleção
múltipla, seleção iterativa e desvio incondicional.
Segundo Sebesta (2018, p. 322), “somente as sequências, os laços
lógicos de pré-teste e as seleções são absolutamente necessários para
exprimir computações”. Trata-se de um resultado inicialmente teórico,
amplamente usado para “banir completamente os desvios incondicionais”.
Nesse sentido, tem-se observado que vários são os problemas com a
instrução goto, porém nenhum deles apresenta uma razão teórica para a
sua não utilização. Vários autores têm considerado o uso da goto na saída
prematura de laços de repetição, principalmente em linguagens de progra-
mação que não oferecem esse tipo de instrução de saída. Dentre as que

64 Técnicas de Programação
apresentam saídas para seus laços, pode-se elencar C, C++, Fortran 90,
Java e Perl – essas saídas ocupam o lugar das instruções goto.
Diante das discussões apresentadas em relação ao uso dos desvios
incondicionais, ou goto, entende-se que esses fazem parte do ciclo de vida
da maioria das linguagens de programação até o momento desenvolvidas.
Assim, o ideal é que os cuidados no uso dessas instruções fiquem minimi-
zados ao ensino das disciplinas de programação.
Já em relação aos comandos protegidos de Dijkstra, são definidos como
construções alternativas, com características teóricas passivas, uma vez
que não são abordados como parte de construções de controle de uma
linguagem, além de sua semântica aparecer nas linguagens concorrentes,
como Ada e CSP.

ATIVIDADES
1. O que são estruturas de controle?

2. Para que servem as questões de projeto nas estruturas de seleção?

3. O que é o corpo do laço?

4. Quais são as soluções para os ifs aninhados?

REFERÊNCIAS
DE MELO, A. C. V.; DA SILVA, F. S. C. Princípios de linguagens de programação. São Paulo:
Blucher, 2003.
DIJKSTRA, E. W. A Discipline of Programming. Englewood Cliffs, NJ: Prentice Hall, 1976.
SEBESTA, R. W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman,
2018.

Estruturas de seleção de controle 65


4
Modularização
Na época dos primeiros computadores, a programação
era bastante limitada, se comparada aos dias de hoje. Antes,
os programadores desenvolviam seus códigos com apenas
um único bloco, uma vez que a divisão desses códigos em
mais de um bloco acarretava maior consumo de recursos e,
principalmente, um sistema de gerenciamento de memória.
Vale destacar que as variáveis também eram limitadas e
usadas em várias partes do programa, com o intuito de mini-
mizar a quantidade de memória exigida para sua execução.
Além disso, os programadores precisavam definir um fluxo
mais eficiente de controle, exigindo uma quantidade infinita
de comandos de desvio condicional.
As linguagens de programação modernas, por sua vez,
adotam a modularização para melhor escrever as coleções de
instruções. Ainda, permitem maior reutilização de variáveis,
garantindo vários tipos de economia, como espaço de memó-
ria e tempo de codificação.
Outro fator importante, nesse contexto, é que a imple-
mentação da estratégia “dividir para conquistar” é realizada,
na maioria das linguagens de programação, por modulariza-
ções, pois apoia a resolução de problemas mais complexos,
facilitando o entendimento dos programas e viabilizando o
reuso do código.
Assim, por meio dessa técnica, os programas podem ser
segmentados em módulos e seus dados encapsulados, ou
seja, os dados são agrupados e os processos logicamente re-
lacionados em uma única entidade de computação.

66 Técnicas de Programação
4.1 Fundamentos de subprogramas
Vídeo Subprogramas são muito utilizados quando se pretende dividir pro-
blemas complexos em várias partes mais gerenciáveis e resolvê-las in-
dependentemente. No entanto, para melhor entendimento do conceito
e da aplicação de subprogramas, é necessário entender a abstração,
visto que essa é a base para seu uso.

Desse modo, pode-se dizer que a abstração é um


Glossário
processo importante em qualquer área de conheci-
mento, pois possibilita o raciocínio e a resolução de abstração: amplamente
usada na computação, sua
problemas em fenômenos da realidade, em toda a
definição está relacionada
sua riqueza de detalhes. à facilitação da resolução
de problemas, por meio de
Para Varejão (2004), o conceito de abstração é mecanismos que tornem mais
usado de acordo com duas perspectivas: a primeira simples a sua operação e pro-
corresponde ao lugar em que a linguagem de pro- gramação (VAREJÃO, 2004).

gramação funciona como uma abstração sobre o


hardware; já a segunda, quando a linguagem de pro-
Curiosidade
gramação fornece um conjunto de mecanismos para
Os mecanismos de abstração
o programador criar e representar suas abstrações
fornecidos pelas linguagens de
sobre determinado problema. programação, normalmente,
são classificados como: abstra-
Com o conceito de abstração entendido, pode-se ção de processos e abstração de
definir o que é um subprograma. Para isso, faz-se ne- dados. No primeiro, as abstra-
ções são referentes aos fluxos
cessário entender um pouco sua evolução: os subpro-
de controle do programa; já
gramas foram um dos primeiros avanços para a no segundo, as abstrações são
modularização, pois permitiram dividir um programa sobre as estruturas de dados
do programa.
em vários blocos logicamente relacionados (VAREJÃO,
2004). Por meio dessa divisão, as tarefas poderiam ser
realizadas/implementadas com menor complexidade de execução.
Figura 1
Módulos de Além disso, com o surgimento dos subprogramas, tornou-se
programas
possível evitar que trechos de códigos semelhantes fossem
Alexander Lysenko/Shutterstock

reescritos somente por apresentarem e operarem dados dife-


rentes (MELO; SILVA, 2003). Nesse sentido, os subprogramas
trouxeram ao conceito de modularização vários benefícios,
como o aumento da legibilidade, redigibilidade, modificabili-
dade, reusabilidade, confiabilidade e eficiência de programa-
ção, conceitos apresentados anteriormente.

Modularização 67
A legibilidade aumenta por meio da divisão lógica do programa em
unidades funcionais e das separações do código relacionado à imple-
mentação da abstração. A redigibilidade é aprimorada, uma vez que
vários trechos podem ser usados em diferentes partes do programa,
sem a necessidade de reescrever todas as vezes que forem usados.

Com relação à modificabilidade, os subprogramas possibilitam maio-


res alterações nos módulos implementados, principalmente, porque
estes não implicam diretamente na modificação dos seus programas e
códigos de usuários. Já a reusabilidade é aplicada quando os módulos
são criados e podem ser aplicados em outros códigos que apresentem
as mesmas funcionalidades, garantindo, também, maior confiabilidade,
pois os módulos criados já foram testados em outros momentos.

A eficiência de programação ocorre devido à divisão em códigos/


módulos menores na construção de determinado programa. Dessa for-
ma, a dedicação do programador fica a cargo de cada um dos módulos,
e não da escrita do programa como um todo.

Para Sebesta (2018), um subprograma descreve a interface e as


ações da abstração. Nesse sentido, pode-se afirmar que todos os
subprogramas apresentam as seguintes características:
•• ponto único de início;
•• todo subprograma chamador fica suspenso enquanto o progra-
ma chamado é executado;

Figura 2 •• Ao fim da execução do programa, o controle retorna ao chamador.


Procedimentos e funções
Diante disso, ao se chamar um subprograma, sempre é realizada
ock uma solicitação explícita para a ativação dele, para posterior ini-
e rs t
u tt
Sh
y/ ciação de sua execução, porém não finalização. Muitos auto-
sb
xu

res também denominam e classificam os subprogramas


ne

como procedimentos e funções, isto é, segundo a forma


como são utilizados e abordados em nível de codifica-
ção em uma linguagem de programação.

Sebesta (2018) afirma que procedimento é um


módulo que não produz qualquer valor de saída, po-
dendo ser representado por exemplos como a leitura
de um elemento e a impressão do maior elemento en-
tre os valores lidos. As funções são bastante semelhan-
tes aos procedimentos, porém têm como base funções

68 Técnicas de Programação
matemáticas. Como exemplos de funções, é possível citar: dar o valor
do maior elemento de três elementos ou determinar se um elemento
está dentro de uma faixa de valores aceitáveis.

O subprograma, porém, sendo uma função ou um procedimento, pre-


cisa atender a uma estrutura composta de cabeçalho e perfil de parâmetro.

O cabeçalho é sempre representado na primeira linha da definição


e serve para vários protótipos. Inicialmente, ele especifica a unidade sin-
tática e, posteriormente, atribui um nome a um subprograma, confor-
me o exemplo, a seguir, de subprograma na linguagem Fortran:

SUBROUTINE SOMADORA (parâmetros)

Já na linguagem Ada, por exemplo, esse mesmo subprograma seria


representado da seguinte forma:

procedure somadora (parâmetros)

Como características, o parâmetro apresenta em seu perfil o nú-


mero, a ordem e os tipos formais de parâmetros. Por outro lado, o
protocolo pode ser entendido como um perfil de parâmetro de um
subprograma, mas, se este for uma função, passa a ser representado
por seu tipo de retorno.

4.1.1 Parâmetro
Os parâmetros facilitam o processo de aplicação de dados diferen-
ciados a chamadas distintas de um subprograma (VAREJÃO, 2004). Sem
o uso de parâmetros, a utilidade dos subprogramas se concentra na
divisão de códigos em pequenos trechos.

Assim, ao se utilizar parâmetros em um subprograma, estes sempre


necessitam de um cabeçalho. Os parâmetros disponíveis no cabeçalho
são chamados de formais, pois recebem o nome de variáveis fictícias,
visto que, em alguns casos, estas somente são vinculadas ao armaze-
namento quando o subprograma é chamado. Essa vinculação ocorre
por meio de algumas variáveis do programa.

Vale destacar que todas as chamadas de um subprograma sempre


incluirão o nome da instrução e uma lista de parâmetros formais vin-
culados, denominados reais. Distinguem-se dos parâmetros formais
porque ambos podem ter diferentes restrições em suas formas, além
de aplicações distintas.

Modularização 69
O exemplo de uma função com parâmetro na linguagem de progra-
mação C pode ser descrito na figura a seguir.

Figura 3
Função com parâmetro em linguagem C

int volume (int altura, int largura, int comprimento)


{
Return altura * largura * comprimento;
}
main ( ) {
int a1 = 1, l1 = 2, c1 =3, a2 = 4, c2 = 5, l2 =6;
int v1, v2;
v1 = volume (a1, l1, c1);
v2 = volume (a2, l2, c2);
printf (“v1: %d\nv2: %d\n”, v1, v2);
}

Fonte: Varejão, 2004, p. 151.

No trecho de código apresentado, nota-se a função de nome volume


com os parâmetros altura, largura e comprimento. Essa função tem por
objetivo calcular o volume de um paralelepípedo. Ainda nesse código,
observa-se maior redigibilidade em relação à não utilização de variá-
veis globais. Além disso, as chamadas de volume explicitam os valores
utilizados em cada chamada.

4.2 Métodos de passagem de parâmetros


Vídeo No desenvolvimento de programas que adotam subprogramas, é
necessário que métodos de passagem de parâmetros sejam adotados.
Por meio desses métodos, torna-se possível realizar a transferência de
parâmetros para subprogramas que são chamadores e/ou subprogra-
mas chamados.

Para Sebesta (2018), os parâmetros formais são especificados


tendo em vista três modelos semânticos: os que permitem receber
dados de outros parâmetros; os que podem transferir dados para
outros parâmetros; e os que podem realizar a transferência e o re-
cebimento de outros parâmetros. A esses três modelos semânticos,
respectivamente, dá-se o nome de modo entrada, modo saída e modo
entrada/saída.

Por outro lado, cinco modelos básicos foram desenvolvidos para im-
plementação de passagem de parâmetros, chamados passagem por va-

70 Técnicas de Programação
lor, passagem por resultado, passagem por valor-resultado, passagem por Figura 4
referência e passagem por nome. Passagem de parâmetros
em linguagem de progra-
Denomina-se passagem de parâmetro por mação
valor o momento em que o valor de um
parâmetro real é inicializado e ativa o
seu parâmetro formal correspondente.
A forma como essa ativação acontece
dentro do subprograma pode ser carac-
terizada como uma variável local den-
tro desse módulo, e o modelo semântico
equivalente a esse processo é chamado
de modo entrada.

Normalmente, essa passagem de parâme-


tro é implementada pela transferência de dados Vin
tag
eT
o ne
reais, pois são mais eficientes. Como alternativa de implementação, /Shu
tt erstock

os caminhos de acessos ao valor do parâmetro real no subprograma


chamador poderiam ser implementados, desde que o valor do parâ-
metro estivesse em uma célula com proteção de escrita.

A principal desvantagem do método de implementação de passa-


gem de parâmetro por valor é quando transferências físicas são fei-
tas. O foco é o armazenamento adicional, sendo ele necessário para Atenção
o parâmetro formal no subprograma chamado ou então em alguma Importante destacar que, na
passagem por resultado, um
área fora tanto do subprograma chamador quanto do chamado.
problema de colisão de parâme-
Em contrapartida, a passagem por resultado adota um modelo tros reais pode vir a acontecer
– por exemplo, quando um é
semântico em modo saída. Isso significa que, se no momento da pas-
criado com a chamada sub (p1,
sagem de parâmetro for passado como resultado, nada será trans- p1). Supondo que em sub os
ferido em valor ao subprograma. dois parâmetros formais têm
nomes diferentes e podem ter
Diante disso, o parâmetro formal apresenta o comportamento valores distintos, qualquer um
de uma variável local, mas, antes que o controle seja transferido ao que seja atribuído por último ao
seu parâmetro real correspon-
chamador, seu valor é passado de volta para o parâmetro real do dente irá se tornar o valor de p1
chamador, que geralmente é uma variável (SEBESTA, 2018). (SEBESTA, 2018).

Nesse método de implementação, um problema que pode ocor-


rer é o implementador ter de escolher entre dois tempos diferentes
para avaliar os endereços dos parâmetros reais, isto é, uma avalia-
ção no momento da chamada ou do retorno.

A passagem por valor-resultado utiliza um modelo semântico de


modo entrada/saída. Nesse modelo, existe a transferência de todos os

Modularização 71
valores reais. Alguns autores também definem esse método como uma
combinação entre a implementação de passagem de valor e a passa-
gem de resultado.
Em determinadas bibliografias, a passagem por valor-resultado é
chamada de passagem por cópia, uma vez que o parâmetro real é co-
piado para o parâmetro formal na entrada do subprograma e, depois,
copiado de volta na finalização do subprograma. Assim, as desvanta-
gens da implementação desse método são as mesmas encontradas na
passagem por valor e por resultado, como a exigência de armazena-
mento múltiplo para parâmetros, tempo de cópia de valores e a ordem
em que os parâmetros reais são atribuídos, respectivamente.
A passagem por referência também é considerada um mo-
delo de entrada/saída. No entanto, o que difere da passagem por
valor-resultado é a transferência de um caminho de acesso, por meio
de um endereço, para o subprograma chamado.
Como vantagem, esse método apresenta bastante eficiência em
seu processo de passagem em níveis de tempo e espaço. No entanto,
como desvantagem, o acesso aos parâmetros formais torna-se mais
lento pela existência de mais um nível de endereçamento indireto.
Além disso, somente uma comunicação unidirecional com o subpro-
grama chamado é exigida, fazendo com que mudanças inadvertidas e
errôneas possam ser feitas no parâmetro real.
Pode ocorrer apelido quando parâmetros passados por referência são
usados, tanto entre dois ou mais parâmetros quanto entre um deles e
uma variável não local acessível. O acesso a essas variáveis não locais é
realizado de várias formas, como por declarações externas, por blocos de
dados globais, por módulos externos, por escopo estático e dinâmico etc.
Por fim, porém não menos importante, a passagem por nome
também é um modelo semântico caracterizado como entrada/saída. A
passagem de parâmetro real, contudo, ocorre de modo diferente, pois
existe uma substituição do parâmetro real pelo parâmetro formal em
todas as ocorrências do subprograma.
Nota-se, nesse método, que os parâmetros reais, sempre quando
chamados ao subprograma, são vinculados a valores ou então ende-
reços reais. Como principal vantagem da passagem por nome, tem-se
a flexibilidade proporcionada ao programador. A desvantagem fica
por conta da lentidão do processo em relação aos outros métodos de
passagem de parâmetros.

72 Técnicas de Programação
4.3 Subprogramas sobrecarregados e genéricos
Vídeo Para entender subprogramas sobrecarregados, é necessário com-
preender o conceito de um operador sobrecarregado. Chama-se de
operador sobrecarregado aquele que apresenta vários significados a
um único tipo de dado do operador. Por exemplo, pode-se descrever
o operador de multiplicação em uma linguagem C, que, em deter-
minados momentos, pode ser representado por uma multiplicação
ao ser adicionado a dois operandos de tipos de dados reais ou, em
outro momento, ser adicionado a um tipo de dado inteiro.

Diante disso, para Sebesta (2018), um operador sobrecarregado


sempre terá em sua estrutura um nome único, independentemente
do ambiente em que está referenciado. Cada versão, porém, deve
apresentar um único protocolo, com diferença quanto ao número, à
ordem ou aos tipos de seus parâmetros. Sendo assim, o significado
de uma chamada a um subprograma sobrecarregado é feito pela
lista de seus parâmetros reais.

Vale ressaltar que algumas linguagens de programação, como


Java, C++ e Ada, já incluem subprogramas sobrecarregados prede-
finidos. Em linguagem Ada, as funções de saída apresentam várias
versões por meio do comando PUT e, normalmente, aceitam valores
de inteiros, caracteres e reais em seus parâmetros. Nas linguagens
C++ e Java são permitidas expressões em modo misto, e o tipo de
retorno se torna irrelevante para eliminar a ambiguidade de funções
sobrecarregadas. Essas linguagens também permitem aos seus de-
senvolvedores a escrita de várias versões de subprogramas com o
mesmo nome, porém sem que forneçam o mesmo processo.

Já os subprogramas genéricos são úteis, principalmente, para


a reutilização de software, aumentando a produtividade no de-
senvolvimento de programas. Portanto, com a criação de subpro-
gramas genéricos, torna-se possível minimizar a necessidade de
implementar o mesmo algoritmo em vários tipos de dados. Assim,
os programadores podem criar, por exemplo, um subprograma de
classificação para quatro vetores diferentes somente em termos de
tipo de elemento.

Modularização 73
Para Sebesta (2018), diz-se que um subprograma genérico, também
Glossário
conhecido por polifórmico, apresenta parâmetros com várias formas
polimorfismo paramétrico:
é adotado em subprogramas, de
de ativações. Algumas linguagens de programação, como Ada e C++,
modo que estes possam definir apresentam um polimorfismo paramétrico em tempo de compilação.
seus tipos de dados generica-
mente para suportar qualquer O subprograma genérico é onde as diferentes versões do subpro-
valor sem depender diretamente grama são instanciadas ou construídas pelo compilador mediante soli-
de seu tipo (SEBESTA, 2018).
citação do programa do usuário. Consequentemente, como as versões
dos subprogramas apresentam o mesmo nome, tem-se a impressão
de que um único subprograma pode acessar diferentes tipos em várias
chamadas, conforme ilustra o trecho de código descrito a seguir.

Figura 5
Exemplo de parâmetros genéricos

generic
type TIPO_INDICE is (< >);
type TIPO_ELEMENTO is private;
type VECTOR is array (TIPO_INTEIRO range < >) of
TIPO_ELEMENTO;
procedure ORD_GENERICA (LISTA : in out VECTOR);
procedure ORD_GENERICA (LISTA : in out VECTOR) is
TEMP : TIPO_ELEMENTO;
begin
for TOPO in LISTA’FIRST .. TIPO_
INDICE’PRED(LISTA’LAST) loop
for BASE in TIPO_INDICE’SUCC(TOPO) ..
LISTA’LAST loop
Saiba mais if LISTA(TOPO) > LISTA(BASE) then
TEMP := LISTA(TOPO);
Os subprogramas genéricos de
LISTA(TOPO) :+ LISTA(BASE);
linguagem Ada e as funções da
linguagem C++ são versões LISTA(BASE) := TEMP;
mais simplificadas de subpro- end if
gramas cujos tipos de parâme- end loop; - for BASE ...
tros formais são vinculados de end loop; - for T|OPO...
modo dinâmico aos tipos reais end ORD_GENERICA;
em uma chamada. Já para saber
como funcionam nas linguagens Fonte: Sebesta, 2018, p. 359.
Smalltalk e Java, sugerimos
ler o capítulo 12, da 10. edição O código da Figura 5 demonstra um procedimento de três parâme-
de Conceitos de linguagens de tros genéricos, desenvolvidos na linguagem Ada, que possibilitam ao
programação, de Robert Sebesta, subprograma atribuir um vetor genérico ao parâmetro. Esse exemplo
publicado em 2015 pela editora
Bookman. mostra um processo de classificação de trocas criado para funcionar
em qualquer vetor com elementos de tipos de dados numéricos.

74 Técnicas de Programação
Essa classificação genérica nada mais é do que um modelo para um
procedimento. Nenhum código é gerado para ele pelo compilador, e
ele não tem nenhum efeito sobre um programa, a menos que seja ins-
tanciado para algum tipo.

Em contrapartida, as funções genéricas em linguagem C++ têm


o nome descritivo de funções do modelo. A função modelo é defi-
nida por:

template <parâmetros>

Onde cada parâmetro pode apresentar cada uma das seguintes


formas:

class identificador

typename identificador

Sendo assim, um exemplo do uso de uma função modelo pode ser:

template <class Tipo>

tipo(Primeiro tipo, Segundo tipo) {

return primeiro > segundo ? primeiro : segundo;

Nesse exemplo, tipo é o parâmetro que especifica o tipo de dados


sobre o qual a função será operada. Essa função modelo pode ser ins-
tanciada para qualquer tipo cujo operador > seja definido.

Para Sebesta (2018), a função modelo do C++ é instanciada impli-


citamente quando a função é nomeada em uma chamada ou quando
seu endereço é tomado com o operador &.

4.4 Semântica de chamadas e retornos


Vídeo Sempre que subprogramas são usados no desenvolvimento de um
programa, é necessário que operações de chamada e de retorno se-
jam feitas a esses subprogramas. Essas chamadas são denominadas
de ligação ou linkagem de subprograma, isto é, qualquer método de
implementação para um subprograma deve ter como base a semân-
tica de sua ligação.

Modularização 75
Uma chamada a subprograma em uma linguagem típica tem nu-
merosa ações associadas a ela. A chamada deve incluir o meca-
nismo para quais métodos de passagem de parâmetros usados.
Se as variáveis locais não forem estáticas, a chamada deverá
fazer com que seja alocado armazenamento para as variáveis
declaradas no subprograma chamado e vinculá-las a ele. Deve-
rá salvar o status de execução da unidade de programa chama-
dora e organizar-se para transferir o controle para o código do
subprograma e assegurar que esse controle possa retornar para
o lugar apropriado quando a execução do subprograma for con-
cluída. Por fim, a chamada deverá fazer com que algum mecanis-
mo seja criado para fornecer acesso a variáveis não locais visíveis
ao subprograma chamado. (SEBESTA, 2018, p. 376)

Essa implementação de chamadas e retornos pode ser aplicada a qual-


quer linguagem de programação. Dependendo da linguagem, determina-
das caraterísticas precisam ser evidenciadas, como ocorre em Fortran 77.

Segundo Sebesta (2018), a semântica de uma chamada a um


subprograma necessita que as seguintes ações sejam cumpridas:

1 2 3 4
Salvar a Executar o Passar o Transferir o
execução da processo de endereço de controle para o
unidade de passagem de retorno para o chamado
programa atual parâmetros chamado

Por sua vez, o retorno do subprograma, ainda nessa linguagem, ne-


cessita de ações também descritas por Sebesta (2018, p. 377):
1) Se forem usados parâmetros passados por resultados, os
valores atuais desses parâmetros serão transferidos para os
parâmetros reais correspondentes; 2) Se o subprograma for
uma função, o valor funcional será transferido para um lugar
acessível ao chamador; 3) O status de execução do chamador
será restabelecido; 4) O controle será transferido novamente
para o chamador.

Logo, entende-se que as ações de chamada e de retorno necessitam


de armazenamento para informação do status sobre o chamador, parâ-
metros, endereço de retorno e valor funcional para subprograma função.

Além da linguagem Fortran, também é possível a implementação da


semântica de subprogramas em linguagens semelhantes ao Algol. No
entanto, nessas implementações, o escopo da linguagem se caracteriza

76 Técnicas de Programação
como estático – foca as operações de chamada e de retorno em situa-
ções mais complexas.

Essas situações mais complexas também podem ser chamadas


de registros de ativações mais complexos, que possibilitam a ligação de
subprogramas pelos seguintes motivos: uma vez que os parâmetros Glossário
podem ser passados por dois métodos diferentes, além das variáveis recursão: também denominada
poderem ser alocadas de modo dinâmico, e pela recursão permitir ati- recursividade, caracteriza-se
como uma função que chama
vações simultâneas múltiplas de um subprograma.
a si mesma. A recursão, por
O formato de um registro de ativação para um subprograma em exemplo, sempre é muito usada
na programação de um número
linguagens de programação que adotam escopo estático é realizado fatorial, pois permite que o
em tempo de compilação. Em algumas linguagens, como Pascal, os ta- número chame o próximo dentro
manhos dos dados locais são fixos, fazendo com que o tamanho de da mesma função.

seus registros também seja mais fácil de ser conhecido. No entanto, em


linguagens em que o tamanho do vetor local pode depender do valor
de um parâmetro real, isso já não ocorre. Um registro de ativação na
linguagem Algol é ilustrado na figura a seguir.

Figura 6
Registro de ativação na linguagem de programação assemelhada ao Algol

Variáveis locais

Parâmetros

Vínculo dinâmico

Vínculo estático
Topo da pilha
Endereço de retorno

Fonte: Sebesta, 2018, p. 380.

Na Figura 6, o endereço de retorno é composto de um ponteiro para


o código do chamador e de um deslocamento nesse segmento de có-
digo da instrução seguinte à chamada. Já o vínculo estático, também
denominado de ponteiro de escopo estático, é aquele que aponta para
a base da instância do registro. O vínculo dinâmico, por sua vez, é um
ponteiro para o topo da instância do registro do ponteiro chamador.

Os parâmetros reais no registro de ativação são os valores, ou então os


endereços, fornecidos pelo chamador. Por fim, as variáveis locais são vincu-
ladas ao armazenamento dentro de uma instância do registro de ativação.

Modularização 77
Nesse sentido, a ativação de um procedimento precisa da criação
dinâmica de uma instância do registro de ativação. Para isso, o formato
do registro de ativação deve ser fixado durante a compilação, mesmo
que seu tamanho dependa da chamada em algumas.

Melo e Silva (2003) dizem que é razoável criar instâncias desses re-
gistros de ativação em uma pilha, uma vez que a semântica das chama-
das e os retornos especificam que o subprograma chamado por último
será o primeiro concluído.

CONSIDERAÇÕES FINAIS
Em todo e qualquer processo de desenvolvimento de software/pro-
grama existe a necessidade de compreensão do processo de abstração.
Isso porque, por meio dele, torna-se possível descrever as ações aptas a
serem representadas e implementadas.
Nesse sentido, os subprogramas surgiram com o objetivo de melhorar
o processo produtivo da programação, pois tratam do conceito “dividir
para conquistar”, que possibilita dividir problemas complexos em proble-
mas menores e colocá-los em execução.
Estudou-se também que, com o surgimento da modularização e uti-
lização de subprogramas, vários benefícios se apresentaram aos desen-
volvedores, dentre eles a reusabilidade e a eficiência da programação. A
reusabilidade possibilita que módulos/subprogramas já desenvolvidos se-
jam aproveitados e adaptados a novos programas, aumentando a produ-
tividade dos programadores, uma vez que minimiza o número de testes e
correções de trechos de códigos.
Além disso, destacou-se que os subprogramas podem ser definidos
como funções ou procedimentos, sendo necessário que atendam a uma
estrutura composta por cabeçalho e perfil de parâmetro. Analisou-se,
também, que os subprogramas podem ser sobrecarregados.

ATIVIDADES
1. Qual a importância dos subprogramas no desenvolvimento de um
programa?

2. Quais são os benefícios que a modularização traz aos programadores?

3. De que modo a abstração é utilizada no contexto dos subprogramas?

4. O que é passagem de parâmetros?

78 Técnicas de Programação
REFERÊNCIAS
MELO, A. C. V. de; SILVA, F. S. C. da. Princípios de linguagens de programação. São Paulo:
Blucher, 2003.
SEBESTA, R. W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman,
2018.
VAREJÃO, F. M. Linguagem de programação: conceitos e técnicas. Rio de Janeiro: Elsevier,
2004.

Modularização 79
5
Orientação a objetos
A orientação a objetos (OO) é um paradigma relativamente
antigo, utilizado desde a década de 1960. No entanto, tornou-se
mais conhecido e empregado no desenvolvimento de diversas
aplicações com o surgimento da linguagem de programação
Java.
O paradigma OO apresenta um enfoque voltado a melho-
rar e gerenciar a complexidade de um sistema. Na orientação a
objetos, a visão do mundo real pode ser estabelecida por meio
de vários objetos autônomos, concorrentes e com interação en-
tre si. Para isso, ao se desenvolver um programa no contexto
da orientação a objetos, é necessário que informações sobre o
problema sejam vistas de modo mais abstrato, isto é, pela ideia
de abstração.
Além desse conceito em relação às complexidades do siste-
ma, é importante prever quais tipos de dados serão definidos
para melhor se adequarem ao paradigma e, principalmente, às
características evidentes de reuso.
Neste capítulo, as implementações da orientação a objetos
são conceituadas, e os processos das metodologias top down
e bottom up no desenvolvimento de programas também são
apresentados.

5.1 Conceitos de abstração


Vídeo O conceito de abstração é bastante usado em linguagens de progra-
mação orientadas a objetos, pois se caracteriza como a forma de entender
problemas tidos como complexos. O entendimento destes é alcançado
por meio de sua divisão em pequenos problemas, de modo a solucioná-
-los individualmente até que o conjunto inteiro possa ser resolvido.

80 Técnicas de Programação
Vale ressaltar que a abstração possibilita a determinadas partes do
problema apresentarem menor ou maior peso, fazendo com que al-
guns detalhes sejam desconsiderados, em certos momentos, para que
outros possam ser ressaltados (CORREIA; TAFNER, 2006).

Ainda, o termo abstração, em qualquer linguagem de programação


e/ou desenvolvimento de sistemas, restringe-se a retratar apenas o
que será apresentado no problema. Essa representação, normalmen-
te, é feita por meio de objetos definidos como representações do mundo
real ou do mundo físico por todos conhecido. Nesse sentido, os objetos
sempre exibirão as características mais relevantes do problema em
questão. Qualquer pessoa, por exemplo, tem um atributo para a cor Glossário
dos olhos, mas, em um sistema de cadastro de fornecedores, essa in-
características: termo usado
formação não é relevante. por muitos autores para descre-
ver os atributos de um objeto.
Ao pensar em pessoa como objeto, pode-se observar que há Sendo assim, ao usar o conceito
vários atributos ou várias características particulares a serem de objetos, é possível encontrar
considerados, como nome, idade, data de nascimento, número de atributos ou características.

documentos, entre outros.

Para Sebesta (2018), a abstração pode ser definida como a visuali-


zação ou representação de uma entidade que inclui somente os atri-
butos de importância em um contexto particular. Em outras palavras,
pode-se dizer que a abstração é adotada para minimizar a complexida-
de do desenvolvimento dos sistemas, uma vez que seu principal pro-
pósito é a simplificação do processo. Em linguagens de programação
contemporâneas, a abstração é classificada em dois tipos distintos: de
processos e de dados. Figura 1
Exemplo de objeto: pessoa
PHOTOCREO Michal Bednarek/Shutterstock

Orientação a objetos 81
A abstração de processos é um dos conceitos mais antigos no pro-
jeto de uma linguagem de programação. Todos os subprogramas são
abstrações de processos, pois oferecem formas de especificar o que
determinado processo deve realizar, porém sem apresentar maiores
detalhes de como isso deverá ser feito.

Quando o programa tem como objetivo realizar a classificação de


um vetor de objetos de dados numéricos de algum tipo, por exem-
plo, geralmente, usa-se um subprograma, sendo necessário que uma
instrução, como ordena_inteiro(lista, comp_lista), seja
atribuída. A essa chamada dá-se o nome de abstração de processos
de classificação real, ou seja, ela torna-se independente do algoritmo
implementado no subprograma chamado (SEBESTA, 2018).

A abstração de processos é fundamental para a abstração dos


detalhes do algoritmo a ser implementado em subprogramas, uma
vez que, com a sua utilização, o entendimento, a criação e a leitu-
ra de uma quantidade muito grande de linhas de código tornam-se
mais viáveis.

No entanto, a abstração de dados tem o mesmo seguimento da


de processos. Para que os processos possam ser realizados, faz-se ne-
cessário que a abstração de dados, por meio de suas operações, seja
definida.

Para Varejão (2004, p. 146), as abstrações de dados “permitem ver


uma determinada combinação de dados como sendo um novo dado
ou tipo de dados”. A abstração de processos, por sua vez, possibilitaria
uma combinação de comandos e expressões como um novo comando
ou uma nova expressão.

Resumidamente, as abstrações de processos são referentes aos flu-


xos de controle do programa, enquanto as abstrações de dados são
sobre as estruturas de dados do programa.

5.2 Tipos abstratos de dados e encapsulamento


Vídeo Para que os tipos abstratos de dados possam ser melhor en-
tendidos, faz-se necessário, inicialmente, compreender o que é um
encapsulamento. Esse é um precursor e um mecanismo de suporte
para os tipos abstratos de dados.

82 Técnicas de Programação
Assim, o encapsulamento é como um dos grandes trunfos da pro-
gramação orientada a objetos, pois disponibiliza o objeto com toda a
sua funcionalidade, sem a necessidade de entender internamente seu
funcionamento, muito menos como os dados precisam ser armaze-
nados ou recuperados. Além disso, o encapsulamento possibilita que
modificações sejam feitas internamente no objeto, acrescentando
métodos, sem afetar os demais componentes do sistema que utilizam Glossário
esse mesmo objeto. métodos: são procedimentos
ou funções que realizam as
Em determinadas situações, o encapsulamento pode ser colocado ações próprias do objeto, ou seja,
em bibliotecas e disponibilizado para outros programas que não sejam representam as ações que os
objetos podem executar. É por
os mesmos para os quais foram escritos. Muitas linguagens de progra-
meio dos métodos que os obje-
mação oferecem a capacidade de reunir coleções de subprogramas, tos se manifestam e interagem
tipos de dados e unidades que podem ser compilados separadamente, com outros objetos.
significando que suas informações de interfaces são salvas pelo compi-
lador e, quando usadas por outra unidade, servem para verificação do
tipo de interface (SEBESTA, 2018).

Entendido o conceito de encapsulamento, convém pensar em tipos Curiosidade


de dados abstratos que podem ser definidos como um encapsulamen- A abstração de dados tem como
to que inclui somente a representação de dados de um tipo específico vantagem tornar programas
complexos mais manejáveis,
e os subprogramas que fornecem as operações para ele. pois é possível criar uma
Os detalhes de qualquer operação podem ser determinados por metodologia de projeto de
programa diferente, assim como
meio do controle de acesso, sendo que informações desnecessárias é permitida a disponibilidade de
podem ser ocultadas das unidades fora do encapsulamento utiliza- abstração de dados.
do. Para Sebesta (2018), as unidades de programa que adotam dados
abstratos podem declarar variáveis desse tipo, não obstante a repre-
Figura 2
sentação real estar oculta delas. Assim, chama-se uma instância de um
Tipos de dados abstratos
tipo de dado abstrato de objeto.

A abstração de dados pode usar, na pro-


gramação orientada a objetos, a vírgula flu-
tuante como um tipo de dado abstrato ou
para apresentar tipos de dados abstratos
definidos pelo usuário. O conceito de vír-
gula flutuante está presente na maioria
das linguagens de programação, que a in-
clui ou considera um tipo de dado abstrato.
Ela é concebida para criar variáveis a todos os da-
dos reais e para fornecer um conjunto de operações ck
er sto
utt
aritméticas de manipulação de objetos. Mocca
/Sh
white

Orientação a objetos 83
Já em linguagens de alto nível, os tipos de vírgula flutuante ado-
tam o conceito de abstração de dados como uma ocultação da in-
formação, ou seja, o formato real do valor de dados em uma célula
de memória de vírgulas flutuantes é oculto do usuário. E somente
as operações disponíveis são as oferecidas pela linguagem, de modo
que o usuário não tem permissão para criar novas operações sobre
os tipos de dados.

Em contrapartida, os tipos de dados abstratos definidos pelo


usuário apresentam as mesmas características do tipo de vírgula
flutuante, como:

Permite às unidades
de programa Permite um conjunto
declararem suas de operações
variáveis, porém que manipulam
oculta a sua objetos do tipo.
representação.

Fonte: Sebesta, 2018.

Diante dessas características, torna-se possível definir um tipo


abstrato de dados, no contexto de tipos definidos por usuários. Para
isso, duas condições precisam ser respeitadas, conforme explica
Sebesta (2018, p. 413).
A representação ou definição do tipo e as operações sobre
os objetos do tipo estão contidas em uma única unidade
sintática. Outras unidades de programa podem ter permis-
são para criar variáveis do tipo definido. A representação
de objetos do tipo não é visível pelas unidades de programa
que usam o tipo, de modo que as únicas operações diretas
possíveis sobre os objetos são aquelas oferecidas na defini-
ção do tipo.

Unidades de programa que usam um tipo de dados abstrato espe-


cífico são denominadas de clientes desse tipo. As vantagens de empa-
cotamento da representação e das operações em uma única unidade
sintática são as mesmas usadas no encapsulamento.

84 Técnicas de Programação
Além disso, o ocultamento das informa-
ções é importante para o aumento da con-
fiabilidade, uma vez que os clientes podem
mudar qualquer representação subjacente de
objetos de maneira direta, permitindo maior integridade
dos respectivos objetos.

Para melhor entendimento dos tipos de dados abstratos, veja


o exemplo de construção de uma pilha que contém as operações
ilustradas no Quadro 1.
Jirsak/Shutterstock

Quadro 1
Exemplo de um tipo de dados abstrato Figura 3
Ocultamento de
informações
Operações Descrição
Cria (pilha) Permite a criação e inicialização de um objeto na pilha.
Destrói (pilha) Possibilita deslocar o armazenamento da pilha.
Função que retorna true se a pilha estiver vazia e false
Vazia (pilha)
se estiver cheia.
Empurra um determinado elemento para uma pilha es-
Empilha (pilha, elemento)
pecificada.
Desempilha (pilha) Remove o elemento do topo da pilha especificada.
Retorna uma cópia do elemento do topo da pilha es-
Topo (pilha)
pecificada.

Fonte: Sebesta, 2018, p. 414.

Em determinados projetos de tipos de dados abstratos, as opera-


ções de criar e destruir não são adotadas, isto é, simplesmente são
definidas variáveis de determinado tipo de dado abstrato que possa
criar a estrutura de dados, bem como inicializá-la. Um exemplo é um
cliente do tipo pilha que poderia ter um conjunto de instruções de có-
digo, como o seguinte:

....

cria(pilha);

empilha(pilha, nome1);

empilha(pilha, nome2);

if (! Vazia (pilha))

temp = topo (pilha);

...

Orientação a objetos 85
Nesse trecho de código, nota-se que a pilha foi criada e, na sequên-
cia, foram adicionados ou empilhados nome1 e nome2. Posteriormente,
é verificado, por meio do condicional if, se a pilha está cheia; caso ne-
gativo, a variável temp é alocada ao topo da pilha para que as inserções
possam ser realizadas desse ponto em diante.

Assim, sempre que se usa a abstração de dados, é permitido aos


programas definir tipos de dados com as características e com o com-
portamento de tipos embutidos.

Além do encapsulamento, outros conceitos, como classe e herança,


são fundamentais na orientação de objetos. Diante disso, uma classe é
definida como a representação dos dados (denominados de atributos)
e um conjunto de operações (chamados de métodos) (VAREJÃO, 2004),
conforme ilustrado no exemplo a seguir.
Quadro 2
Exemplo de uma classe de nome Pessoa

Pessoa

Nome: string;
Idade: inteiro;

Cadastrar()

Fonte: Elaborado pela autora.

Já a herança, na orientação a objetos, refere-se àquilo que se


herda ou que se transmite. Assim, entende-se que uma classe pode
herdar características, métodos e atributos de outras classes. Sob a
ótica da OO, a herança constitui um mecanismo muito inteligente
de aproveitamento de código, pois os objetos podem compartilhar
informações.

5.3 Implementação de construções


Vídeo orientadas a objetos
As construções de implementações orientadas a objetos estão di-
retamente relacionadas com o projeto dos tipos abstratos de dados.
Elas devem, ainda, considerar questões como: a facilidade de definição
dos tipos abstratos na linguagem de programação – uma vez que esta
precisa oferecer uma unidade sintática para encapsular a definição do
tipo – e o subprograma das operações de abstração.

86 Técnicas de Programação
Além disso, outro ponto a ser considerado se refere à visibilidade
dada aos clientes em relação ao nome do tipo e aos cabeçalhos de
subprograma de abstração. Embora o nome do tipo necessite de vi-
sibilidade externa, sua definição sempre precisa ser oculta. O mesmo
ocorre com as definições dos subprogramas, em que os cabeçalhos
estão visíveis, porém os corpos (operações) ocultos.

Vale ressaltar que a maioria das linguagens de programação exi-


ge operações de tipos de dados abstratos, porém estas não são uni-
versais e precisam ser fornecidas pelos projetistas do tipo. Sebesta
(2018) cita os iteradores, os construtores e os destruidores como
sendo essas operações. Os primeiros se referem a construções de
laço de controle, enquanto os segundos são usados para inicializar
partes dos objetos recém-criados. Por sua vez, os últimos são adota-
dos para reaver o armazenamento do nome, que pode ser utilizado
por partes de objetos de tipos de dados abstratos.

Dentre as principais questões de projeto, convém citar as espécies


de tipos, que podem ser abstratos e restritos, e a possibilidade de
parametrização entre os tipos de dados abstratos. Por meio desta, de-
terminado tipo de dado será criado e usado por vários subprogramas,
independentemente do seu tipo escalar.

Já em relação à implementação de construções orientadas a


objetos, existem, no mínimo, duas partes de suporte interessantes,
denominadas de estruturas de armazenamento para variáveis de instân-
cia e vinculações dinâmicas de mensagens de métodos.

A primeira, dependendo da linguagem, é definida como uma


extensão de estruturas de registros, como ocorre com as classes da
linguagem C++. No caso da classe, portanto, todos os membros e
a herança são privados, por exemplo, padrão, diferentemente dos
registros.

A estrutura de um registro de instância da classe (RIC) é estática


e construída no processo de compilação, utilizada como um mode-
lo para criar instâncias da classe. Dessa forma, qualquer subclasse
pode, simplesmente, estender o RIC da sua classe-pai adicionando as
suas novas variáveis de instâncias.

Nesse sentido, por se tratar de uma estrutura estática, todos os


acessos às variáveis de instância podem ser realizados por meio de
um registro, usando apenas deslocamento de constantes a partir do

Orientação a objetos 87
início do RIC. Isso faz com que todos os acessos sejam mais eficientes
em relação aos seus campos e registros.

Por sua vez, a segunda não precisa estar envolvida no RIC da-
quela classe. Os métodos que foram vinculados dinamicamente, no
entanto, devem ter entradas para essas estruturas. Como exem-
plo de entrada, poderia ser utilizado um ponteiro para o código
do método, definido no momento de sua criação. Essa abordagem
apresenta como desvantagem o fato de que toda instância precisa
armazenar ponteiros para seus respectivos métodos dinamicamen-
te vinculados.

Para Sebesta (2018), a lista de métodos dinamicamente vincula-


dos, que podem ser chamados de instâncias de uma classe, é a mes-
ma para todas as instâncias dessa classe, fazendo com que a lista de
métodos seja chamada apenas uma única vez. Dessa forma, o RIC
precisa apenas de um ponteiro para essa lista ativá-lo, de modo a lo-
calizar os métodos chamados. A essa estrutura de armazenamento
da lista dá-se o nome de tabela de método virtual (VMT).

Observe o trecho de código a seguir, em que se presume a vincu-


lação dinâmica de todos os métodos, segundo Sebesta (2018, p. 478):

class Pequena {

public int a, b, c;

public void desenhar () { … }

class Grande extends Pequena {

public int d, e;

public void desenhar () { … }

public void examiner () { … }

Nesse trecho de código, a classe Pequena é criada e instanciada


para a classe Grande. A Figura 4 ilustra como os RICs para as duas
classes estão relacionados juntamente com seus VMTs.

88 Técnicas de Programação
Figura 4
Registros de instância de classe e tabelas de métodos virtuais

Registro de b
instância de classe
para Pequena c

VMT desenhar VMT para Pequena

Registro de b
instância de classe
para Grande c

VMT desenhar
VMT para Grande

d examinar

Fonte: Adaptado de Sebesta, 2018, p. 479.

Entende-se, dessa forma, que as variáveis de uma classe an-


cestral sempre referenciam o RIC do objeto do tipo correto, cuja
obtenção da versão correta de um método vinculado dinamicamen-
te está garantida.

5.4 Metodologias de desenvolvimento


Vídeo top down e bottom up
No desenvolvimento de um programa, determinadas metodologias
podem ser usadas para auxiliar os projetistas durante fases específicas.
Dentre essas metodologias, encontram-se a top down e a bottom up,
sendo a primeira baseada nas funcionalidades dos programas e a se-
gunda orientada aos dados.

Orientação a objetos 89
A programação top down adota, em sua abordagem de desenvolvi-
mento, o processo de decomposição de problemas complexos, ou mui-
to abrangentes, em problemas menores e mais específicos, mais fáceis
de serem entendidos.

Nesse contexto, pode-se dizer que a modularização e os subpro-


gramas são exemplos da aplicação dessa metodologia de desenvolvi-
mento, independentemente do paradigma de programação escolhido.
Havendo um problema complexo, portanto, ele é dividido em peque-
nas partes para que possa ser solucionado e, posteriormente, integra-
do como um todo.

Assim, essa técnica, conforme observado na figura a seguir, pode


ser várias vezes aplicada hierarquicamente ou por meio de uma árvore
de tarefas, na qual a raiz representa a tarefa inicial e as folhas retratam
as tarefas mais simples ou, então, os diretórios mais profundos dessa
hierarquia.
Figura 5
Ilustração de tarefas na metodologia top down

Problema inicial
Tarefas mais
complexas e
genéricas

Tarefas mais
simples e
específicas

Fonte: Adaptado de Varejão, 2004.

Nota-se, na Figura 5, que a decomposição do problema em partes


Glossário
menores é definida com os mecanismos de iteração e com o escopo cla-
escopo: no desenvolvimento de ros. Assim, tem-se tarefas genéricas/complexas em tarefas específicas/
um programa, é a delimita-
ção dada ao problema a ser simples.
resolvido, ou seja, somente são Vale ressaltar que, quando se trata de uma abordagem top down, a
consideradas as informações
relevantes e necessárias ao base inicia em problemas mais complexos, os quais exigem um conjun-
problema em questão. to de passos para serem solucionados, tais como: análise do problema,
especificação, codificação, teste e refinamento, geração e manutenção
da documentação. A análise do problema trata do entendimento das
funcionalidades dele, enquanto a especificação aborda a definição de

90 Técnicas de Programação
estruturas de dados e de algoritmos adequados para que códigos-fonte
possam ser implementados.

Analogicamente, nessa abordagem, a codificação de um programa


se descreve como um procedimento que nomeia todas as principais
funções necessárias para, mais tarde, junto com a sua equipe, o pro-
gramador olhar os requisitos e repetir o processo. Essas sub-rotinas
compartimentadas, eventualmente, realizarão ações tão simples que
podem ser fácil e concisamente codificadas.

Quando todas as suas diversas sub-rotinas forem codificadas, o pro-


grama está pronto para o teste. Ao definir como o aplicativo virá junto a
um nível elevado, o trabalho de nível inferior pode ser autossuficiente;
ao definir como as abstrações de nível mais baixo são esperadas para
integrar as de nível superior, as interfaces se tornam claras.

Como vantagens do uso da metodologia top down, pode-se elencar


a facilidade de uso na fase inicial do projeto, além de, geralmente, ser
mais rápido de ser informado ao cliente e bastante útil para enten-
der o interesse deste em relação ao que está sendo desenvolvido. Por
fim, essa metodologia pode ser usada quando o projeto não apresenta
muitos detalhamentos.

No entanto, como desvantagens, há a necessidade de experiência


anterior para melhor uso da abordagem, a falta de pessoas especiali-
Figura 6
zadas e conhecedoras do método para usá-lo e a possibilidade de um Metodologia bottom up
grande risco na estimativa de custos de determinado projeto.

Diferentemente, a abordagem bottom up identifica, em um pro-

ColdSnow/Shutterstock
blema complexo, tarefas definidas e com formas reconhecidas como
imprescindíveis ao desenvolvimento. Sendo assim, após sua imple-
mentação, essas partes são reunidas pelo programador para a obten-
ção da solução do problema mais complexo. Assim, pode-se dizer
que tal abordagem apresenta maior precisão e comprometimento
da equipe, levando a dados detalhados do projeto e permitindo
melhor monitoramento e controle.

Por sua vez, entre as desvantagens da metodologia


bottom up, há maior esforço, custo e recurso na esti-
mativa do desenvolvimento, como, também, a ne-
cessidade de que o projeto esteja bem definido e
entendido.

Orientação a objetos 91
De modo geral, é importante ressaltar que a elaboração de um pro-
grama poderá adotar uma abordagem mista, top down e bottom up.

CONSIDERAÇÕES FINAIS
O conceito de orientação a objetos teve sua origem difundida pela
linguagem Simula 67, mas somente obteve maior repercussão com o
surgimento da linguagem Smalltalk, na década de 1980. Muitos autores
consideravam essa linguagem totalmente orientada a objetos, uma vez
que apresentava, entre suas características e seus recursos-chave, os
conceitos de tipos de dados abstratos, herança e um tipo particular de
vinculação dinâmica.
Dessa forma, as definições de abstração de dados foram inseridas no
desenvolvimento de programas com o objetivo de minimizar a comple-
xidade deles. Isto é, por meio da abstração, tornava-se possível dividir o
programa em partes menores, a fim de minimizar a dificuldade de co-
dificação, e, ao final, integrá-lo novamente. Com base nos conceitos de
abstração, os tipos de dados abstratos passaram a ser muito utilizados
por todos os projetistas, de modo a serem projetados para todas as lin-
guagens e tornarem-se cada vez mais seguros e confiáveis.
Relacionado com os conceitos de OO, há, também, o encapsulamento.
Ele possibilita a inclusão de uma quantidade de tipos de dados de objetos
a determinadas entidades, de modo que o programador consegue orga-
nizar e acessar os métodos ou as operações das referidas classes.
Os dois principais recursos dos tipos de dados abstratos são o em-
pacotamento de objetos de dados, com suas operações associadas, e a
ocultação de informação. Uma linguagem de programação pode suportar
tipos de dados abstratos diretamente ou, então, simulá-los com encapsu-
lamentos mais genéricos.
Por fim, as implementações das construções orientadas a objetos são
estruturas baseadas em duas abordagens denominadas de armazena-
mento de dados de instâncias e vinculação dinâmica de mensagens e métodos.
Diante disso, conclui-se que as técnicas de programação, independen-
temente do paradigma adotado na resolução de um programa, precisam
respeitar sintaxes de linguagens e estruturas na utilização de comandos
para melhor desempenho e produtividade do código-fonte.

92 Técnicas de Programação
ATIVIDADES
1. O que são dados abstratos?

2. Quais são os dois tipos de abstração de dados?

3. Quais as principais vantagens das linguagens orientadas a objetos?

4. O que é o encapsulamento e qual a sua funcionalidade na orientação


a objetos?

REFERÊNCIAS
CORREIA, C. H.; TAFNER, M. A. Análise Orientada a Objetos. 2. ed. São Paulo: Visual Books,
2006.
SEBESTA, R. W. Conceitos de linguagens de programação. 10. ed. Porto Alegre: Bookman,
2018.
VAREJÃO, F. M. Linguagem de programação: conceitos e técnicas. Rio de Janeiro: Elsevier,
2004.

Orientação a objetos 93
GABARITO
1 Introdução a linguagens de programação
1. As linguagens de programação são fundamentais para o
desenvolvimento de programas, pois, através delas, torna-se
possível realizar a comunicação entre o hardware da máquina e as
instruções escritas pelo programador. Além disso, permitem auxiliar
no desenvolvimento de várias competências e habilidades dos
programadores em relação ao raciocínio lógico, o pensamento mais
analítico etc.

2. Várias são as razões para se estudar as linguagens de programação,


mas é possível destacar: a capacidade de desenvolver soluções
computacionais; habilidades no estudo e no uso de uma linguagem de
programação; melhor entendimento da escolha de aplicabilidade de
linguagens de programação etc.

3. O paradigma imperativo é bastante usado na atualidade por suas


linguagens de programação estruturada, orientada a objetos e
concorrente. Esse paradigma é responsável por representar como o
computador deve realizar uma tarefa. No paradigma declarativo, os
computadores são as especificações do que são essas tarefas. Dentro
desse paradigma, estão os paradigmas lógico e funcional.

4. A grande maioria dos programas desenvolvidos em alguma linguagem


de programação necessita ser traduzida para uma linguagem de
máquina e, somente então, ser executada. Essa tradução é realizada
através dos métodos de implementação chamados de: compilação,
interpretação pura e híbridos.

2 Desenvolvendo um programa
1. Em qualquer linguagem de programação, o entendimento da sintaxe
é importante, primeiro, porque é por meio dela que se torna possível
a legibilidade de um programa por parte de seus desenvolvedores,
segundo, pelo fato de o compilador entender e apontar os erros
existentes no código-fonte.

2. Nomes ou variáveis em uma linguagem de programação são usados


para permitir que determinados valores possam ser alocados na

94 Técnicas de Programação
memória do computador e, principalmente, processados durante a
execução do programa.

3. Os tipos primitivos de dados são classificados como inteiros, que


permitem a declaração de variáveis que armazenem valores inteiros.
São eles: inteiro, caractere, booleano, decimal, ponto flutuante,
enumerado e intervalo inteiro. O que diferencia um tipo do outro é a
faixa de valores por eles representada.

4. A precedência de operadores é importante, pois, por meio dela, é


possível, ao programador e computador, avaliar a ordem em que as
operações entre os operandos serão executadas.

3 Estruturas de seleção de controle


1. As estruturas de controle são usadas nas linguagens de programação
para ampliar a possibilidade dos programadores na escrita de
códigos, uma vez que por meio delas torna-se possível repetir trechos
de códigos em uma quantidade de vezes determinada ou, então,
estabelecida pelo usuário. Além disso, essas estruturas permitem que
os códigos não sejam executados apenas de modo sequencial.

2. As questões de projeto são importantes, independentemente do


tipo de seleção utilizado, pois, por meio delas, o programador pode
estabelecer padrões e pensar em como usar variáveis, estruturas de
seleção e estruturas de controle da melhor forma possível na resolução
de um determinado problema.

3. O corpo do laço é importante na estrutura de controle, visto que


representa a sintaxe utilizada em cada uma das linguagens de
programação. Cabe ressaltar que ele pode sofrer variações, conforme
o tipo de linguagem empregado, por exemplo: para representar um
corpo do laço, uma linguagem imperativa pode usar uma sintaxe
diferente de uma linguagem orientada a objetos.

4. Ao se utilizar ifs aninhados no desenvolvimento de programas, é


importante prestar atenção em suas estruturas de início e término, para
que fique claro qual trecho de instruções pertence a seu respectivo if.

4 Modularização
1. Os subprogramas foram desenvolvidos com o objetivo de facilitar o
processo de desenvolvimento de um programa, uma vez que permitem
dividir o programa em partes menores de códigos e, assim, executá-las
de modo independente.

Gabarito 95
2. A modularização traz vários benéficos aos programadores, como o
aumento da legibilidade, a redigibilidade, a facilidade de modificabilidade
dos programas, a reusabilidade de códigos, a confiabilidade e a
eficiência na programação.

3. Por meio da abstração, torna-se possível obter uma boa modularização,


visto que ela permite o desenvolvimento de programas em níveis
que são identificados no contexto do problema e, posteriormente,
implementados em módulos correspondentes.

4. Como passagem de parâmetros, entende-se o processo no qual os


parâmetros formais assumem seus respectivos valores durante a
execução de um subprograma.

5 Orientação a objetos
1. A abstração de dados pode ser definida como uma representação
de determinado objeto que inclui apenas os atributos de relativa
importância em determinado contexto. Por exemplo, na representação
de um objeto ou uma entidade carro, é possível atribuir a ele apenas
as informações realmente relevantes, como placa, para viabilizar
o registro de uma multa de trânsito. Dessa forma, com o uso da
abstração, os programadores conseguem, de modo mais eficiente,
focar os atributos mais importantes para determinado problema.

2. Podem ser classificadas em dois tipos distintos e diretamente


relacionados entre si: abstração de processo e abstração de dados.
O primeiro se refere ao fluxo de controle do programa, enquanto o
segundo trata das estruturas de dados do programa.

3. As linguagens orientadas a objetos apresentam, entre as suas principais


vantagens, a reusabilidade, uma vez que adotam características
de herança, o que permite criar classes herdando os atributos e os
métodos de outras classes. Dessa forma, o projetista/programador
tem maior facilidade no momento de declarar suas classes, instanciar
seus objetos, bem como reutilizar os atributos e os métodos em mais
de uma parte do programa.

4. O encapsulamento é um dos fatores importantes da orientação a


objetos e eficaz para todas as linguagens que o implementam. Com
ele, torna-se possível informar e definir os processos sem detalhar o
que eles fazem, propriamente.

96 Técnicas de Programação
te
cni

TÉCNICAS DE PROGRAMAÇÃO
cas
Cassiana Fagundes da Silva

de
pro
Cassiana Fagundes da Silva
gra
Código Logístico Fundação Biblioteca Nacional
ISBN 978-85-387-6614-8

ma
cao
59310 9 788538 766148

Você também pode gostar