Asignatura: Entornos de Programación

Ejemplos de funciones de un entorno de programación


Producto: GNAT (compilador de Ada)

Este producto incluye el compilador de Ada/C++ y herramientas básicas (gcc, gnatbind, gnatlink), y además una colección de utlidades complementarias (gnatmake, gnatstub, gnatmetric, etc.).

Comprobación de sintaxis
La opción de compilación  ... -gnats ...  sólo comprueba la sintaxis, no genera código objeto.
Comprobación de estilo
La opción de compilación  ... -gnaty ...  comprueba determinadas reglas de estilo de codificación.
Compilación de ficheros individuales
La opción de compilación  ... -c ...  compila y genera código objeto, pero no el programa ejecutable.
Montaje del programa ejecutable
La orden  gnatmake programa  compila sólo lo necesario y genera el programa ejecutable.
La orden  gnatmake -f programa  es como la anterior, pero recompila todos los ficheros, anque ya estuvieran compilados.

A continuación se presenta un extracto de la ejecución de estas órdenes.

C:\ASIG\Ejemplos\ajustar.ada>gnatmake -gnaty ajustar
gcc -c -gnaty ajustar.adb
ajustar.adb:2:04: (style) space required
ajustar.adb:3:04: (style) space required
...
gcc -c -gnaty palabra.adb
palabra.adb:7:04: (style) space required
palabra.adb:26:04: (style): subprogram body has no previous spec
palabra.adb:56:22: (style) space not allowed
...
gcc -c -gnaty parrafo.adb
parrafo.adb:19:80: (style) this line is too long
...
gcc -c -gnaty linea.adb
linea.adb:17:33: (style) bad casing of "Text_IO" declared at a-textio.ads:51
linea.adb:36:23: (style) bad casing of "Numpalab" declared at linea.ads:61
linea.adb:62:16: (style) space required
linea.ads:36:80: (style) this line is too long
...
gnatbind -x ajustar.ali
gnatlink ajustar.ali

C:\ASIG\Ejemplos\ajustar.ada>gnatmake ajustar
gnatmake: "ajustar.exe" up to date.

C:\ASIG\Ejemplos\ajustar.ada>gnatmake -f ajustar
gcc -c ajustar.adb
gcc -c palabra.adb
gcc -c parrafo.adb
gcc -c linea.adb
gnatbind -x ajustar.ali
gnatlink ajustar.ali

C:\ASIG\Ejemplos\ajustar.ada>
Generación de código: esqueleto de implementación a partir de la interfaz
La utilidad gnatstub genera un esqueleto de código vacío para un fichero de implementación .adb a partir del fichero de interfaz .ads.
I:\pruebas\ada>type parrafo.ads
----------------------------------------------------------------------------
-- PROYECTO:  Ajustar
-- MODULO:  Parrafo
-- AUTOR:  Manuel Collado
-- FECHA:  Febrero 2005
-- DESCRIPCION:  TAD párrafo de salida
-- RESPONSABILIDADES:
--   - Componer un párrafo palabra a palabra, rellenado líneas e imprimiendo
--   las líneas por la salida estándar a medida que se compone
--   - Generar por la salida la separación respecto al párrafo anterior
----------------------------------------------------------------------------

with Palabra; use Palabra;

package Parrafo is

   ----------------------------------------------------------------------------
   -- Imprime las líneas en blanco de separación entre parrafos,
   -- e inicia la línea de salida, vacía, con el sangrado.
   procedure Iniciar( Separador: in Tipo_Separador );

   -----------------------------------------------------------------------------
   -- Si la palabra cabe en la línea en curso, la pone en ella. En caso
   -- contrario, imprime la línea en curso, ajustándola, y la inicia
   -- con la nueva palabra.
   procedure Poner_Palabra( Pal: in Tipo_Palabra );

   -----------------------------------------------------------------------------
   -- Completa el párrafo, imprimiendo la última línea, sin ajustar.
   procedure Acabar;

end Parrafo;

I:\pruebas\ada>gnatstub -hs parrafo.ads
body is created for parrafo.ads

I:\pruebas\ada>type parrafo.adb
----------------------------------------------------------------------------
-- PROYECTO:  Ajustar
-- MODULO:  Parrafo
-- AUTOR:  Manuel Collado
-- FECHA:  Febrero 2005
-- DESCRIPCION:  TAD párrafo de salida
-- RESPONSABILIDADES:
--   - Componer un párrafo palabra a palabra, rellenado líneas e imprimiendo
--   las líneas por la salida estándar a medida que se compone
--   - Generar por la salida la separación respecto al párrafo anterior
----------------------------------------------------------------------------

