Ir para o conteúdo

Procedimentos e Funções encadeados

Após ver a existência de pessoal que estava a converter código minimamente bom num código esparguete cheio de Gotos, decidi mostrar uma das maravilhas do Pascal.

Os procedimentos e funções podem-se chamar uns aos outros, mas muitas vezes damos por nós a criar procedimentos ou funções que só são necessários para um(a) outro/a. Para este caso, podemos criar o procedimento, ou a função, dentro do próprio procedimento/função que o necessitar! Este não será acessível ao resto do programa e outros procedimentos e funções que não sejam aquele que o contém.

Bem, isto já parece algo confuso. Um exemplo prático irá esclarecer bem o assunto.

Imaginemos que queremos um procedimento que escreve um texto convertido. A conversão consiste em transformar cada caracter no seu terceiro sucessor. Isto é, A será D, e X será A. Ou seja, quando o caracter é Z, o seu sucessor directo é A (X > Y (1º) > Z (2º) > A (3º)).

Criemos então um procedimento, Escrever, que recebe como argumento o texto a converter, obtido por leitura do utilizador. Este procedimento vai depender um conversor, uma função que recebe o texto a converter e o converte. O seu nome será original, Conversor. :-D Mas o conversor irá depender de uma outra função que lhe irá dar directamente o terceiro sucessor de um caracter. Sendo Succ a função padrão que dá o sucessor directo, o nome da função que devolve o terceiro sucessor será Succ3.

Numa árvore, temos o seguinte:

  • Programa Principal
    • Escrever
      • Conversor
        • Succ3

Aqui vê-se que o programa principal pode aceder a Escrever, mas não pode aceder a Conversor nem a Succ3. Escrever pode aceder a Conversor, mas não a Succ3. Conversor pode aceder a Succ3.

Vemos, então, que cada procedimento/função só pode aceder a outros procedimentos/funções que estejam directamente na sua linha de hierarquia ou na seguinte. As superiores são-lhes inacessíveis.

Basta pensar em cada procedimento e função como um pequeno programa com os seus procedimentos e funções. Outro programa externo não pode aceder directamente a esses procedimentos e funções — são seus e não de outrém.

Assim sendo, e dando por terminada a teoria, segue-se a implementação prática.

Em comentário entre {} está o nome do procedimento ou da função a que cada Begin/End se refere para evitar confusões.

{$MODE Delphi}
PROGRAM ProcFuncEx;
VAR Txt : string[80];

PROCEDURE Escrever(const Texto : string[80]);
(* Escreve "Texto" com os seus caracteres convertidos nos seus terceiros sucessores *)

    function Conversor(const Linha : string[80]) : string;
    (* Debita "Linha" convertida, cujos caracteres são os seus terceiros sucessores *)
    var i : byte;
        Resultado : string[80];

        function Succ3(const Caracter : char) : char;
        (* Função que calcula o terceiro sucessor *)
        var Res : char;
            j : 1..3;
        begin {Succ3}
             Res := Caracter;
             for j:=1 to 3 do begin // Terceiro sucessor
                 Res := Succ(Res);
                 if (ord(Res) > Ord('Z')) then Res := 'A'; // Evita caracteres não alfanuméricos
             end;

             Result := Res; // Output da função
        end; {Succ3}

    begin {Conversor}
         Resultado := ''; // Inicia a String

         // Converte caracter a caracter
         for i:=1 to length(Linha) do Resultado := Resultado + Succ3(Linha[i]);

         Result := Resultado; // Output da função
    end; {Conversor}

begin {Escrever}
     // Debita o texto, em maiúsculas, convertido, recorrendo ao Conversor
     writeln(Conversor(UpCase(Texto)));
end; {Escrever}

BEGIN (* Bloco Principal *)
     repeat
           Write('Txt? '); ReadLn(Txt);
           Escrever(Txt); // debita texto convertido
           WriteLn; // parágrafo em branco
     until (UpCase(Txt) = 'SAIR');
END.