2605 - Linguagens Imperativas e Orientadas por Objectos Ano Lectivo 2002/2003 Relatório do Exame Nº 1 Este relatório reproduz o texto do exame na íntegra, adicionado das resposta em itálico. Instruções Este exame têm três grupos, com a cotações relativas indicadas entre parêntesis. Cada grupo têm uma ou mais questões. As questões são numeradas a partir de 1 até ao fim do teste. Responda a cada questão no espaço imediatamente a seguir ao respectivo enunciado. Se precisar de mais espaço utilize a última página, identificando a questão. Ao escrever código, utilize letras separadas (não cursivas), seja cuidadoso com os símbolos e.g. distinga bem o hífen (-) da sublinha (_), e espaceje bem os elementos lexicais entre si. Distinga bem entre código e texto normal, se a sua resposta contiver ambos. Dê respostas concisas e claras. Pode usar abreviaturas para as palavras-chave muito frequentes, e.g. proc (procedure), func (function), ret (return), alistando-as no fim. Não aborde os vigilantes sobre o texto do exame. Se detectar alguma ambiguidade ou gralha, resolva-a individualmente, incluindo essa resolução na sua resposta. I. Ada (50%) 1. Escreva, em Ada, o programa Olá Mundo. (O programa Olá Mundo é um programa cujo comportamento se resume a escrever "Olá, mundo!" na saída de dados padrão.) with Ada.Text_IO; procedure Olá_Mundo is begin Ada.Text_IO.Put_Line ("Olá, mundo!"); end; 2. Defina a classe de derivação Pessoa : :..Amigo : :..Colega tal que: toda pessoa tem um nome uma pessoa concreta é ou um amigo ou um colega os amigos são saudados por "ôi" e os colegas por "bom dia" 1 Usando class wide programming, defina uma colecção de pessoas, contendo pelo menos um amigo e um colega, e saúde todas as pessoas da colecção. Escreva o resultado esperado do programa. package Pessoas is type String_Ptr is access String; type Pessoa is abstract tagged record Nome : String_Ptr; end record; procedure Saudar (X : Pessoa) is abstract; type Pessoa_Ptr is access Pessoa'Class; type Amigo is new Pessoa with null record; procedure Saudar (X : Amigo); type Colega is new Pessoa with null record; procedure Saudar (X : Colega); end; ----with Ada.Text_IO; use Ada.Text_IO; package body Pessoas is procedure Saudar (X : Amigo) is begin Put_Line ("ôi, " & X.Nome.all); end; procedure Saudar (X : Colega) is begin Put_Line ("bom dia, " & X.Nome.all); end; end; ----with Pessoas; use Pessoas; procedure Saudar_Pessoas is Pessoas_Conhecidas : array (1 .. 2) of Pessoa_Ptr := (1 => new Amigo' (Nome => new String' ("Zé" )), 2 => new Colega' (Nome => new String' ("Sr. Fonseca"))); begin for I in Pessoas_Conhecidas'Range loop Saudar (Pessoas_Conhecidas (I).all); end loop; 2 end; Resultado esperado: ôi, Zé bom dia, Sr. Fonseca 3. Especifique um pacote genérico que fornece listas. Uma lista é uma sequência variável de elementos. Os elementos podem ser adicionados ao princípio ou ao fim da lista, ou imediatamente antes ou depois de qualquer elemento existente. Qualquer elemento pode ser removido. Tem que haver um meio de aceder a todos os elementos. Escreva um exemplo de utilização do pacote, e o resultado esperado. generic type Elemento is private; package Listas is type Lista is private; type Posição is private; function Primeiro (L : Lista) return Posição; function Último (L : Lista) return Posição; function Seguinte (P : Posição) return Posição; function Anterior (P : Posição) return Posição; function Valor_Elementar (P : Posição) return Elemento; procedure Adicionar_Antes (L : in out Lista ; P : Posição; E : Elemento); procedure Adicionar_Depois (L : in out Lista ; P : Posição; E : Elemento); procedure Remover (L : in out Lista ; Q : Posição); Posição_Nula_Mas_Lista_Não_Vazia : exception; private type Lista is record Primeiro : Posição; Último : Posição; end record; type Nó is record Carga : Elemento; Seguinte : Posição; Anterior : Posição; end record; type Posição is access Nó; end; ----with Ada.Text_IO; with Listas; procedure Listest is package Listas_C is new Listas (Character); use Listas_C; L : Lista; procedure Ver_Lista is use Ada.Text_IO; I : Posição := Primeiro (L); begin Put ('['); loop Put (Valor_Elementar (I)); I := Seguinte (I); 3 end loop; exception when others => Put_Line ("]"); end; begin Ver_Lista; Adicionar_Depois (L, Último (L), 'a'); Ver_Lista; Adicionar_Depois (L, Último (L), 'b'); Ver_Lista; Adicionar_Depois (L, Último (L), 'c'); Ver_Lista; Remover (L, Último (L)); Ver_Lista; Remover (L, Último (L)); Ver_Lista; Remover (L, Último (L)); Ver_Lista; end; Resultado esperado de Listest: [] [a] [ab] [abc] [ab] [a] [] II. Smalltalk (20%) 4. Escreva o programa Olá Mundo em Smalltalk. (Pode usar o Transcript como saída padrão.) Transcript show: 'Olá, mundo!' 5. O protocolo da class Object (o topo da hierarquia de classes do sistema Smalltalk) inclui as seguintes mensagens: isMemberOf: aClass Responde o valor booleano do facto do receptor ser uma instância da classe especificada. class Responde a classe do receptor. Implemente o método isMemberOf:, utilizando class. isMemberOf: aClass "Responde o valor booleano do facto do receptor ser uma instância da classe especificada." ^ self class == aClass 6. Acrescentámos ao protocolo da classe Float a mensagem hipotenusa: outroCateto com o comportamento esperado. Implemente o respectivo método. hipotenusa: outroCateto "Responde a hipotenusa especificado." correspondente 4 ao receptor e ao cateto ^ ((self ** 2) + (outroCateto ** 2)) sqrt 7. Descreva o resultado da avaliação das seguintes expressões em Smalltalk: 2 * 3 + 6 (2 * 3) + 6 2 * (3 + 6) 2 + 3 * 6 (2 + 3) * 6 2 + (3 * 6) -> -> -> -> -> -> 12 12 18 30 30 20 III. Linguagem à escolha (30%) 8. Considere a pequena linguagem imperativa Li dedicada exclusivamente a números inteiros. Li tem literais, três variáveis prédeclaradas A, B, C, e as operações de afectação (assignment), soma, multiplicação e entrada/saída de dados. Escolha Ada ou Smalltalk, e conceba uma maneira de representar e executar programas em Ic. Escreva um programa de teste, e o resultado esperado. Use técnicas de orientação por objectos, ou justifique porque não. Escolho Ada. O pacote Lilib fornece meios de representação e execução de programas Li: package Lilib is type Variable is (A,B,C); type Expression is private; function Literal (Value : Integer) return Expression; function Name (Name : Variable) return Expression; function "+" (L, R : Expression) return Expression; function "*" (L, R : Expression) return Expression; type Statement is private; function Assign (Name : Variable ; X : Expression) return Statement; function Write (X : Expression) return Statement; function Read (Name : Variable) return Statement; type Program is array (Positive range <>) of Statement; procedure Execute (P : Program); private type Expression_Root is abstract tagged null record; function Value (X : Expression_Root) return Integer is abstract; type Expression is access all Expression_Root'Class; type Statement_Root is abstract tagged null record; procedure Execute (S : Statement_Root) is abstract; type Statement is access all Statement_Root'Class; end; A utilização deste pacote é exemplificada pelo seguinte programa de teste: with Lilib; use Lilib; procedure Litest is 5 begin Execute (( Write (Literal (1)), Write (Literal (2)), Assign (A, Literal (3)), Write (Name (A)), Assign (B, Name (A) + Literal (4)), Write (Name (B)), Write (Literal (2) * Literal (2)) )); end; Resultado esperado: 1 2 3 7 4. Implementação do pacote Lilib: with Ada.Streams.Stream_IO; with Ada.Text_IO; with GNAT.IO_Aux; package body Lilib is --> LITERAL EXPRESSION type Literal_Expression is new Expression_Root with record Value : Integer; end record; function Value (X : Literal_Expression) return Integer; --> NAME EXPRESSION type Name_Expression is new Expression_Root with record Name : Variable; end record; function Value (X : Name_Expression) return Integer; --> SUM EXPRESSION type Sum_Expression is new Expression_Root with record Left, Right : Expression; end record; function Value (X : Sum_Expression) return Integer; --> PRODUCT EXPRESSION type Product_Expression is new Expression_Root with record Left, Right : Expression; end record; function Value (X : Product_Expression) return Integer; --> ASSIGN STATEMENT 6 type Assign_Statement is new Statement_Root with record Name : Variable; X : Expression; end record; procedure Execute (S : Assign_Statement); --> WRITE STATEMENT type Write_Statement is new Statement_Root with record X : Expression; end record; procedure Execute (S : Write_Statement); --> READ STATEMENT type Read_Statement is new Statement_Root with record Name : Variable; end record; procedure Execute (S : Read_Statement); --> EXPRESSION METHOD BODIES Store : array (Variable) of Integer; function Value (X : Name_Expression) return Integer is begin return Store (X.Name); end; function Value (X : Literal_Expression) return Integer is begin return X.Value; end; function Value (X : Sum_Expression) return Integer is begin return Value (X.Left.all) + Value (X.Right.all); end; function Value (X : Product_Expression) return Integer is begin return Value (X.Left.all) * Value (X.Right.all); end; --> EXPRESSION CONSTRUCTOR BODIES function Name (Name : Variable) return Expression is begin return new Name_Expression' (Name => Name); end; function Literal (Value : Integer) return Expression is begin return new Literal_Expression' (Value => Value); 7 end; function "+" (L, R : Expression) return Expression is begin return new Sum_Expression' (L, R); end; function "*" (L, R : Expression) return Expression is begin return new Product_Expression' (L, R); end; --> STATEMENT CONSTRUCTOR BODIES function Assign (Name : Variable ; X : Expression) return Statement is begin return new Assign_Statement' (Name, X); end; function Write (X : Expression) return Statement is begin return new Write_Statement' (X => X); end; function Read (Name : Variable) return Statement is begin return new Read_Statement' (Name => Name); end; --> STATEMENT METHOD BODIES procedure Execute (S : Assign_Statement) is begin Store (S.Name) := Value (S.X.all); end; procedure Execute (S : Write_Statement) is begin Ada.Text_IO.Put (Integer'Image (Value (S.X.all))); end; procedure Execute (S : Read_Statement) is begin Store (S.Name) := Integer'Value (GNAT.IO_Aux.Get_Line); end; --> PROGRAM METHOD BODY procedure Execute (P : Program) is begin for I in P'Range loop Execute (P (I).all); end loop; end; end; 8