Métodos de Programação I Departamento de Matemática, FCTUC 16 CAPÍTULO 2 PROGRAMAÇÃO IMPERATIVA: a Linguagem Pascal 2.1 Programação: Conceitos Fundamentais 2.1.1 Fases de construção de um programa executável 2.1.2 Metodologia da programação 2.2 A Linguagem Pascal 2.2.1 Introdução 2.2.2 Tipos de informação: Tipos pré-definidos (standard) 2.2.3 Apresentação dos Diagramas de Sintaxe Identificador Programa Declaração de Variáveis Declaração de constantes 2.2.4 Tipos definidos pelo utilizador Definição por enumeração Definição por sub-domínio 2.2.5 Expressões 2.2.6 Instrução de Sequenciação 2.2.7 Instrução de Atribuição 2.2.8 Instruções de Entrada e Saída Instruções de Leitura Instruções de Escrita Formatos 2.2.9 Estruturas de Controlo Selecção: condicional e alternativa Repetição: com teste à cabeça, com teste à saída e com contador 2.2.10 Tipo Estruturado Tabela 2.3 Subprogramas 2.3.1 Introdução 2.3.2 Procedimentos 2.3.3 Domínio dos identificadores 2.3.4 Parâmetros 2.3.5 Classes de parâmetros 2.3.6 Funções
Métodos de Programação I Departamento de Matemática, FCTUC 17 Capítulo 2 2.1 PROGRAMAÇÃO: CONCEITOS FUNDAMENTAIS 2.1.1 FASES DE CONSTRUÇÃO DE UM PROGRAMA EXECUTÁVEL Como vimos anteriormente, quando necessitamos de programar o nosso computador de modo a efectuar uma dada tarefa, podemos escrever um programa numa determinada linguagem de alto nível. No entanto, para que o computador possa entender os comandos necessários para realizar a tarefa programada, ter-se-á que transformar o programa escrito pelo utilizador, num programa que possa ser compreendido pela CPU, isto é, em linguagem máquina. Para esse efeito, existe software de suporte especial, que traduz o programa de alto nível - dito programa fonte - para o seu equivalente em linguagem máquina, o programa objecto. A esse software especial, que é um programa executável de suporte, dá-se o nome de COMPILADOR. Dados Programa Fonte Compilador Fase de Compilação Computador Programa Erros de Objecto compilação Fase de Computador Execução Resultados Erros de execução Figura 2.1: Fases principais de construção de um programa executável Podemos, portanto, definir duas fases principais e usuais para conseguir implementar um programa num computador (e poder correr, isto é, pôr em funcionamento efectivo ou executar):
Métodos de Programação I Departamento de Matemática, FCTUC 18 Fase de Compilação: tradução de um programa fonte num programa objecto. Podem ocorrer, nesta fase, erros léxicos ou sintáticos, como por exemplo, no caso de se ter cometido um erro ortográfico, ou usado incorrectamente uma dada construção (instruções incompletas ou incompatíveis). Numa situação destas, o compilador termina a sua tarefa com mensagens de erro e identificação do(s) erro(s) ou da zona a partir da qual deixou de entender o fluxo de instruções. Estas mensagens de erro tomam o nome especial de erros de compilação. Caso os erros não tenham sido suficientemente graves para interromper a tradução, o programa objecto é gerado de qualquer modo, sendo as mensagens enviadas pelo computador, simples avisos (que devemos ter em conta e corrigir). Noutros casos, o compilador não consegue recuperar os erros e não gera código máquina, ou seja, não gera o programa objecto. O programador é obrigado a corrigir os erros. Fase de Execução: funcionamento do programa (objecto). Também nesta fase podem ocorrer erros (obviamente ditos erros de execução): introdução incorrecta de dados, erros semânticos, algoritmo mal construído ou inadequado. Estes erros podem ser detectados de dois modos: o programa aborta, isto é, termina repentinamente (muitas vezes sem enviar qualquer mensagem inteligível) ou então devolve resultados errados ou demasiado estranhos. Cabe inteiramente ao programador a identificação da situação de erro e sua correcção. Apesar de, por uma questão de simplicidade, termos começado por apresentar estas duas fases é óbvio que, anteriormente às fases de compilação e execução, é necessário construir o programa para executar uma dada tarefa. Assim, temos a Fase de Elaboração de um Programa Problema: Identificação do problema que se pretende resolver; Especificação: Dados Resultados Relações entre ambos Algoritmo (sequência de instruções que definem um método de resolução) Esquema do Programa Primeira versão do Programa Simulação: simular alguns valores de modo a tentar evitar erros de execução; Aperfeiçoamentos Compilar e Executar Correções/Aperfeiçoamentos 2.1.2 METODOLOGIA DA PROGRAMAÇÃO Vimos já que um algoritmo é uma sequência finita e ordenada de instruções (escritas numa linguagem natural ou matemática) e que permite a construção de um objecto (solução de um dado problema que o algoritmo ). Um programa é uma sequência finita de instruções, bem definidas e (tanto quanto possível) sem ambiguidades, cada uma das quais pode ser executada mecanicamente, num período de tempo finito, e utilizando quantidades finitas de recursos. Qualquer computador é gerido por programas, e podemos, sempre que necessário, criarmos nós mesmos os programas que necessitamos. Para uma efectiva e eficiente construção de programas, são necessárias 3 peças fundamentais: um bom algoritmo (método conceptual de resolução), ordem e método. Por algoritmo entende-se uma
Métodos de Programação I Departamento de Matemática, FCTUC 19 sequência finita de passos elementares e não ambíguos, que permitam a construção de algo ou a resolução de um problema. Pretende-se, com o ponto presente, sumariar alguns princípios fundamentais que servem como base para conseguir um bom programa, o mais rapidamente possível. Estes princípios são especialmente importantes quanto maior (ou mais complexa) é a tarefa em causa. A apresentação seguinte salienta a necessidade de uma programação estruturada, no sentido em que um bom programa é sempre aquele que se apresenta bem estruturado e bem documentado, qualquer que seja a sua ordem de grandeza. Assim, a metodologia da programação tem como objectivos principais a atingir os seguintes: Correcção O programa deve obedecer exactamente às especificações, para poder, efectivamente, resolver o problema proposto. Um bom algoritmo é uma especificação concisa de um método para resolver o problema em causa, desenvolvida em várias fases, que vão desde a perfeita compreensão do problema a solucionar, passando pelo desenho de uma solução conceptual, até à implementação dessa solução através de um programa de computador. Assim, dever-se-à ter em conta os pontos seguintes: Simplicidade; Estrutura (aproximação sistemática, modular e descendente); Verificação Formal (demonstração lógica da correcção do algoritmo); Clareza O programa deve reflectir a estrutura do algoritmo em causa e permitir uma fácil detecção e correcção de erros. Mais ainda, deve ser legível, modificável e de fácil ampliação por outro programador. Nesse sentido dever-se-à: Utilizar separação de código em blocos (módulos); Fazer um uso adequado das estruturas da linguagem; Escolher cuidadosamente os identificadores a usar; Sempre que necessário, colocar espaços em branco para evitar confusões; Promover uma boa indentação; Utilizar comentários para ilustar passagens ou blocos menos óbvios; Eficiência Tempo de execução; Espaço de memória; A medida computacional de eficiência de um programa não depende apenas do tempo mas ainda do espaço, isto é, não contamos apenas o tempo que um dado programa leva até completar a tarefa a que está destinado, mas também o espaço de memória que ocupa para a execução. Mais ainda, estes dois factores estão, na prática, muitas vezes intimamente interligados, daí que, na maior parte dos casos, diminuir um deles implica também diminuir o outro. De qualquer modo, a eficiência não deverá ser conseguida à custa da perda de clareza do programa.
Métodos de Programação I Departamento de Matemática, FCTUC 20 2.2. A LINGUAGEM PASCAL 2.2.1INTRODUÇÃO Qualquer programa em Pascal tem, obrigatoriamente, duas partes principais: uma parte declarativa e uma parte operativa. Vamos começar por apresentar um exemplo de um programa muito simples que nos vai ajudar a reconhecer algumas regras da linguagem Pascal e, nomeadamente, a reconhecer as partes e componentes fundamentais de qualquer programa em Pascal. Suponha-se que queremos escrever um programa que possa somar dois números dados: (* programa que soma 2 números *) comentário parte program somar (input, output); declarativa var x, y, soma : real; ficheiros de entrada e saída begin parte read( x, y); operativa soma := x + y; write( soma ) end. Figura 2. 2: Programa para somar dois números dados. A parte declarativa, precede a parte operativa e serve, evidentemente, para declarar: o nome do programa e ficheiros externos que possam ser utilizados (este conjunto é conhecido como cabeça do programa), as variáveis que vão ser utilizadas, etc. A parte operativa é composta por blocos de instruções, tantos quantos os necessários, e onde cada instrução é separada da seguinte por ; (ponto e vírgula). O programa termina obrigatoriamente com o caracter. (ponto final). Mais ainda, É obrigatória a declaração de todas as variáveis a usar, podendo ser denominadas livremente pelo utilizador, desde que este se abstenha de usar palavras reservadas para determinadas funções dentro da própria linguagem - algumas dessas palavras reservadas são, por exemplo, aquelas que aparecem sublinhadas no programa do exemplo anterior. Há instruções compostas (blocos), que são delimitadas pelas palavras reservadas begin e end - sendo exemplo disso mesmo a parte operativa de um programa, que também é dita bloco (ou módulo) principal do programa. O programa é, usualmente escrito em letras minuscúlas, e como foi referido anteriormente, a indentação torna o programa mais legível. NOTAS: Por vezes existem alterações ao Pascal Standard para certos computadores, como por exemplo, Comentários indicados por { }. ou (* *); A indicação de comunicação com o exterior (declaração dos ficheiros de input/output) na cabeça do programa ou após; Índices indicados por [ ] ou (..); Uso de letras minúsculas e/ou maiúsculas; Palavras reservadas diferenciadas ou não: begin begin.begin.
Métodos de Programação I Departamento de Matemática, FCTUC 21 2.2.2 TIPOS DE INFORMAÇÃO PRÉ-DEFINIDOS TIPOS ESCALARES DEFINIDOS PELO UTILIZADOR ESTRUTURADOS TIPOS PRÉ-DEFINIDOS (STANDARD) E ALGUNS SEUS OPERADORES E FUNÇÕES Os tipos pré-definidos elementares no Pascal são os seguintes: inteiros - integer reais - real lógicos - boolean caracteres - char Seguidamente, veremos quais os operadores mais usuais para cada um destes tipos e, mesmo, algumas funções pré-definidas que permitem operar com alguns deles. Inteiros integer Como vimos anteriormente, o maior inteiro que é possível representar depende da palavra do computador. No entanto, esse maior inteiro toma a designação genérica de maxint. Para operar de, e para, o domínio dos inteiros, existem vários operadores e funções, dos quais passamos a descrever, apenas, os mais usuais: Operadores aritméticos com operandos e resultados inteiros: operador exemplo operação + 5 + 3 adição - 2 9 subtracção ou simétrico * 45 * 1098 multiplicação div 107 div 3 quociente da divisão inteira mod 16 mod 7 resto da divisão inteira Funções com argumento e resultado inteiros função exemplo resultado abs abs ( -6 ) = 6 abs ( 5 ) = 5 sqr sqr ( 3 ) = 9 sqr ( -3 ) = 9 valor absoluto potência quadrada
Métodos de Programação I Departamento de Matemática, FCTUC 22 succ succ ( 7 ) = 8 sucessor succ ( -7 ) = -6 pred pred ( 10 ) = 9 predecessor Funções com argumento inteiro e resultado real função exemplo resultado sqrt sqrt ( 3 ) = 1,732050808 raiz quadrada Operadores relacionais operador exemplo operação = abs( 5 ) = 5 igualdade < > 2 <> 9 desigualdade < 45 < 1098 menor que > 107 > -3 maior que >= 12 >= 2 maior ou igual <= -6 <= 7 menor ou igual Reais real Do mesmo modo que para os inteiros, a grandeza e precisão máximas dependem do computador. Operadores aritméticos o Basta que um dos operandos seja real para que o resultado seja um real; o Os reais são armazenados e avaliados em notação científica. operador exemplo operação + 5 + 3.5 = 8.5 adição 5.0 + 3.5 = 8.5-2.9-9 = -6.1 subtracção -89.65 simétrico * 0.5 * 3 = 1.5 multiplicação / 1.2 / 2 = 0.6 3 / 2 = 1.5 divisão real os dois operandos podem ser inteiros Funções com resultado real se o argumento fôr real função exemplo resultado abs abs ( -6.5 ) = 6.5 valor absoluto abs ( 5 ) = 5 sqr sqr ( 3.1 ) = 9.61 potência quadrada
Métodos de Programação I Departamento de Matemática, FCTUC 23 Funções com argumento real e resultado inteiro função exemplo resultado trunc trunc ( -3.7 ) = -3 trunc ( 3.7 ) = 3 round round ( -3.7 ) = -4 round ( 3.7 ) = 4 round ( 3.2 ) = 3 round ( -3.2 )= -3 truncatura arredondamento Funções com resultado real função exemplo resultado cos cos ( 3 ) = 0.98999 cosseno cos( 3.14 15) = 1.0 sin sin ( 3 ) = 0.14112 seno sin (3.14 15) = 0.0 arctan arctan ( -1) = 3.11415 arco de tangente sqrt sqrt ( 4 ) = 2.0 raiz quadrada sqrt ( 9.0 ) = 3.0 exp exp ( 1 ) = 2.71828 exponencial ln ln ( 2.71828 ) = 1.0 ln ( 1 ) = 0.0 logaritmo nepperiano Operadores relacionais operador exemplo operação =????? igualdade < > desigualdade < menor que > maior que >= maior ou igual <= menor ou igual A utilização de operadores de comparação entre reais é mais problemática que entre inteiros e só deve ser efectuada quando absolutamente necessário e rodeada de todos os cuidados. Vejamos o exemplo seguinte que ilustra bem este ponto: Sabemos que, aritmeticamente, 1/3 + 2/3 = 1. De facto, estas fracções são dizimas infinitas (1/3 = 0.333333333 e 2/3 = 0.66666666 ) que, no limite, igualam 1. No entanto, a representação computacional destas fracções tem uma precisão truncada, não temos recursos de memória infinitos, donde, temos que cortar algures a dizima para a poder representar. Assim, o resultado computacional da avaliação desta soma é: 0.3333333 + 0.6666666 = 0.9999999 1
Métodos de Programação I Departamento de Matemática, FCTUC 24 Lógicos boolean, com valores - false e true Operadores lógicos Os operadores e valores lógicos seguem as tabelas de verdade já nossas conhecidas, e, obviamente, seguem as mesmas regras gerais de avaliação do valor de verdade. operador operação and conjunção ( ) or dijunção ( ) not negação ( ) Exemplos: x ]0, 1], isto é, x > 0 x 1, em Pascal é: ( x > 0 ) and ( x <= 1 ) ( x > 1 ) and ( x < 0 ) é falso e not ( 0 < -1 ) = true é verdadeiro Função com argumento inteiro e resultado lógico função exemplo operação odd odd ( 5 ) = true odd ( 2 ) = false ímpar Caracteres char O conjunto dos caracteres possíveis pode variar mas inclui sempre, enter outros mais usuais, A B C D X Y Z a b c d x y z 0 1 2 9 + - * ( ) onde: cada subconjunto está ordenado; cada caracter tem uma representação interna - nº natural; qualquer caracter é representado entre apóstrofes: A A + + 5 5 variável operador numeral Funções de transferência: função exemplo operação chr chr ( 48 ) = A caracter ord ord ( A ) = 48 nº interno correspondente Por exemplo, chr ( ord ( a ) + 2 ) = c ord ( D ) - ord ( A ) = 3 ord ( 5 ) - ord ( 0 ) = 5
Métodos de Programação I Departamento de Matemática, FCTUC 25 Os operadores relacionais são válidos entre caracteres, a < c, X = X e, mais ainda, as duas funções anteriores são inversas uma da outra, isto é chr (ord (char ) ) = char e ord (chr ( inteiro ) ) = inteiro Funções argumento e resultado char: função exemplo operação succ succ ( R ) = S chr(ord(char) + 1) pred pred ( a ) = Z chr(ord(char) - 1) Vejamos um pequeno exemplo que engloba algumas das regras e operações anteriores, apresentando um programa em Pascal para simular o funcionamento de uma calculadora aritmética simples: program calculadora (input, output); var operador : char; x, y, resultado : real; begin read(x, operador, y); case operador of + : resultado := x + y; - : resultado := x - y; * : resultado := x * y; / : resultado := x / y end; write(x, operador, y, =, resultado) end. Figura 2.3: programa para simular uma calculadora aritmética. 2.2.3 APRESENTAÇÃO DOS DIAGRAMAS DE SINTAXE A linguagem Pascal, como qualquer outra, para além do léxico próprio, necessita de regras sintácticas para construir frases e palavras válidas para a linguagem. Fica completamente definida por um conjunto de diagramas sintácticos e diz-se que Um programa está correcto sintaticamente se e só se corresponder a um caminho ao longo dos diagramas. Vejamos alguns exemplos de diagramas sintáticos para a construção correcta de alguns objectos em Pascal.