package body Parrafo is

   ------------
   -- Acabar --
   ------------

   procedure Acabar is
   begin
      null;
   end Acabar;

   -------------
   -- Iniciar --
   -------------

   procedure Iniciar (Separador: in Tipo_Separador) is
   begin
      null;
   end Iniciar;

   -------------------
   -- Poner_Palabra --
   -------------------

   procedure Poner_Palabra (Pal: in Tipo_Palabra) is
   begin
      null;
   end Poner_Palabra;

end Parrafo;
Métricas de complejidad
La utilidad gnatmetric genera un informe de métricas de código para un fichero o una colección de ficheros.
Metrics computed for c:\asig\ejemplos\ajustar.ada\palabra.adb
containing package body Palabra

=== Code line metrics ===
  all lines           : 116
  code lines          : 70
  comment lines       : 33
  end-of-line comments: 5
  blank lines         : 13

Palabra (package body - library item at lines  16: 116)

=== Code line metrics ===
   all lines           : 101
   code lines          : 69
   comment lines       : 21
   end-of-line comments: 5
   blank lines         : 11

=== Element metrics ===
   all subprogram bodies    : 7
   all statements           : 30
   all declarations         : 20
   maximal unit nesting     : 1
   maximal construct nesting: 4
   logical SLOC             : 50

=== Complexity metrics ===
   statement complexity     : 1
   short-circuit complexity : 0
   cyclomatic complexity    : 1
   essential complexity     : 1
   maximum loop nesting     : 0

   Leer_C (procedure body at lines  26: 41)

   === Code line metrics ===
      all lines           : 16
      code lines          : 13
      comment lines       : 3
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 7
      all declarations         : 1
      maximal construct nesting: 3
      logical SLOC             : 8

   === Complexity metrics ===
      statement complexity     : 3
      short-circuit complexity : 0
      cyclomatic complexity    : 3
      essential complexity     : 1
      maximum loop nesting     : 0

   Imprimir (procedure body at lines  44: 48)

   === Code line metrics ===
      all lines           : 5
      code lines          : 4
      comment lines       : 1
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 1
      all declarations         : 2
      maximal construct nesting: 1
      logical SLOC             : 3

   === Complexity metrics ===
      statement complexity     : 1
      short-circuit complexity : 0
      cyclomatic complexity    : 1
      essential complexity     : 1
      maximum loop nesting     : 0

   Leer (procedure body at lines  51: 82)

   === Code line metrics ===
      all lines           : 32
      code lines          : 27
      comment lines       : 4
      end-of-line comments: 0
      blank lines         : 1

   === Element metrics ===
      all statements           : 17
      all declarations         : 3
      maximal construct nesting: 3
      logical SLOC             : 20

   === Complexity metrics ===
      statement complexity     : 6
      short-circuit complexity : 0
      cyclomatic complexity    : 6
      essential complexity     : 5
      maximum loop nesting     : 1

   Longitud (function body at lines  85: 89)

   === Code line metrics ===
      all lines           : 5
      code lines          : 4
      comment lines       : 1
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 1
      all declarations         : 2
      maximal construct nesting: 1
      logical SLOC             : 3

   === Complexity metrics ===
      statement complexity     : 1
      short-circuit complexity : 0
      cyclomatic complexity    : 1
      essential complexity     : 1
      maximum loop nesting     : 0

   Es_Nulo (function body at lines  92: 96)

   === Code line metrics ===
      all lines           : 5
      code lines          : 4
      comment lines       : 1
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 1
      all declarations         : 2
      maximal construct nesting: 1
      logical SLOC             : 3

   === Complexity metrics ===
      statement complexity     : 1
      short-circuit complexity : 0
      cyclomatic complexity    : 1
      essential complexity     : 1
      maximum loop nesting     : 0

   Es_Nula (function body at lines  99: 103)

   === Code line metrics ===
      all lines           : 5
      code lines          : 4
      comment lines       : 1
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 1
      all declarations         : 2
      maximal construct nesting: 1
      logical SLOC             : 3

   === Complexity metrics ===
      statement complexity     : 1
      short-circuit complexity : 0
      cyclomatic complexity    : 1
      essential complexity     : 1
      maximum loop nesting     : 0

   Anular (procedure body at lines  106: 110)

   === Code line metrics ===
      all lines           : 5
      code lines          : 4
      comment lines       : 1
      end-of-line comments: 0
      blank lines         : 0

   === Element metrics ===
      all statements           : 1
      all declarations         : 2
      maximal construct nesting: 1
      logical SLOC             : 3

   === Complexity metrics ===
      statement complexity     : 1
      short-circuit complexity : 0
      cyclomatic complexity    : 1
      essential complexity     : 1
      maximum loop nesting     : 0
