INF1018 - Software Básico - 2010.2

Segundo Trabalho

Gerador de Funções

O objetivo deste trabalho é implementar uma função create_func que é capaz de gerar em tempo de execução uma nova função a partir de uma outra função já existente. Para isso, create_func deve receber como parâmetros uma função f qualquer (um ponteiro de função em C) e uma string descrevendo os tipos de seus parâmetros e valor de retorno. A função create_func deve então gerar uma nova função que, quando chamada, recebe como parâmetro um vetor com os parâmetros a serem passados para f, chama a função f, e armazena o valor de retorno de f no mesmo vetor dos parâmetros.

A função create_func deve ter o seguinte protótipo:

   DynCall create_func (void* f, const char* signature);
onde o parâmetro f é um ponteiro para uma função já existente e o parâmetro signature descreve a assinatura de f (veja aqui como é feita essa descrição). O valor de retorno de create_func é um ponteiro para a função gerada dinamicamente, e o tipo ponteiro para função DynCall é definido como:
   typedef void (*DynCall) (Any* params); /*ponteiro para funções que recebem um vetor de Any
                                            como parâmetro, sem valor de retorno*/
e Any é definido como:
   typedef union {
      int i;
      char c;
      double d;
      float f;
      void* p;
   } Any;
As funções geradas por create_func recebem como parâmetro um vetor com os parâmetros que devem ser passados para a função f. A primeira posição desse vetor (índice 0) é sempre reservada para o valor de retorno de f, mesmo que f não tenha valor de retorno. Os parâmetros a serem passados para f começam a partir da segunda posição do vetor, obedecendo a ordem em que eles aparecem na assinatura de f.

Também deve ser implementada a função

   void free_func (DynCall func);
que é responsável por liberar uma função criada dinamicamente.

A função create_func deve ser implementada em C, mas ela deve gerar, em uma área de memória, um trecho de código em linguagem de máquina que implementa a função criada dinamicamente. De forma geral, create_func irá percorrer a string com a descrição da assinatura da função original e gerar um código em linguagem de máquina que:

Descrição da Assinatura de uma Função

As assinaturas das funções passadas para create_func serão descritas através de strings, onde os tipos dos parâmetros e do valor de retorno serão indicados por um caractere da seguinte forma: Primeiro devem ser indicados os tipos dos parâmetros e depois o do valor de retorno, caso haja algum. O caractere indicando o tipo do valor de retorno deve ser precedido pelo caractere '>'. Veja a seguir alguns exemplos de codificação de assinatura de funções:

Exemplo

Considere a função

   double pow (double x, double y);
definida em math.h. O trecho de programa a seguir cria dinamicamente uma função que recebe os parâmetros para a função pow através de um array. Essa função é usada para calcular os quadrados de 0 a 10.
   #include <math.h>
   #include <stdio.h>
   #include "dyncall.h"

   int main (void) {
      int i;
      Any params[3];
      DynCall f = create_func(pow,"dd>d");
   
      params[2].d = 2.0;  /* todos os numeros serao elevados ao quadrado */
      for (i = 0; i <= 10; i++) {
         params[1].d = i;
         f(params);
         printf("%.0f^%.0f = %.0f\n",params[1].d,params[2].d,params[0].d);
      }
      free_func(f);
      return 0;
   }   
Nesse exemplo, create_func cria em tempo de execução uma nova função baseada na função pow. Essa nova função recebe os parâmetros para pow nas posições de índice 1 e 2 do vetor params, e armazena na posição de índice 0 do vetor params o resultado de pow. A seguir ilustramos através de um código equivalente em C como deveria ser o código em linguagem de máquina gerado por create_func nesse caso:
   void df (Any* v) {
      v[0].d = pow(v[1].d, v[2].d);
   }

Prazo

O trabalho deve ser entregue no dia 22 de novembro de 2010 (até a meia noite).

Observações: