01 O que é Ada? |
02 Estrutura Básica de Um Programa em Ada. |
03 Palavras reservadas. |
04 Declarações de Bibliotecas. |
05 Programa Alô Mundo. |
06 Cláusula Use. |
07 Declaração de Variáveis. |
08 Get. |
09 Comentários. |
10 IF. |
11 For. |
12 While. |
13 Loop. |
14 Case. |
15 Null. |
16 New_Line. |
17 Strings. |
18 Put_Line. |
19 Caracters. |
20 Exemplo de um pequeno programa. |
21 Tipos Pré-definidos em Ada. |
22 Conversão de tipos. |
23 Arrays. |
24 Procedimentos e Funções. |
25 Arquivo de "Corpo" e "Fonte". |
26 Manipulando Arquivos. |
27 Unbounded Strings. |
28 Ainda Strings. |
29 Novos Tipos e Subtipos. |
30 Registros. |
31 Gerador de Números Aleatórios. |
32 Números de ponto flutuante e ponto fixo. |
33 Goto. |
34 Access Type. |
35 Generics. |
36 Maiúsculas e Minúsculas. |
37 Ada.Numerics.Elementary_Functions; |
38 Números Complexos. |
39 Exceptions. |
40 Importando funções de outras linguagens. |
41 Sites de Ada. |
42 Manuais e Compilador.
|
1 O que é Ada?
Ada é uma linguagem de programação de alto nível, imperativa, tipicamente compilada (embora haja
interpretadores) e baseada em Pascal, que foi criada através de um concurso realizado pelo DoD (U. S.
Departament of Defense) sendo o principal projetista o francês Jean Ichbiah. Tal concurso foi realizado
para por ordem na situação em que o DoD se encontrava pois eles em 1974 usavam cerca de 450
linguagens ou dialetos de programação e não havia uma linguagem adequada.
A linguagem foi primeiramente padronizada em 1983 pelo ANSI e em 1985 pela ISO (Organização
Internacional de Padronização) e em 1995 a ISO padronizou uma versão melhorada conhecida como
Ada 95. Ada 95 foi a primeira linguagem de programação orientada ao objeto padronizada internacionalmente.
O nome Ada é homenagem a condessa de Lovelace, Augusta Ada Byron, filha de Lord Byron e que
trabalhou com Charles Babage sendo considerada a primeira programadora de computadores da
Hístoria. Veja que o correto é Ada e não ADA.
2 Estrutura Básica de Um Programa em Ada.
--Declaracoes de bibliotecas |
Procedure nome_do_programa is |
--Declaracoes de variaveis |
begin |
--Corpo do programa |
end nome_do_programa;
|
Ada é uma linguagem não sensível a case, ou seja, tanto faz escrever em maiusculo ou minusculo.
3 Palavras reservadas.
De acordo com o "Ada 95 Reference Manual" essas são as palavras reservadas em Ada.
Tanto faz letras maiúsculas ou minúsculas.
Umas 47 1 dessas são abordadas nesse manual ou são de uso óbvio.
abort | abs | abstract | accept | access | aliased | all |
and | array | at | begin | body | case | constant |
declare | delay | delta | digits | do | else | elsif |
end | entry | exception | exit | for | function | generic |
goto | if | in | is | limited | loop | mod |
new | not | null | of | or | others | out |
package | pragma | private | procedure | protected | raise | range |
record | rem | renames | requeue | return | reverse | select |
separate | subype | tagged | task | terminate | then | type |
untill | use | when | while | with | xor | |
4 Declarações de Bibliotecas
Como ocorre na maioria das linguagens modernas os procedimentos de entrada e saída não são
definidos na linguagem propriamente dita mas sim em bibliotecas especiais. São muito importantes em
Ada as seguintes bibliotecas: Ada.Text_IO (ou simplesmente Text_IO), Ada.Integer_Text_IO e
Ada.Float_Text_IO que servem para fornecer procedimentos de entrada e saída e para trabalhar com textos,
números inteiros e números reais de ponto flutuante respectivamente.
Para declarar a biblioteca Ada.Text_IO basta fazer assim
5 Programa Alô Mundo
--Programa Alo Mundo |
With Ada.Text_IO; |
Procedure AloMundo is |
begin |
Ada.Text_IO.Put_Line("Alo Brasil!!!"); |
Ada.Text_IO.Put_Line("Alo Mundo!!!"); |
end AloMundo; |
6 Cláusula Use
O comando Put_Line pertence a biblioteca Ada.Text_IO. Usando Use não precisamos reescrever o
nome da biblioteca cada vez e assim o programa Alô Mundo fica:
--Programa Alo Mundo |
With Ada.Text_IO; Use Ada.Text_IO; |
Procedure AloMundo is |
begin |
Put_Line("Alo Brasil!!!"); |
Put_Line("Alo Mundo!!!"); |
end AloMundo; |
Mas é preciso cuidado ao usarmos o Use para evitar que em grandes programas não saibamos mais de
que biblioteca vem o comando ou procedimento.
7 Declaração de Variaveis
Para declarar a variável x como sendo float é só fazer:
x : float;
Para declarar a variável y como sendo do tipo interio e atribuir o valor 5 e a constante Pi de valor 3.1415 basta fazer:
y :integer := 5; Pi :constant float :=3.1415;
As declarações em geral devem ficar entre o cabeçalho do programa e o begin mas o mesmo pode ser
feito para funções ou procedimentos sendo nesse caso variaveis locais e não globais.
8 Get
A biblioteca Ada.Text_IO define o Put como sendo o comando padrão de saída assim como é o
PRINT do BASIC ou o Write do Pascal. Já o comando de entrada padrão é o Get. Para fazer o Get ler do
teclado e por numa variável x basta fazer:
Exemplo:
With Ada.Integer_Text_IO, Ada.Text_IO; |
Use Ada.Integer_Text_IO, Ada.Text_IO; |
Procedure mostraget is |
x : natural; |
begin |
Put_Line("Entre um numero natural"); |
Get(x); |
Put_Line("O numero que voce entrou foi: "); |
Put(x); |
end mostraget; |
9 Comentários
Comentários são anotações feitas dentro do próprio código do programa que servem para tornar o
mesmo código mais claro e fácil de ser entendido ou ainda para alertar para algo que se deseja ser
enfatizado.
Um bom programa deve possuir muitos comentários.
Os comentários não são lidos pelo compilador.
Em Ada tudo o que estiver a direita de -- não será lido pelo compilador.
Ex:
Esse é o unico tipo de comentário existente em Ada. Não existe nada análogo ao /* e */ do C e ao { e } ou (* e *) do Pascal.
O if(se) pode ser usado assim:
if condicao then |
sequencia de comandos (executada se a condição é verdadeira) |
else |
outra sequencia de comandos (executada se a condição é falsa) |
end if ;
|
Ex:
if x > 4 and x < 10 then |
y:=x+2; |
x:=3; |
else |
y:=0; |
end if; |
Uma outra estrutura mais simples e bastante comum é
if condicao then |
sequencia de comandos (executada se a condição é verdadeira) |
end if;
|
O if também pode ser usado com o "elsif" permitindo assim fazer estruturas bem complexas de forma
simples
if condicao1 then |
sequencia de comandos1 |
elsif condicao2 then |
sequencia de comandos2 |
elsif condicao3 then |
sequencia de comandos3 |
. |
. |
else |
sequencia de comandos |
end if;
|
Ao contrario do Pascal você não precisa usar begin e end caso haja mais de um comando.
Você também não precisa usar paranteses quando usar mais de um operador logico tipo and, or, etc,
na condição do if, a não ser que haja ambiguidade.
O for (para) pode ser usado da seguinte forma: (Isso é um meio exemplo)
for a in 1..10 loop |
sequencia de comandos |
end loop;
|
a não precisa estar declarado a menos que você o use explicitamente não só como indice.
Esse meio exemplo executa uma sequencia de comandos para a=1 até a=10. Para fazer na ordem
contraria basta fazer:
for a in reverse 1..10 loop
|
12 While
O While (enquanto) é usado da seguinte forma: (Outro meio exemplo)
while a /=3,e b < =15,e c=3.0 loop |
sequencia de comandos |
end loop;
|
onde "/=" quer dizer diferente.
13 Loop
O Loop é usado para repetições infinitas. (Meio exemplo)
loop |
sequencia de comandos |
end loop;
|
Mas é claro que podemos parar, veja:
loop |
sequencia de comandos |
exit when a=3; |
outra sequencia de comandos |
end loop;
|
No exemplo acima o loop irá parar quando a for igual a 3. A primeira sequencia de comandos será
executada quando for 3 mas a outra posterior ao exit não.
Um aspecto agradável em Ada é que todas as repitições terminam em end loop; o que torna fácil
modifica-las de uma para outra sem jamais confundir com um if ou case por exemplo.
14 Case
O case (caso) pode ser usado assim: (novamente um meio exemplo)
case x is |
when 1 = > executa alguma coisa |
when 2 = > executa outra coisa |
when 3..10 = > executa outra coisa ainda |
when others = > Put_Line("Oi"); |
end case;
|
Nesse meio exemplo, se x for 1 vai executar alguma coisa, se for 2 outra, se estiver entre 3 e 10
incluindo 3 e 10 vai executar outra coisa ainda e irá escrever "Oi" caso não seja nenhum desses.
15 Null
Quando você não quer fazer nada use null. Ex:
Procedure nulo is |
begin |
null |
end nulo; |
16 New_Line
Você usa New_Line; para mudar de linha na saída padrão.
17 Strings
Strings são arrays (sequencias) de caracteres que você pode usar para conter textos.
Você delimita uma string usando " e ", Ex:
Put("Isso aqui e' uma string"); ;
|
Você também pode criar variaveis do tipo string como no exemplo de declaração abaixo.
menssagem : string(1..9) :="Oi gente!";
18 Put_Line
Tem o mesmo efeito de Put seguido de New_Line mas só pode ser usado para strings.
19 Caracteres
Exemplo de uma declaração: x : Character :='w';
Note que usa ' e não " e " como no caso das strings.
20 Exemplo de um pequeno programa
--Esse e' um programa que escreve a tabuada. |
With Ada.Text_IO; Use Ada.Text_IO; |
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO; |
Procedure Tabuada is |
A, B: Integer; |
begin |
for A in 1 .. 10 loop |
New_Line; |
Put(" Tabuada do "); |
Put(A); |
New_Line; |
New_Line; |
for B in 1 .. 10 loop |
Put(A); |
Put(" X"); |
Put(B); |
Put(" ="); |
Put(A*B); |
New_Line; |
end loop; |
New_Line; |
end loop; |
end Tabuada; |
21 Tipos Pré-definidos em Ada
Integer:Valores inteiros de no mínimo -32767..32767 ou seja (-2**15+1..2**15-1). Long_Integer: Valores inteiros de no mínimo -2147483647..2147483647 ou seja (-2**31+1..2**31-1).
O RM sugere a existencia dos tipos Long_Long_Integer, Short_Integer, Short_Short_Integer, etc, mas não obriga a existencia deles e deixa para as implementações determinarem o range. Apenas diz que que o que tiver Long deve ter um range maior, o que tiver Short menor, etc. O tipo integer admite basicamente as
operações +, -, *, /, abs, mod, ** (potencia), entre outras. Os operadores de
comparação admitidos são: =, /= (diferente), < , > , < =, > =.
Natural: É um subtipo do Integer que não possui números negativos.
Positive: É um subtipo do Integer que não possui zero e números negativos.
Float: Tipo real de ponto flutuante de no mínimo -10.0**(4D)..10.0**(4D) onde D é a precisão decimal. O RM sugere o Long_Float com D=11 no mínimo e no que
diz respeito aos Long_Long_Float, Short_Float, etc, se existirem a situação é a
mesma da do Integer. As operações admitidas são +, -, *, /, abs, ** mas essa
última deve ter o segundo nmero (expoente) inteiro embora o resultado seja
float. Os operadores de comparação são os mesmos do interger.
Character: Assume os valores de caracteres correspondente aos 256 valores de codigo do Row00
também conhecido como latim 1. Os operadores de comparação são os mesmos.
String: É um array(lista) de Characters.
Boolean: Assume os valores true e false. Os operadores de comparação são os mesmos já citados.
Permite as operações lógicas and, or, xor(or exclusivo), not.
Existe diversas bibliotecas padrões que podem ampliar o quadro visto.
A Ada.Numerics.Elementary_Functions permite fazer as operações Sin, Cos, Tan, ArcSin, ArcCos,
ArcTan, SinH, CosH, Exp, Log, Sqrt com o tipo Float além definir Pi e e, etc.
A Ada.Calendar define o tipo Time com subtipos tais como Year_number, etc.
Você também pode criar seus próprios tipos.
22 Conversão de Tipos
Sendo uma linguagem baseada em Pascal, Ada conserva a caracteristica de ser fortemente tipada.
Suponha que você tenha duas variaveis a e b declaradas assim:
Para fazer a receber o valor de b você deve fazer:
a := integer(b); --O valor sera arredondado.
Já para fazer b receber o valor de a você deve fazer:
b := float(a);
A expressão a := b (analoga a uma permitida em linguagem C) ou mesmo a mais inocente b := a
(permitida em Pascal) são completamentes erradas em Ada. Ada permite conversão de tipos a vontade
desde que o programador demostre que realmente sabe o que esta fazendo e que portanto não é um erro.
23 Arrays
Os arrays são uma maneira de se armazenar coisas na forma de listas, tabelas, etc.
Veja um exemplo de um programinha usando arrays:
With Text_IO; Use Text_IO; |
Procedure usando_array is |
vogal : array(1 .. 5) of character; |
begin |
vogal(1):='a'; |
vogal(2):='e'; |
vogal(3):='i'; |
vogal(4):='o'; |
vogal(5):='u'; |
for i in 1 .. 5 loop |
Put(vogal(i)); |
end loop; |
end usando_array; |
Agora para declarar um um array bi-dimensional você pode fazer assim
tabela: array(1 .. 10, 1 .. 10) of integer;
|
Nesse caso, para fazer o elemento de posição 2,3 assumir o valor 5 bastaria fazer
tabela(2,3):=5;
24 Procedimentos e Funções
Procedimentos e funções são pedaçoes de programa que ficam separados do corpo principal do
programa e servem para evitar demasiada repitição de código semelhante, para tornar o programa mais
claro, etc.
A declaração de um procedimento ou função deve ficar entre o procedure e o begin do procedimento
principal, i.e., do programa.
Veja um exemplo de declaração de um procedimento:
Procedure escreve_oiz_gente_dez_vezes is |
begin |
for i in 1..10 loop |
Put_Line("Oi gente"); |
end loop; |
end escreve_oi_gente_dez_vezes; |
No corpo do programa principal, cada vez que aparecer o comando
escreve_oi_gente_dez_vezes;
Esse procedimento será executado.
Observe que não preciso declarar aqui a biblioteca Text_IO uma vez que a mesma já esta
supostamente declarada no programa principal.
As funções são como os procedimentos mas diferem desses por sempre retornarem um valor e
poderem ser postas dentro de expressôes usadas em formulas ou ainda dentro de condições. ex:
Function fatorial(n: integer) return integer is |
numero: integer; |
begin |
numero:=n; |
resultado:=1; |
while numero /= 1 loop |
resultado:=resultado*numero; |
numero:=numero-1; |
end loop; |
return resultado; |
end fatorial; |
Observe que nesse exemplo numero é uma variável local enquanto resultado é uma variável global já
declarada no programa principal. O comando "return resultado;" faz com que a função de por saida a
variável resultado. Eu poderia escrever "in" entre os "n:" e o "integer" na declaração da função mas isso
não é preciso uma vez que funcões só recebem parametros de entrada que não podem ser modificados
dentro da função, dai a nescessidade de criar a variável "numero" aparentemente redundante.
No corpo do programa para calcular o fatorial de x basta fazer:
fatorial(x);
Podemos até mesmo fazer:
a:= 3 + fatorial(b);
Nesse outro exemplo abaixo vamos por uma função na condição de um if:
Function par(n: in integer) return boolean is |
resultado:boolean; |
begin |
if n mod 2 = 0 then resultado:=true; else |
resultado:=false; |
end if; |
return resultado; |
end par; |
Dai no corpo do programa podemos escrever:
if par(x)=true then |
Put_Line("Esse numero e' par"); |
else |
Put_Line("Esse numero e' impar"); |
end if; |
Observe que nesse exemplo acima eu usei o "in" e nesse caso resultado esta como variável local.
Para a função isso não tem importancia nenhuma, ou melhor, esse é o jeito mais correto.
25 Arquivos de Corpo e Fonte
Em Ada os programas não precisam estar contidos em um único arquivo.
Existem dois tipos de arquivos. Os de "corpo" (ou "body") e os de "fonte" (ou "source").
Os primeiros contem os procedimentos e funções que constituem um programa.
São geralmente identificados pela extensão .ada ou .adb (Ada Body) e correspondem aos arquivos .c em linguagem C.
Os arquivos de fonte são identificados em geral com a extensão .ads (Ada Source) e correspondem aos .h do C.
O compilador Gnat usa as extensões .adb e .ads enquanto outras implementações poderão usar outras extensões.
Vamos ilustrar o uso desses arquivos criando um package (pacote).
Crie um arquivo de texto com o nome cumprimentos.adb e com seguinte conteúdo.
With Text_IO; Use Text_IO; |
Package body Cumprimentos is |
Procedure Bom_Dia is |
begin |
Put_Line("Bom dia!"); |
end Bom_Dia; |
Procedure Boa_Tarde is |
begin |
Put_Line("Boa tarde!"); |
end Boa_Tarde; |
Procedure Boa_Noite is |
begin |
Put_Line("Boa noite!"); |
end Boa_Noite; |
end Cumprimentos; |
Pronto! Criamos o pacote cumprimentos contendo os procedimentos Bom_dia, Boa_Tarde e Boa_Noite.
Agora precisamos criar um arquivo de "source" chamado cumprimentos.ads. Ele conterá uma relação
das coisas contidas no pacote de "body". Ponha o seguinte:
Package Cumprimentos is |
Procedure bom_dia; |
Procedure boa_tarde; |
Procedure boa_noite; |
end Cumprimentos; |
Observe que no arquivo "source" vai a relação dos procedimentos e funções contidos no arquivo de "body". Cada um delaração indentica a que vai no arquivo "body" a menos do "is" que é substituido por ";". Os arquivos "source" também podem conter declarações de variáveis.
Agora podemos criar um programa que chame esse pacote e use esses procedimentos.
Considere por exemplo o programa saudacao.adb
With Cumprimentos; |
Procedure saudacao is |
begin |
Cumprimentos.bom_dia; |
Cumprimentos.boa_tarde; |
Cumprimentos.boa_noite; |
end saudacao; |
Ou se você preferir usar o "Use"
With Cumprimentos; Use Cumprimentos; |
Procedure saudacao is |
begin |
bom_dia; |
boa_tarde; |
boa_noite; |
end saudacao; |
Daí basta compilar dando gnatmake saudacao.adb (ou as vezes gnat make saudacao.adb).
O gnatmake é esperto! Basta manter os três arquivos no mesmo diretório que ele faz o resto.
Agora é só executar o programa saudacao.
No que diz respeito a declaração de variáveis (quase sempre nescessária) é melhor evitar o conceito de global e local e se ater ao de visível e não visível.
As variáveis declaradas no programa principal NÃO são visíveis para os pacotes. Caso o programa principal compartilhe variaveis com algum pacote tais variaveis devem ser declaradas no referido pacote.
As variáveis declaradas nos arquivos .ads são visíveis para o programa principal e podem ser visíveis para outros pacotes desde que esses outros pacotes nos arquivos de corpo invoquem o primeiro pacote usndo o "use".
Você não deve criar arquivo .ads para o programa principal uma vez que o GnatMake não irá saber quem é o programa principal, tratará o programa principal como um pacote e irá compilar cada pacote semparadamente (claro que Ada suporta compilação em separado) sem linkar ninguém.
26 Manipulando Arquivos
A manipulação de arquivos de texto em Ada 95 é muito simples.
Primeiro devemos declarar uma variável que representará o arquivo perante o programa.
Arquivo_1:File_Type;
Se o arquivo que vamos trabalhar ainda não existe nos o criamos
create(arquivo_1,out_file,"Arquivo_1.txt");
A linha acima cria um arquivo associado a variável arquivo_1 e cujo nome perante o sistema operacional (seja ele qual for) será "Arquivo_1.txt".
Se o arquivo já existir basta abri-lo.
open(arquivo_1,in_file,"Arquivo_1.txt");
Mas atenção, se o arquivo já existir e você usar o create o arquivo será sobrescrito.
Para escrever algo no arquivo usamos o Put fazendo referencia a variável
Pute{arquivo_1,"Isso escreve Alo Mundo!!!!");
Se quizer mudar de linha após ter escrito uma string use o Put_Line.
Se quizer só mudar de linha então faça
New_line(arquivo_1);
Para ler algo do arquivo usamos o Get também com referencia ao arquivo
get(arquivo_1,Variavel);
No exemplo acima o Variavel é uma variável qualquer que lê um dado do seu tipo do arquivo. No fim devemos fechar o arquivo.
close(arquivo_1);
27 Unbounded Strings
Unbouded Strings são um tipo de string que não possui um tamanho determinado. Para lidar com elas podemos usar o pacote "Ada.Strings.Unbounded".
with Ada.Strings.Unbounded; Use Ada.Strings.Unbounded;
Podemos declarar Unbounded Strings como fazemos como qualquer outro tipo de variável.
Frase_Verdadeira : Unbounded_String;
Dai no corpo do programa podemos atribuir um valor para essa unbouded string
Frase_Verdadeira :=To_Unbounded_String("Ada e' legal!!!");
Nesse exemplo fizemos uso da função To_Unbounded_String que pega uma string e converte para
Unbounded.
Ada não possui procedimentos de entrada e saída para as unbounded strings de modo que isso precisa ser feito usando strings comuns. Veja no exemplo abaixo como entramos strings de tamanho desconhecido a partir do teclado usando strings comuns.
With text_IO; Use text_IO; |
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO; |
|
Procedure entre_seu_nome is |
n: natural; |
stringona: string(1..100); |
begin |
Put_Line(" Entre o seu nome. (Ate 100 caracteres)"); |
Get_Line(stringona,n); |
Put_Line("O numero de letras de seu nome e':"); |
Put(n); |
New_Line; |
Put_Line("Seu nome e:"); |
Put(stringona(1..n)); |
Put_Line("Seu nome de traz para frente fica:"); |
for I in reverse 1..N loop |
Put(Stringona(I)); |
end loop; |
|
end entre_seu_nome; |
Nós fomos capazes de entrar seu nome graças ao uso do procedimento Get_Line. Ele lê do teclado preenchendo uma dada string e fornece também o numero de caracteres. É mais ou menos analogo a função gets do C mas é superior pois de cara te dá o tamanho da string entrada. Observe que aqui não se trata de Unbounded Strings mas sim de Strings de tamanho fixo. A idéia é criar strings que sejam suficientemente grandes para poderem receber qualquer tamanho de Unbounded String.
Agora façamos algo parecido já usando as Unbounded Strings.
With Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded; |
Use Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded; |
|
Procedure entre_seu_nome2 is |
n: natural; |
stringona: string(1..100); |
Stringona2,Stringona3: Unbounded_String; |
begin |
Stringona2:=To_Unbounded_String("Ola "); |
Put_Line(" Entre o seu nome. (Ate 100 caracteres)"); |
Get_Line(stringona,n); |
Stringona3:=To_Unbounded_String(Stringona(1..N)); |
Put(To_String(Stringona2)); |
Put_Line(To_String(Stringona3)); |
end entre_seu_nome2; |
Nesse exemplo acima usamos a função To_String para converter de Unbounded para String.
Finalmente uma situação bastante tipica. Você quer criar um arquivo mas quer que a pessoa (usuário do programa) escolha o nome do arquivo. No exemplo que segue cria-se o arquivo e escreve-se uma menssagem nele.
With Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded; |
Use Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded; |
|
Procedure nome_de_arquivos is |
n: natural; |
nome:string(1..100); |
nome2:unbounded_string; |
arquivo:File_Type; |
begin |
Put_Line("Entre o nome do arquivo"); |
Get_Line(nome,n); |
nome2:=To_Unbounded_String(nome(1..N)); |
create(arquivo,out_file,to_string(nome2)); |
Put_Line(arquivo,"Alo gente!!!"); |
close(arquivo); |
end nome_de_arquivos; |
Mas você também pode fazer isso sem usar o tipo unbounded.
With Text_IO, Ada.Integer_Text_IO; |
Use Text_IO, Ada.Integer_Text_IO; |
|
Procedure nome_de_arquivos2 is |
|
n: natural; |
nome:string(1..100); |
arquivo:File_Type; |
|
begin |
Put_Line("Entre o nome do arquivo"); |
Get_Line(nome,n); |
create(arquivo,out_file,nome(1..N)); |
Put_Line(arquivo,"Alo gente!!!"); |
close(arquivo); |
end nome_de_arquivos2; |
Enfim, o tipo unbounded_string é uma opção a mais para te ajudar a lidar
com essas strings de tamanho indefinido, embora haja outras maneiras de
lidar com elas.
28 Ainda Strings
Ada permite que concatenemos strings usando o caracter &.
O seguinte código
Put_Line("Alo " & "voce!!");
gera na saída
Alo voce!!
O programa abaixo ilustra isso inclusive usando o atributo 'Image que representa uma dada variável como se fosse uma string.
With Text_IO, Ada.Integer_Text_IO; |
Use Text_IO, Ada.Integer_Text_IO; |
|
Procedure idade is |
|
Idade, N:Natural; |
Nome:String(1..90); |
|
begin |
|
Put_Line("Qual e'" & " seu nome?"); |
Get_Line(Nome,n); |
Put_Line("Quantos anos voce tem?"); |
Get(Idade); |
Put("Voce " & Nome(1..N) & " tem " & Natural'Image(idade) & " anos."); |
New_Line; |
end idade; |
Se idade for um natural igual a 25 Natural'Image(idade) será a string " 25".
29 Novos Tipos e Subtipos
Para criar um novo tipos basta usar na declaração do programa o comando type. Dai você coloca o nome do tipo seguindo de "is" e ai você coloca a especificação do tipo.
Ex:
type segundo is range 1 .. 60;
type sinal is (verde, amarelo, vermelho);
O tipo sinal que declaramos é um exemplo dos chamados tipos de enumeração. O tipo pré-definido boolean também é desse tipo.
Já Subtipos são tipos que são constituidos de uma parte dos elementos de outro tipo.
Veja o programa a seguir.
With Ada.Text_IO; Use Ada.Text_IO; |
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO; |
|
Procedure Mostra_Tipos is |
|
type Dia_Do_Ano is range 1 .. 365; |
type Ano is range 1_900 .. 2_100; |
type Dia_Da_Semana is (Domingo,Segunda,Terca,Quarta,Quinta,Sexta,Sabado); |
subtype Dia_Util is Dia_Da_Semana range Segunda .. Sexta; |
type Quase_Booleano is (True, False, I_Dont_Know); |
|
N:Dia_Do_Ano; |
Folga: Dia_Da_Semana; |
Esse_Programa_funciona: Quase_Booleano; |
|
begin |
|
N:=2; |
Folga:=Terca; |
Esse_Programa_funciona:=I_Dont_Know; |
|
end Mostra_Tipos; |
30 Registros
Registros são tipos formados pela união de outros tipos mais simples.
Ex:
type Aluno is record |
Nome:Unbounded_String; |
Idade:integer range 1 .. 99; |
Nota:integer range 0 .. 100; |
end record ; |
Depois podemos criar uma variável chamada João do tipo aluno.
Joao:Aluno;
E podemos atribuir valores para essa variável.
Joao.Nome:=To_Unbounded_String("Joaozinho da Silva");
Joao.Idade:=15;
Joao.Nota:=70;
Veja como poderia ficar o programa completo
With Ada.Text_IO, Use Ada.Text_IO; |
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO; |
With Ada.Strings.Unbounded; Use Ada.Strings.Unbounded; |
|
Procedure mostra_registro is |
|
type Aluno is |
record |
Nome:Unbounded_String; |
Idade:integer range 1 .. 99; |
Nota:integer range 0 .. 100; |
end record ; |
|
Joao:Aluno; |
|
begin |
|
Joao.Nome:=To_Unbounded_String("Joaozinho da Silva"); |
Joao.Idade:=15; |
Joao.Nota:=70; |
|
end mostra_registro; |
|
31 Gerador de Números Aleatórios
Gerar números aleatórios pode ser algo muito importante e Ada nos ajuda a fazer isso sem que tenhamos que re-inventar a roda.
With Ada.Numerics.Float_Random, Text_IO, Ada.Float_Text_IO; |
Use Ada.Numerics.Float_Random, Text_IO, Ada.Float_Text_IO; |
|
Procedure Randonico is |
G: Generator; |
Saida:Float; |
begin |
Reset (G); --Linha a |
|
Saida:=Random(G); --Linha b |
Put(Saida); --Linha c |
New_Line; --Linha d |
|
end Randonico; |
Esse programa usa o pacote Ada.Numerics.Float_Random que possui a função Random. Ela pega uma variável do tipo generator, tipo esse declarado no mesmo pacote, e resulta num número entre 0 e 1. Para entender o que é o Reset faça o seguinte. Comente a linha 'a' e repita uma ou duas vezes as linhas de 'b' até 'd'. Ada também permite que se crie valores discretos aleatórios o que na minha opinião não seria preciso. O leitor interessando deve ver o RM para isso.
32 Números com ponto flutuante e ponto fixo.
O tipo float é um tipo real de ponto flutuante sendo que uma variável X declarada como X: float:=2.0; apareceria na tela ao darmos put(x) como algo tipo 2.00000E+00. Nós podemos no entanto mudar a precisão de digitos criando novos tipos.
type pontoflutuante8 is digits 8;
Isso acima cria um tipo de ponto flutuante de 8 digitos.
Podemos também criar tipos de ponto fixo.
type nota is delta 0.1 range 0.0 .. 10.0;
ou mesmo algo tipo
type temperatura is delta 0.1 digits 2;
O primeiro cria um tipo nota que varia de 0 a 10 com um intervalo de 0.1. O segundo cria um tipo dito temperatura que vai de -100 até 100 variando de 0.1 em 0.1.
O programa abaixo ilustra varias maneiras de se escrever o número 2.
With Text_IO, Ada.Float_Text_IO; |
Use Text_IO, Ada.Float_Text_IO; |
|
Procedure fixoflutuante is |
|
type Pflutuante4 is digits 4; |
type Pflutuante9 is digits 9; |
type fixo is delta 0.1 range -3.0 .. 3.0; |
|
F2:Pflutuante4; |
F9:Pflutuante9; |
Pf:Fixo; |
|
begin |
|
F2:=Pflutuante4(2.0); |
F9:=Pflutuante9(2.0); |
Pf:=Fixo(2.0); |
|
Put_Line(Pflutuante4'Image(F2)); |
Put_Line(Pflutuante9'Image(F9)); |
Put_Line(Fixo'Image(Pf)); |
|
end fixoflutuante; |
Veja que usamos o atributo 'Image, que representa a variável como uma string, para podermos imprimir usando o put uma vez que os novos tipos são incompativeis com o mesmo e uma conversão para float arruinaria a formatação.
A saída gerada por esse programa é
2.000E+00
2.00000000E+00
2.0
33 Goto.
Ada permite o uso do goto. No programa abaixo ilustramos seu uso.
With Text_IO; Use Text_IO; |
|
Procedure vaipara is |
x:integer:=1; |
begin |
|
<< inicio >> |
|
Put_Line("Nao use isso!!!!"); |
x:=x+1; |
|
if x < 30 then goto inicio; end if; |
|
end vaipara; |
|
34 Access Type.
Imagine que uma dada variável não guarde um valor em si mas sim uma referencia para outra variável. Esse tipo de variável é chamada de Access Type em Ada ou ponteiros em C e é algo mais ou menos parecido com os links nos sistemas operacionais.
Uma diferença entre os Access Types e os ponteiros do C é que em Ada não é permitida aritimética com os mesmos.
Ada também pode criar Access Types não apenas para variaveis mas também para subprogramas o que foge o nosso escopo.
O exemplo abaixo mostra como os Acces Types funcionam.
With Ada.Integer_Text_IO; |
Use Ada.Integer_Text_IO; |
|
Procedure Ponteiros1 is |
|
type Integer_Ponteiro is access Integer; |
Numero: Integer:=10; |
Link1,Link2 : Integer_Ponteiro; |
|
begin |
|
Link1 := new Integer; |
Link2 := new Integer; |
|
Link1.all:=Numero; --O link1 aponto para numero. |
Link2.all:=Link1.all; --O link2 recebe o valor de link1. |
|
Put(numero); |
Put(Link1.all); |
Put(Link2.all); |
|
end Ponteiros1; |
Você também pode criar ponteiros gerais desde que as variáveis sejam Aliased.
O tipo geral é identificado pela palavra All na declaração.
With Ada.Integer_Text_IO; |
Use Ada.Integer_Text_IO; |
|
Procedure Ponteiros2 is |
|
type Integer_Ponteiro1 is access Integer; |
type Integer_Ponteiro2 is access all Integer; |
|
A: Integer:=10; |
B: aliased Integer :=10; --B e' aliased. |
|
Link1: Integer_Ponteiro1; |
Link2: Integer_Ponteiro2; |
|
begin |
|
Link1:=new Integer; |
Link1.all:=A; --Link1 e' um ponteiro comum. |
Put(Link1.all); |
|
Link2:=B'Access; --Link2 e' um ponteiro geral. |
Put(Link2.all); |
|
end Ponteiros2; |
Mas você poderia perguntar: Para que isso tudo serve?
Bom, uma das muitas aplicações dos ponteiros ou access types é quando estamos trabalhando com algo de tamanho desconhecido. Suponha que tenhamos um jogo de tabuleiro qualquer e usamos aquele programa de
números aleatórios para escolher a jogada. Aquele programa não saberia o
"tamanho livre" do tabuleiro. Pode ser que uma jogada escolhida já tivesse sido
feita. O que você sugere?? Chamar o gerador de numeros aleatórios de novo
usando um goto? NUNCA! Uma solução é usar os ponteiros ou access types. Quando
uma jogada fosse feita o ponteiro para aquela jogada apontaria para uma outra que
ainda não tivesse sido feita e dai quando aquela jogada fosse chamada iria para
outra. Simples né?
35 Generics
Suponha que você tenha que fazer um pacote contendo uma função que deverá receber 3 variaveis inteiras e retornar verdadeiro se duas forem iguais e falso caso as três sejam iguais ou as três diferentes (poderia ser util num joguinho da velha). Depos pedem para você fazer o mesmo só que com variaveis do tipo float. O que você faria? Conversão de tipos? Ao converter de float para inteiro devido ao arredondamento o resultado da função seria falseado. E se depois pedissem para você fazer para caracteres, strings, etc? Você faria tudo de novo cada vez?
Ada resolve esse problema para você permitindo a criação de pacotes genéricos. Você cria um pacote genérico que trabalhe com um tipo genérico e quando precisar usar você especifica o tipo que lhe interessa e a isso dão o nome de 'instantiation'.
Por exemplo, podemos criar um pacote genérico como
--generic_doisiguais.adb |
Package body Generic_Doisiguais is |
|
Function Generic_Sao2iguais(A,B,C: in algum_tipo) return Boolean is |
Resultado:Boolean; |
begin |
Resultado:=False; |
if A=B or B=C or A=C then Resultado:=True; end if; |
if A=B and B=C then Resultado:=False; end if; |
return Resultado; |
end Generic_Sao2iguais; |
|
end Generic_Doisiguais; |
e para o qual tenhamos a declaração
--generic_doisiguais.ads |
package Generic_Doisiguais is |
generic type algum_tipo is private; |
Function Generic_Sao2iguais(A,B,C: in algum_tipo) return Boolean; |
end Generic_Doisiguais; |
Dai podemos criar um programa que use isso fazendo a 'instantation'. No exemplo a seguir usamos o tipo integer.
--usa2iguais.adb |
With Ada.Integer_Text_IO, Generic_Doisiguais, Text_IO; |
Use Ada.Integer_Text_IO, Generic_Doisiguais, Text_IO; |
|
Procedure Usa2iguais is |
|
Function Sao2iguais is new Generic_sao2iguais(Integer); |
Resposta: Boolean; |
|
begin |
|
Resposta:=Sao2iguais(2,2,3); --Experimente mudar os valores. |
Put(Boolean'Image(Resposta)); |
|
end Usa2iguais; |
No exemplo acima criamos a função Sao2iguais como sendo a função Generic_sao2iguais com o tipo integer. Poderiamos fazer isso para qualquer outro tipo.
36 Maiúsculas e Minúsculas
Exemplo:
With Ada.Strings.Maps.Constants; |
With Ada.Strings.Fixed; |
With Text_IO; |
|
Use Text_IO; |
|
Procedure Maisculas_E_Minusculas is |
String1 : String := "Alo Mundo!"; |
String2,String3 : String(1..10); |
begin |
|
-- Converte para maiusculas. |
String2:=Ada.Strings.Fixed.Translate(String1, |
Ada.Strings.Maps.Constants.Upper_Case_Map); |
|
-- Converte para minusculas. |
String3:=Ada.Strings.Fixed.Translate(String1, |
Ada.Strings.Maps.Constants.Lower_Case_Map); |
|
-- Imprime as tres strings. |
Put_Line(String1); |
Put_Line(String2); |
Put_Line(String3); |
|
end Maisculas_E_Minusculas; |
37 Ada.Numerics.Elementary_Functions
O pacote Ada.Numerics.Elementary_Functions é a versão para o tipo float do pacote genérico Ada.Numerics.Generic_Elementary_Functions.
De acordo com o Ada95 Reference Manual temos as seguinte funções nesse pacote.
Sqrt Arctan Log Arccot
Exp Sinh ** Cosh
Sin Coth Cos Arcsinh
Tan Arccosh Cot Arctanh
Arcsin Arccoth Arccos
Para as funções trigonométricas o ângulo é em principio em radianos.
Podemos também especificar outra medida de ângulo pondo o equivalente a uma revolução inteira.
Ex:
sin(0.7853)
é o mesmo que
sin(45.0,360.0)
A função sqrt é a raiz quadrada enquanto **continua sendo a potenciação só que agora todos os numeros devem ser do tipo float.
Log é o logaritimo natural (base e), a não ser que outra base seja especificada.
Você também pode usar outras versões não genéricas para outros intervalos do tipo float como por exemploNumerics.Short_Elementary_Functions, Numerics.Long_Elementary_Functions e assim por diante.
A seguir um pequeno programa exemplo.
With Ada.Float_Text_IO,Ada.Numerics.Elementary_Functions; |
Use Ada.Float_Text_IO,Ada.Numerics.Elementary_Functions; |
|
Procedure Funcoes_numericas is |
A,B,C,D,E,F,G:Float; |
begin |
|
A:=3.0**2.0; |
--3 ao quadrado |
B:=2.0**0.5; |
--Raiz de 2 = 1.4142. |
C:=Sqrt(100.0); |
--Raiz de 100. |
D:=Sin(3.141592); |
--Aproximadamente seno de Pi. |
E:=Sin(180.0,360.0); |
--Seno de Pi. |
F:=Log(Exp(5.0)); |
--5.0 |
G:=Log(10000.0,10.0); |
--Logaritimo decimal de 10000 |
|
Put(A); |
Put(B); |
Put(C); |
Put(D); |
Put(E); |
Put(F); |
Put(G); |
|
end Funcoes_numericas; |
38 Números Complexos
Para trabalhar com números complexos podemos usar o pacote Ada.Numerics. Complex_Types. Um número complexo pode ser declarado como do tipo complex o qual tem ambas as compontentes do tipo real. Para atribuir um valor podemos usar parentezes e para receber o valor de um número complexo podemos usar os atributos .Re e .Im.
Ex:
With Ada.Float_Text_IO, Ada.Numerics.Complex_Types; |
Use Ada.Float_Text_IO, Ada.Numerics.Complex_Types; |
|
Procedure Complexos is |
|
A,B,S,P: Complex; |
|
begin |
|
A:=(2.3,3.4); |
B:=(1.0,1.0); |
|
S:=A+B; |
P:=A*B; |
|
Put(S.Re); |
Put(S.Im); |
|
Put(P.Re); |
Put(P.Im); |
|
end Complexos; |
39 Exceptions
A linguagem Ada permite o tratamento de Exceptions que são erros que aparecem quando o programa se defronta com uma situação inesperada. Em geral tais erros provacam a interrupção indesejada do programa. Com o tratamento de exceptions a interrupção pode ser evitada e pode-se contornar o problema. Ada permite que o programador declare suas próprias exceptions mas aqui iremos nos limitar a interceptar as exceptions pré-defidas. Algumas das exceptions pré-definidas que aparecem no pacote Ada.Exceptions e também no próprio pacote text_IO são: Constraint_Error, Program_Error, Storage_Error, Name_Error, etc.
Exemplo: Considere o programa Mytype que pega um arquivo e exibe o conteudo no console:
With Text_IO; Use Text_IO; |
|
Procedure mytype is |
File : File_Type; |
N : Natural; |
File_name : String(1..99); |
MyString : String(1..999); |
begin |
|
Put("Enter the file name: "); |
Get_Line(File_Name,N); |
|
Open(File,In_File,File_Name(1..N)); |
while not End_of_file(File) loop |
Get_Line(File, MyString, N); |
Put_Line(MyString(1..N)); |
New_Line; |
end loop; |
Close(File); |
end mytype; |
Se entrarmos o nome de um arquivo que não existe aparecerá a menssagem:
raised ADA.IO_EXCEPTIONS.NAME_ERROR
Com o uso de exception podemos ensinar ao programa o que ele deve fazer nessa situação.
Nesse caso o programa poderia ser melhor escrito na seguinte forma:
With Text_IO; Use Text_IO; |
|
Procedure mytype is |
File : File_Type; |
N : Natural; |
File_name : String(1..99); |
MyString: String(1..999); |
|
Procedure open_file is |
begin |
Put("Enter the file name: "); |
Get_Line(File_Name,N); |
Open(File,In_File,File_Name(1..N)); |
exception |
when |
NAME_ERROR = > Put_Line("File not found!"); |
open_file; --Uma chamada recursiva. |
end open_file; |
|
begin |
open_file; |
while not End_of_file(File) loop |
Get_Line(File, MyString, N); |
Put_Line(MyString(1..N)); |
New_Line; |
end loop; |
Close(File); |
end mytype; |
Nesse caso a palavra chave exception (que deve ficar após a sequencia normal de comandos), inicia a parte do programa que atua caso um erro ocorra. No caso exibe uma mensagem de advertencia e executa novamente o mesmo procedimento através de uma chamada recursiva sem que o programa seja interrompido.
40 Importando funções de outras linguagens
A linguagem Ada 95 permite complexas interfaces com C, FORTRAN e COBOL, sendo que o compilador GNAT permite interface com C++ também. Uma coisa simples de se fazer no entanto é importar funções. O pequeno exemplo a seguir mostra isso com C e FORTRAN.
Exemplo:
Procedure Uso_do_Import is |
|
Procedure minha_printf (x:string); |
Pragma Import (C, minha_printf, "printf"); |
|
Procedure minha_write (x:string); |
Pragma Import (Fortran,minha_write,"write"); |
|
begin |
minha_printf("Alo Mundo!!!!"); |
minha_write("Alo Brasil!!!"); |
|
end Uso_do_Import; |
|