Fallos de memoria dinámica
La utilidad gnatmem permite ejecutar un programa y detectar al final los bloques de memoria dinámica no liberados (memory leaks).
I:\Trabajos\currency\simple>gnatmem converter.exe
Global information
------------------
   Total number of allocations        :  32
   Total number of deallocations      :   0
   Final Water Mark (non freed mem)   :  17.01 Kilobytes
   High Water Mark                    :  17.01 Kilobytes

Releasing deallocated memory at :
--------------------------------
   : jewl__finalize$2

   : system__secondary_stack__ss_free

   : system__machine_state_operations__free_machine_state

Allocation Root # 1
-------------------
 Number of non freed allocations    :   7
 Final Water Mark (non freed mem)   : 672 Bytes
 High Water Mark                    : 672 Bytes
 Backtrace                          :
   : jewl__simple_windows__label

Allocation Root # 2
-------------------
 Number of non freed allocations    :   6
 Final Water Mark (non freed mem)   : 576 Bytes
 High Water Mark                    : 576 Bytes
 Backtrace                          :
   : jewl__simple_windows__button

Allocation Root # 3
-------------------
 Number of non freed allocations    :   3
 Final Water Mark (non freed mem)   : 288 Bytes
 High Water Mark                    : 288 Bytes
 Backtrace                          :
   : jewl__simple_windows__editbox

Allocation Root # 4
-------------------
 Number of non freed allocations    :   3
 Final Water Mark (non freed mem)   :  59 Bytes
 High Water Mark                    :  59 Bytes
 Backtrace                          :
   : jewl__simple_windows___elabb

Allocation Root # 5
-------------------
 Number of non freed allocations    :   2
 Final Water Mark (non freed mem)   :  10.03 Kilobytes
 High Water Mark                    :  10.03 Kilobytes
 Backtrace                          :
   : system__secondary_stack__ss_init

Allocation Root # 6
-------------------
 Number of non freed allocations    :   2
 Final Water Mark (non freed mem)   :   3.33 Kilobytes
 High Water Mark                    :   3.33 Kilobytes
 Backtrace                          :
   : system__tasking___elabb

Allocation Root # 7
-------------------
 Number of non freed allocations    :   2
 Final Water Mark (non freed mem)   :  48 Bytes
 High Water Mark                    :  48 Bytes
 Backtrace                          :
   : system__machine_state_operations__allocate_machine_state

Allocation Root # 8
-------------------
 Number of non freed allocations    :   2
 Final Water Mark (non freed mem)   :  32 Bytes
 High Water Mark                    :  32 Bytes
 Backtrace                          :
   : jewl__simple_windows___elabs

Allocation Root # 9
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   :   1.70 Kilobytes
 High Water Mark                    :   1.70 Kilobytes
 Backtrace                          :
   : system__tasking__stages__create_task

Allocation Root # 10
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   : 104 Bytes
 High Water Mark                    : 104 Bytes
 Backtrace                          :
   : jewl__simple_windows__dialog

Allocation Root # 11
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   : 104 Bytes
 High Water Mark                    : 104 Bytes
 Backtrace                          :
   : jewl__simple_windows__frame

Allocation Root # 12
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   :  96 Bytes
 High Water Mark                    :  96 Bytes
 Backtrace                          :
   : jewl__simple_windows__combobox

Allocation Root # 13
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   :  20 Bytes
 High Water Mark                    :  20 Bytes
 Backtrace                          :
   : jewl__message_handling___elabs


