PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO 2 PARADIGMA IMPERATIVO 2.1 CONCEITO As linguagens que pertencem ao paradigma imperativo tomam por base a perspectiva da máquina. Ou seja, no modo como o computador executa programas em linguagem de máquina. Por esta razão é o paradigma mais antigo e difundido pelo mundo. Existe uma infinidade de linguagens de programação do paradigma imperativo. Como a construção de programas desse paradigma segue o modo de execução da linguagem de máquina, o processo de tradução do programa é mais simples que os demais paradigmas. Outra característica importante das linguagens imperativas é que a oferta dos seus recursos está presa à arquitetura do computador utilizada, o que explica as diversas diferenças entre a linguagem C para arquiteturas CISC e para RISC. Em outras palavras, uma linguagem de programação é construída a partir de uma determinada arquitetura base. A arquitetura mais utilizada é a Máquina de Von Neumann, cuja estrutura está ilustrada na Figura 2.1. R1 R2 . . . Memória (Instruções e dados) Rn Resultados das operações CPU Unidade lógica e aritmética Instruções e dados Unidade de controle Figura 2-1 - Máquina de Von Neumann WILIAM HIROSHI HISATUGU E/S PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO Como as linguagens de programação imperativas imitam as ações da máquina, fazendo operações básicas entre a memória e a CPU. Uma unidade de execução de um programa é composta por: Obter endereços de memória para armazenar os resultados e buscar os operandos; Obter os dados a serem utilizados na operação; Realizar a operação com os operandos; Armazenar o resultado no devido endereço. Os dados são manipulados através de endereços de memória denominados variáveis e através de operações de atribuições de valores à essas variáveis e de iterações (repetição de passos elementares). A Figura 2.2 ilustra um exemplo de uma unidade de execução desse modelo. EXEMPLO a = b+c; Obter os endereços de a, b e c; Obter os valores dos endereços de c e c; Realizar a operação b+c; Armazenar o valor da operação no endereço de a; Figura 2-2 - Exemplo de uma Unidade de Execução Como forma de criar uma maior aproximação entre o desenvolvedor humano e o computador, foi criado o conceito de função. Uma função é a representação de um bloco de código de linguagem de máquina que executa uma determinada tarefa. Muitas funções assemelham-se à expressões em linguagens naturais como, por exemplo : for (i = 0;i<10;i++) ou clrscr (clear screen = tela limpa). Esta aproximação se reflete em uma maior eficiência dos programas. 2.2 TIPOS DE DADOS “Tipos de dados podem ser entendidos como métodos (sig: meio, forma) para interpretar o conteúdo da memória do computador“ Os tipos de dados definem os valores que uma determinada posição da memória (variável pode assumir). As linguagens de programação possuem os tipos primitivos que podem ser utilizados tanto na sua forma natural, ou na construção de outros tipos de dados chamados por estruturados (Matrizes e Registros). Os tipos de dados foram construídos para: WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO Associar um nome (de tipo) a um domínio, uma representação interna e a um conjunto pré-determinado de operações; Permitir a verificação estática de tipos Uso em expressões, e/s e atribuição; Definição de equivalência de tipos; Conversão implícita e explícita. Segurança: A representação de tipos é inviolável e somente pode ser alterada através das operações definidas pela linguagem De forma geral, um tipo de dado é constituído de um nome, um ou mais domínios de valores e é associado a um conjunto de operações para manipular os seus valores. Esta representação é inviolável, somente acessível para a máquina. A Figura 2.3 ilustra dois exemplos de tipos de dados e suas operações. LINGUAGEM C EXEMPLO 1 float - domínios: números inteiros e fracionários; - operações: soma, divisão, multiplicação e subtração; - atribuição: recebe valores float e int; EXEMPLO 2 int - domínios: números inteiros - operações: soma, divisão, multiplicação, subtração e resto; - atribuições: valores int Figura 2-3 - Exemplos de Tipos de Dados Sobre os domínios de valores, há duas categorias: Primitivos – não necessitam de descrição explícita como, por exemplo, o conjunto dos números reais. Eles são a base de todos os demais tipos das linguagens de programação; Definidos – os componentes devem ser explícitos através de enumeração ou restrição. A Figura 2.4 ilustra um exemplo de enumeração e de restrição. WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO EXEMPLO ENUMERAÇÃO O conjunto são os valores: 1, 2, 3, 4,5 EXEMPLO RESTRIÇÃO O conjunto são os valores entre 2000 e 3000 Figura 2-4 - Enumeração e Restrição Existem vários propósitos para os tipos: 1. Passagens de parâmetros para funções; 2. Prevenir ou detectar construções incorretas em um programa 3. Determinar os métodos de representação e manipulação de dados no computador. Já os tipos definidos pelos usuários: Mnemônicos associados a tipos existentes Sinonímia: não criam novos identificadores simbólicos. tipos de dados; apenas usam Composição: podem ser combinados com outros tipos de dados. Permitem restrições / enumerações Os domínios compostos resultam de aplicação de métodos para construir novos domínios com base em domínios já existentes. Estes domínios compostos constituirão os tipos de dados estruturados disponíveis nas linguagens de programação: homogêneos e heterogêneos (estáticos, dinâmicos e variantes). A Figura 2.5 ilustra a estrutura de construção de um tipo composto. domínio simples método domínio estruturado Figura 2-5 - Domínio Composto Neste conceito, há duas categorias para os tipos de dados compostos: Homogêneas – todos os componentes pertencem ao mesmo tipo. Os vetores e as matrizes pertence a essa categoria; WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO Heterogênea – os componentes podem pertencer a diferentes tipos primitivos ou mesmo outros tipos compostos. Nesta categoria se encontram os registros e estruturas. Sobre os tipos primitivos, eles podem ser classificados em duas categorias: Numérico: compreende os tipos de dados utilizados para operações aritméticas. Conseqüentemente, eles podem armazenar apenas números. São exemplos de tipos numéricos: int, float na linguagem C e integer, real na linguagem Pascal; Caractere: são tipos de dados orientados para caracteres. Como forma de possibilitar o manuseio de cadeias de caracteres (palavras, frases e expressões) foi inserido o conceito de strings. Algumas linguagens fazem esse tratamento de forma explícita como, por exemplo, a linguagem Pascal. Outras fazem de forma implícita como, por exemplo, a linguagem C. na sua forma mais pura, uma string é uma matriz do tipo caractere. Para suporte às operações com strings foram criadas funções específicas para o manuseio das mesmas. As matrizes, também chamadas arrays, são definidas como um agregado homogêneo de dados, cujo elemento individual é identificado por sua posição em relação ao primeiro. Elas podem ser classificadas como: Array estático: faixas de índice estão estaticamente vinculadas e a alocação de armazenamento e estática (eficiente) Array stack-dinâmico fixo: índices estáticos, com alocação durante a execução; Array stack-dinâmico: índices e alocações dinâmicas. (flexibiliade) Array heap-dinâmico: (flexibilidade. alocação pode alterar durante a execução. Por outro lado, os registros e estruturas são formados por elementos de diferentes tipos, onde eles são identificados por um nome. Para ser acessado, o elemento é associado junto com o nome da variável estrutura. A Figura 2.6 ilustra um exemplo de uma estrutura feita em linguagem C. WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO EXEMPLO: struct Ficha{ char nome[40]; char endereco[40]; char fone[20]; float valor; } struct Ficha nova; gets(nova.nome); 2.3 COMPATIBILIDADE, EQUIVALÊNCIA E INFERÊNCIA A equivalência de tipos determina quando dois valores possuem o mesmo tipo A compatibilidade define quando um tipo pode ser usado em lugar de outro em um determinado contexto A inferência de tipos define o tipo de uma expressão com base nos tipos de operandos envolvidos e a operação a ser realizada. 2.3.1 Compatibilidade Quando existe compatibilidade de tipos, pode-se misturar valores de tipos diferentes em expressões, ou mesmo usar um tipo A em lugar de um tipo B, sem que haja violação das regras de segurança de tipos (erro de tipo). A Figura 2.7 ilustra um exemplo de compatibilidade de dados. EXEMPLOS: Seja i um inteiro e f um real e fun (inteiro, real) São válidas as atribuições: i := r e r:= i? É válida a invocação: fun(r, i)? Conversão de Tipos Quando os tipos envolvidos em uma expressão não são equivalentes, a linguagem oferece a possibilidade de conversão de tipos. A conversão implícita ou automática é feita com base nas regras definidas sem a interferência do programador. A conversão explícita é codificada diretamente pelo programador. WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO A conversão de tipos primitivos é ditada pelas regras da linguagem de programação. Normalmente admite a conversão de um tipo de representação menor para um tipo de representação maior. Por exemplo, em Java, a conversão entre tipos primitivos, exceto o tipo bool que não admite conversão, considera o tamanho do tipo (8, 16, 32, 64 bits). A Figura 2.8 ilustra um exemplo de conversões possíveis de tipos. de byte short char int long float para short,int,long,float,double int,long,float,double int,long,float,double long,float,double float,double double A conversão pode ser feita de três maneiras, ilustradas posteriormente na Figura 2.9: Por atribuição, ou conversão implícita para o tipo do lado esquerdo do comando de atribuição; Por promoção aritmética para o tipo de resultado esperado da operação (inferência); Por conversão explícita (casting). EXEMPLO DE CONVERSÃO: 2.3.2 Seja float f, int i, float r; exemplo de atribuição: f = i; exemplo de promoção: r = f / i; exemplos de casting: i = (int) f ; r = (float) i/f; Equivalência de Tipos Tipos estruturados e tipos definidos pelo usuário. As formas de equivalência são: Equivalência estrutural: mesma representação Equivalência de nome: mesmo nome de tipo Equivalência de declaração: mesma declaração A Figura 2.10 ilustra um exemplo de equivalência de tipos: WILIAM HIROSHI HISATUGU PARADIGMAS DE LINGUAGEM DE PROGRAMAÇÃO type doiscampos = record a, b: integer; end; ? type doiscampos = record a: integer; b: integer; end; type doiscampos = record b: integer; a: integer; end; WILIAM HIROSHI HISATUGU