I:\Trabajos\currency\simple>
Perfil de ejecución
La utilidad gprof permite visualizar los tiempos de ejecución individuales de cada función de un programa (y otros datos sobre la ejecución). El programa ha debido ser compilado con la opción -pg. Al ejecutarse el programa se guarda información de los tiempos de ejecución en un fichero auxiliar, que es examinado posteriormente por gprof para generar el listado.
I:\pruebas\ada>gprof  p_palabra.exe
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  us/call  us/call  name
 18.18      0.02     0.02                             system__file_io__write_buf
  9.09      0.03     0.01    11793     0.85     0.85  palabra(long,...)(...)(long double)
  9.09      0.04     0.01        1 10000.00 20000.00  _ada_p_palabra
  9.09      0.05     0.01                             _mcount
  9.09      0.06     0.01                             ada__text_io__get
  9.09      0.07     0.01                             ada__text_io__integer_aux__put_int
  9.09      0.08     0.01                             ada__text_io__put$3
  9.09      0.09     0.01                             mcount
  9.09      0.10     0.01                             system__exception_table___elabb
  9.09      0.11     0.01                             system__img_wiu__set_image_width_integer
  0.00      0.11     0.00   212438     0.00     0.00  palabra__leer_c
  0.00      0.11     0.00    11793     0.00     0.00  palabra__es_nula
  0.00      0.11     0.00    11792     0.00     0.00  palabra__es_nulo
  0.00      0.11     0.00    11792     0.00     0.00  palabra__imprimir
  0.00      0.11     0.00    11792     0.00     0.00  palabra__longitud
  0.00      0.11     0.00        1     0.00     0.00  adainit
  0.00      0.11     0.00        1     0.00     0.00  palabra___elabb

 %         the percentage of the total running time of the
time       program used by this function.

cumulative a running sum of the number of seconds accounted
 seconds   for by this function and those listed above it.

 self      the number of seconds accounted for by this
seconds    function alone.  This is the major sort for this
           listing.

calls      the number of times this function was invoked, if
           this function is profiled, else blank.

 self      the average number of milliseconds spent in this
ms/call    function per call, if this function is profiled,
           else blank.

 total     the average number of milliseconds spent in this
ms/call    function and its descendents per call, if this
           function is profiled, else blank.

name       the name of the function.  This is the minor sort
           for this listing. The index shows the location of
           the function in the gprof listing. If the index is
           in parenthesis it shows where it would appear in
           the gprof listing if it were to be printed.
...
Pruebas de cubrimiento
La utilidad gcov permite visualizar el número de veces que se ejecuta cada línea del código fuente. El programa ha debido ser compilado con las opciones -fprofile-arcs -ftest-coverage. Al ejecutarse el programa se guarda información de los contadores de frecuencia de ejecución en un fichero auxiliar, que es examinado posteriormente por gcov para generar el listado. Los valores de los contadores aparecen al margen, a la izquierda de cada línea que contiene código ejecutable. Las líneas que nunca se ejecutan se destacan con la marca ######.
E:\pruebas\ada\ajustar.ada>gnatmake c  p_palabra
gcc -c -fprofile-arcs -ftest-coverage p_palabra.adb
gnatbind -x p_palabra.ali
gnatlink p_palabra.ali

E:\pruebas\ada\ajustar.ada>p_palabra < p_palabra.dat
    -1     0 NULO     4 [Esto]
    -1     0 NULO     2 [es]
    -1     0 NULO     2 [un]
    -1     0 NULO     7 [ejemplo]
     0     0 NULO     2 [de]
    -1     0 NULO     5 [texto]
    -1     0 NULO     4 [para]
    -1     0 NULO     8 [pruebas.]
     1     0 ----     4 [Este]
    -1     0 NULO     2 [es]
    -1     0 NULO     4 [otro]
    -1     0 NULO     8 [párrafo.]
     0     3 ----     1 [y]
    -1     0 NULO     4 [este]
    -1     0 NULO     7 [también]
    -1     0 NULO     2 [es]
    -1     0 NULO     5 [otro.]
     1     0 ----     5 [Ahora]
    -1     0 NULO     5 [viene]
    -1     0 NULO    64 [una-palabra-muy-larga-que-sobrepasa-la-longitud-máxima-admisible]
    -1     0 NULO    64 [-y-no-puede-ser-procesada-de-una-vez-sino-que-tiene-que-ser-frag]
    -1     0 NULO    17 [mentada-en-varias]
     0     1 ----     2 [Se]
    -1     0 NULO     6 [acabó.]

E:\pruebas\ada\ajustar.ada>gcov palabra.adb
 92.50% of 40 source lines executed in file palabra.adb
Creating palabra.adb.gcov.
  0.00% of 4 source lines executed in file palabra.ads
Creating palabra.ads.gcov.

E:\pruebas\ada\ajustar.ada>type palabra.adb.gcov
                ----------------------------------------------------------------------------
                -- PROYECTO:     Ajustar
                -- MODULO:       Palabra
                -- AUTOR:  Manuel Collado
                -- FECHA:  Febrero 2005
                -- DESCRIPCION:  TAD palabra
                -- RESPONSABILIDADES:
                --   - Definir la palabra como un texto de longitud variable
                --   - Leer la palabra de la entrada estándar, detectando la separación
                --     respecto a la palabra anterior
                --   - Imprimir la palabra por la salida estándar
                ----------------------------------------------------------------------------

                with Ada.Text_IO; use Ada.Text_IO;

           1    package body Palabra is

                   NUL : constant Character := Standard.Ascii.nul; -- carácter nulo
                   TAB : constant Character := Standard.Ascii.ht;  -- tabulador

                   C   : Character;         -- carácter leído, anticipado
                   EOL : Boolean   := True; -- indicador de fin de línea leído
                   EOF : Boolean   := True; -- indicador de fin de fichero leído

                   ----------------------------------------------------------------------------
         262       procedure Leer_C is
                      -- Registra en 'C' el siguiente carácter de la entrada.
                      -- Si se alcanza el fin de línea o fichero, lo indica en 'EOL' y 'EOF'
                      -- y asigna a 'C' el valor 'NUL'
                   begin
         262          EOL := End_Of_Line;
         262          EOF := End_Of_File;
         524          if EOL then
           8             C := NUL;
           8             if not EOF then
           7                Skip_Line;
                         end if;
                      else
         254             Get( C );
                      end if;
                   end Leer_C;

                   ----------------------------------------------------------------------------
          24       procedure Imprimir( Pal: in Tipo_Palabra ) is
                      -- Imprime la palabra por la salida estándar
                   begin
          24          Put( Pal.Valor(1..Pal.Longitud) );
                   end Imprimir;

                   ----------------------------------------------------------------------------
          50       procedure Leer( Pal : out Tipo_Palabra; Sep: out Tipo_Separador ) is
                      -- Devuelve la siguiente palabra del fichero de entrada, y la
                      -- separación de párrafo situada delante de ella, si la hay.
                   begin
                      -- buscar el inicio de palabra
          25          Sep.Salto :=  - 1;
          25          Sep.Sangrado := 0;
          52          loop
          52             if C = ' ' then
          20                Sep.Sangrado := Sep.Sangrado + 1;
          32             elsif C = TAB then
      ######                Sep.Sangrado := (Sep.Sangrado / 8) * 8 + 8;
          32             elsif EOL and not EOF then
           7                Sep.Salto := Sep.Salto + 1;
           7                Sep.Sangrado := 0;
                         else
          25                exit;
                         end if;
          27             Leer_C;
                      end loop;
          25          if Sep.Salto < 0 then
          20             Sep.Sangrado := 0;
                      end if;

                      -- leer los caracteres de la palabra
          25          Pal.Longitud := 0;
         259          while (C /= ' ') and (C /= NUL) and (Pal.Longitud < MAXLONG) loop
         234             Pal.Longitud := Pal.Longitud + 1;
         234             Pal.Valor(Pal.Longitud) := C;
         234             Leer_C;
                      end loop;
                   end Leer;

                   ----------------------------------------------------------------------------
          24       function Longitud( Pal: in Tipo_Palabra ) return Integer is
                      -- Devuelve la longitud (número de caracteres) de la palabra
                   begin
          24          return Pal.Longitud;
                   end Longitud;

                   ----------------------------------------------------------------------------
          24       function Es_Nulo( Sep: in Tipo_Separador ) return Boolean is
                   -- Devuelve TRUE si el separador no representa un cambio de párrafo.
                   begin
          24          return (Sep.Salto <= 0) and (Sep.Sangrado <= 0);
                   end Es_Nulo;

                   ----------------------------------------------------------------------------
          25       function Es_Nula( Pal: in Tipo_Palabra ) return Boolean is
                      -- Devuelve TRUE si la palabra no tiene caracteres.
                   begin
          25          return (Pal.Longitud <= 0);
                   end Es_Nula;

                   ----------------------------------------------------------------------------
      ######       procedure Anular( Sep: out Tipo_Separador ) is
                      -- Asigna valor nulo al separador
                   begin
      ######          Sep := Sep_Nulo;
                   end Anular;

                   ----------------------------------------------------------------------------
                begin
                   -- leer el primer carácter, anticipado
           1       Leer_C;
                end Palabra;

E:\pruebas\ada\ajustar.ada>