Previous Up Next

Dependency graph generation module
(depend)

Introduction

This module contains the procedures that derive the dependency graph from the given attribute assignments. The graph itself is built by calling procedures from the Simple Multi-Pass Module [allsmp].

This module also contains the function that tests whether the given grammar is flat implementable, as defined in [2.9].

1 Testing flat implementability

The boolean function flatimplementable returns TRUE when the grammar is flat implementable, otherwise FALSE. The procedure first makes the sets of right- and left-hand side elements by calling the local procedure make right left side elements. This procedure initializes (as a global side effect) the two global variables left side elements and right side elements [bintree 2.2]

When the right-hand side elements are known the procedure end always at is called for all right-hand side elements. The procedure end always at is the straightforward implementation of "end always at" in [2.9].

2 Projection for the flat implementation

In [3.1.1] we defined the function "attr elem pairs of", that specified on which (attribute,element) pairs a given (attribute,element) pair is projected according to the flat implementation. The function projection is the implementation of this function. It returns the subset of the elements for a given pair that is equal to the clause "clos parents of and(E) union clos class(E)" in the formal definition. The first parameter attr nr contains the number of the attribute, and the second parameter elem nr contains the number of the element of the attribute pair.

3 Numbering of the nodes in the dependency graph

In [3.1.1] we defined the set "all attr elem pairs" as the set of (attribute,element) pairs that form the nodes of the dependency graph. The set is implemented by assigning a unique number to each pair. This is also explained in [4.13]. The global variable number of is used to store the lowest number of all attribute element pairs with each element. The following two subsections explain how numbers are assigned to pairs, and once this is done, how the number assigned to a pair can be found.

3.1 Assigning numbers to the pairs

The function make numbering for pairs tries to make a unique numbering for all the (attribute,element) pairs. The function returns FALSE when more pairs are found than the implementation allows, otherwise TRUE is returned. Pairs are numbered by calling the procedure make for for each element that has an indirect, direct or empty tree rule defined.

The procedure make for adds the pairs as nodes to the dependency graph by calling the procedure add a node [allsmp 2.1] for the attributes as represented by the parameter attrs, and the element with element number elem nr. The variable number of is also updated for the element with element number elem nr.

3.2 Find number of pair

The function number of pair returns the number of the pair given by the parameters attr nr and elem nr. It makes use of the global variable number of.

4 Generate dependencies

The boolean function generate all dependencies tries to generate the dependency graph. When this is not possible, due to restrictions imposed by the implementation on the number of nodes of the dependency graph, the function returns FALSE, otherwise TRUE. The value returned is the same as the value returned by the function make numbering for pairs (see section 3.1). This procedure can be viewed as the implementation of the expression that is used to define the set "dependencies" in [3.1.2].

The function generates the dependencies that are introduced by each tree rule by calling the procedure dep lattr ass  (see next section) after calling the local procedure make partlist. The procedure make partlist fills its second parameter with the representation of the part list [2.11.2] of the element as indicated by the value of the first parameter of the procedure. A slightly different implementation for the part list is chosen here, compared to that which is used in the Attribute Assignment Transformation Module [trans 3].

The global boolean variable with dep info [definitions 2.6] is used to determine whether information of the collected dependencies with each tree rule have to be printed or not.

4.1 Attribute assignments

The procedure dep lattr ass generates the dependencies for the attribute assignments pointed to by the first parameter lattr ass ptr of type plattr ass [bintree 1.5] within the context described by the second reference parameter partlist. The procedure calls either the procedure dep simp ass or dep sel ass for each assignment in the list of assignments pointed to by lattr ass ptr. This procedure is the implementation of the function "dep in AAS" in [3.1.2].

The procedure dep simp ass generates the dependencies of a simple attribute assignment. It initializes the global variables to attr, to elements and to part, which represents the nodes of the dependency graph to which the dependencies introduced by the expression on the right-hand side of the simple attribute assignment point. It also calls the procedure dep expr, see following subsection.

The procedure dep sel ass generates the dependencies of a case expression. For each alternative of the case expression the local procedure dep alter is called.

The procedure dep alter calls the procedure dep lattr ass recursively, with an updated partlist for each element in the selector represented by the first parameter selector.

4.2 Expressions

The procedure dep expr generates the dependencies introduced by the expression pointed to by the first parameter expr ptr in the context described by the second reference parameter partlist. The procedure either calls the procedure dep simple expr, dep sem func or dep case expr depending on the kind of the expression. This procedure is the implementation of the function "dep in EXPR" in [3.1.2].

The procedure dep simple expr generates the dependencies from the nodes determined by the applied attribute occurrence to the nodes determined by the assigned attribute occurrence. These nodes are represented by the global variable to attr, to elements and to part, which are initialized in the procedure dep simp ass (see previous subsection). This is done by calling the procedure generate dependencies with the right arguments.

The procedure dep sem func generates the dependencies introduced by a semantic function expression, by calling the procedure dep expr recursively from all the argument expressions.

The procedure dep case expr generates the dependencies introduced by a case expression. This is done by calling the local procedure dep alter for each alternative of the case expression. The procedure dep alter generates the dependencies for the selector represented by the first parameter selector and the expression pointed to by the second parameter expr. For each element in the selector the procedure dep expr is called recursively with an updated part list.

4.3 Adding dependencies in the dependency graph

The procedure generate dependencies adds the dependencies from the nodes represented by the parameters attr from and elements from to the nodes represented by the parameters attr to and elements to, using the restrictions determined by the part as represented by the parameters part from and part to. The kind of restriction is returned by the local function direction, which is the implementation of "direction" in [3.1.2]. The dependencies are added to the graph by calling the procedure add a dependency [allsmp 2.1].

5 Interface

This module uses the following modules:

5.1 Exported functions

The following functions are exported by this module:

This procedure tests whether the grammar is implementable according to the flat implementation. It is described in section 1

This procedure generates the dependency graph, and returns the value TRUE whenever this was successful, otherwise the value FALSE is returned. See section 4, for a complete description.

6 The listing

[ENVIRONMENT ('depend.pen'),
 INHERIT     ('definitions.pen',
              'perform.pen',
              'bintree.pen',
              'allsmp.pen',
              'listing.pen')]MODULE depend;

(*      MODULE: DEPEND                                                        *)

(*  This module generates the dependencies, for a so called flat              *)
(*  implementation model. It includes a testing function whether it is        *)
(*  possible to make a flat implementation.                                   *)
(*  The generating process stores all the information in the data structure   *)
(*  of allsmp. This is done by the procedures :                               *)
(*      initialize_smp_algorithm                                              *)
(*      add_a_node(nr, elem_nr, attr_nr : integer)                            *)
(*      add_a_dependency(from, to_ : integer; dir : tdirection)               *)


(*                  !!! WARNING !!!                                           *)

(*   The type partlist is defined different from the one used in TRANS.       *)

[HIDDEN]
CONST
  max_pairs     = 255;

[HIDDEN]
TYPE

(* Begin of the declarations for the partlist                                 *)
  twhere        = ARRAY[0..max_part_nr] OF ttr_ass;
  tpartlist     = ARRAY[0..max_part_nr] OF integer;

(* Begin of the declaration for the dependency generation                     *)
  tlower        = ARRAY[0..max_elem_nr] OF elements;
  tnumber       = ARRAY[0..max_elem_nr] OF integer;

(*      VARIABLE DECLARATION                                                  *)

[HIDDEN]
VAR
(* local for this program                                                     *)
  lower       : tlower;   (* lower_left_hand_side_elements           *)
  number_of   : tnumber;  (* start numbers for numbering of pairs    *)
  to_attr     : integer;  (* These variables are used as a parameter *)
  to_elements : elements; (* mechanism between: dep_simp_ass, (ass)  *)
  to_part     : integer;  (* and dep_simple_expr where they are used.*)
  number      : integer;

6.1 Test flat implementable

  FUNCTION flatimplementable : boolean;
  (* This procedure tests whether the described grammar is implementable      *)
  (* using the socalled flat implementation. The test for this is :           *)
  (*    ALL e IN  right_hand_side_elements                                    *)
  (*        ( end_always_at(e))                                               *)
  (*          WHERE end_always_at(e)                                          *)
  (*                =   e IN element_with_direct_tree_rule                    *)
  (*                  OR (e NOT IN elements_with_indirect_tree_rule           *)
  (*                      AND ALL e' IN class(e) (end_always_at(e'))          *)
  (*                     )                                                    *)
  (* To do this test first the sets right_hand_side_elements and left_hand_   *)
  (* side_elements are generated. Then the test is performed.                 *)
  VAR
    right_elem_nr : integer;
    no_errors     : boolean;

    PROCEDURE make_right_left_side_elements;
    (* This procedure makes the right hand side and the left hand side        *)
    (* elements, which are put in left_side_elements and right_side_elements  *)
    VAR
      elem_nr : integer;

      PROCEDURE make_from(tree_rule : ptree_rule);
      (* This procedure finds all the right hand side elemets from the tree   *)
      (*  rule.                                                               *)
      BEGIN
        WHILE tree_rule <> NIL
        DO BEGIN
             right_side_elements := right_side_elements
                                  + [tree_rule^.element^.elem_nr];
             tree_rule := tree_rule^.rest
           END
      END;

    BEGIN (* of make_right_left_side_element *)
      left_side_elements  := [];
      right_side_elements := [root^.elem_nr];
      FOR elem_nr := 0 TO nr_of_elem
      DO WITH element[elem_nr]^
         DO IF   kind_of_rule IN [r_dire,r_empt]
            THEN BEGIN
                   left_side_elements := left_side_elements + [elem_nr];
                   make_from(tree_rule)
                 END
    END;

    PROCEDURE print_error_message(elem_nr : integer);
    (* This procedure prints an error message if the grammar is not flat      *)
    (* implementable. with an indication of the place where the error         *)
    (* occurred.                                                              *)
    BEGIN
      IF   no_errors
      THEN BEGIN
             write(listing, 'GRAMMAR IS NOT FLAT IMPLEMENTABLE');
             print_newline;
             write(listing, 'for:');
             print_newline(2);
             no_errors := FALSE
           END;
      write(listing, element[elem_nr]^.name, ' in ',
                     element[right_elem_nr]^.name);
      print_newline
    END;

    PROCEDURE end_always_at(start_nr : integer);
    (* This procedure seeks whether this element ends at an element with an   *)
    (* indirect tree rule, and if so an error message is generated.           *)
    VAR
      elem_of : integer;
      class   : elements;
    BEGIN
      WITH element[start_nr]^
      DO IF   kind_of_rule = r_indi
         THEN print_error_message(start_nr)
         ELSE IF  NOT(start_nr IN left_side_elements)
              THEN BEGIN
                     class := class_rule;
                     elem_of := start_nr;
                     WHILE class <> []
                     DO BEGIN
                          next_elem(elem_of, class);
                          end_always_at(elem_of)
                        END
                   END
     END;

  BEGIN (* of flatimplementable *)
    perf_start_time(perf_3_fl_im);
    make_right_left_side_elements;
    no_errors := TRUE;
    FOR right_elem_nr := 0 TO nr_of_elem
    DO IF   right_elem_nr IN right_side_elements
       THEN end_always_at(right_elem_nr);
    IF   NOT no_errors
    THEN print_newline(3);
    flatimplementable := no_errors;
    perf_end_time(perf_3_fl_im);
  END;

6.2 The projection for the flat implementation

(*  This page deals with the projection from each attribute element pair on   *)
(*  pairs in the implementation. Which could be described with the            *)
(*  following formal description, where the function projection returns all   *)
(*  elements of the pairs in the implementation :                             *)
(*                                                                            *)
(*  DF projection(attr, elem)                                                 *)
(*     = IF   elem IN elements_with_indirect_tree_rule                        *)
(*       THEN IF   attr IN attr_of(elem)                                      *)
(*            THEN [ elem ]                                                   *)
(*            ELSE projection(attr, parent_of(elem))                          *)
(*       ELSE IF   elem IN elements_with_tree_production                      *)
(*            THEN [ elem ]                                                   *)
(*            ELSE clos_class_or_and(elem)                                    *)
(*                 INTERSECTION left_hand_side_elements                       *)

  [HIDDEN]
  FUNCTION projection(attr_nr : integer; elem_nr : integer) : elements;
  (* This function returns the non_empty set of elements, to which this       *)
  (* attribute element (attr_nr, elem_nr) pair is projected by the flat       *)
  (* implementation method.                                                   *)
  VAR
    par_nr  : integer;
  BEGIN
    WITH element[elem_nr]^
    DO IF   kind_of_rule = r_indi
       THEN IF   attr_nr IN attr[nor_gen]
            THEN projection := [elem_nr]
            ELSE BEGIN
                   par_nr := start_nr;
                   REPEAT
                     REPEAT par_nr := succ(par_nr) UNTIL par_nr IN parent
                   UNTIL element[par_nr]^.kind_of_rule IN [r_indi, r_dire];
                   projection := projection(attr_nr, par_nr)
                 END
       ELSE projection := (clos_class + [elem_nr]) * left_side_elements
  END;

6.3 The numbering of the nodes in the dependency graph

(*  This page deals with the numbering of the attribute element pairs with a  *)
(*  unique number that can be used for the construction of the dependency     *)
(*  graph. Two things have to be done. First we have to assign a number to    *)
(*  each pair, and secondly we have to give a function that retrieves the     *)
(*  number for a given pair.                                                  *)
(*  We choose for the representation where we assign a number to each element *)
(*  which added with an order of the attribute in the attribute set of this   *)
(*  element gives a unique number, in such a way that the resulting numbering *)
(*  is compact.                                                               *)

  [HIDDEN]
  FUNCTION make_numbering_for_pairs : boolean;
  (* This function assigns the right number to the global variable number_of  *)
  (* for every element, that has not an undefined tree rule. The function     *)
  (* returns TRUE if the maximum possible pairs is not exceeded.              *)
  VAR
    number  ,
    elem_nr : integer;

    PROCEDURE make_for(attrs : attributes);
    (* This procedure sets number_of to the right value for elem_nr, and adds *)
    (* number with the number of attributes in attrs. As a side effect the    *)
    (* attributes are written to the dependency file as pairs with the        *)
    (* name of element elem_nr.                                               *)
    VAR
      attr_nr     : integer;
      pair        : tnode;
    BEGIN
      number_of[elem_nr] := number;
      attr_nr   := start_nr;
      WHILE attrs <> []
      DO BEGIN
           next_attr(attr_nr, attrs);
           add_a_node(number, elem_nr, attr_nr);
           number := succ(number);
         END
    END;

  BEGIN (* of mak_numbering_for_pairs *)
    perf_start_time(perf_3_mk_nr);
    number  := 0;
    FOR elem_nr := 0 TO nr_of_elem
    DO WITH element[elem_nr]^
       DO CASE kind_of_rule OF
            r_dire ,
            r_empt : make_for(attr[all_gen]);
            r_indi : make_for(attr[nor_gen]);
            r_undf : number_of[elem_nr] := error_nr
          END;
    make_numbering_for_pairs := number <= max_pairs;
    perf_end_time(perf_3_mk_nr)
  END;

  [HIDDEN]
  FUNCTION number_of_pair(attr_nr, elem_nr : integer) : integer;
  (* This function returns the number associated with the attribute element   *)
  (* pair (elem_nr, attr_nr), using the start_number assigned to the element, *)
  (* which is in the global variable number_of, and the order of the          *)
  (* attribute in the attribute set.                                          *)
  VAR
    cur_attr_set : attributes;
    number       ,
    a            : integer;

  BEGIN
    WITH element[elem_nr]^
    DO IF   kind_of_rule = r_indi
       THEN cur_attr_set := attr[nor_gen]
       ELSE cur_attr_set := attr[all_gen];
    number := number_of[elem_nr];
    FOR a := 0 TO pred(attr_nr)
    DO IF   a IN cur_attr_set
       THEN number := succ(number);
    number_of_pair := number
  END;

6.4 Generate dependencies

This page deals with the generation of the dependencies for given set of elements with their attributes and partnumbers.

  [HIDDEN]
  PROCEDURE generate_dependencies
           (attr_from : integer; elements_from : elements; part_from : integer;
            attr_to   : integer; elements_to   : elements; part_to   : integer);
  (* This procedure generates all the dependencies for all the pairs formed   *)
  (* by attr_from and elements_from to the pairs formed by attr_to and        *)
  (* elements_to, with the right restrictions on the direction, depending on  *)
  (* part_from and part_to.                                                   *)
  VAR
    elem_nr      ,
    from_elem_nr ,
    to_elem_nr   ,
    from     ,
    to_         : integer;
    dir         : tdirection;
    elements_between ,
    helements_to     : elements;

    FUNCTION direction(part_from, part_to : integer): tdirection;
    (* This function returns the restrictions on the direction for a           *)
    (* dependency from node part_from to node part_to, of a tree rule.        *)
    BEGIN
      IF   (part_from = main_part_nr)
      OR   (part_to   = main_part_nr)
      THEN direction := none
      ELSE IF   part_from = part_to
           THEN direction := both
           ELSE IF   part_from < part_to
      THEN direction := left
      ELSE direction := right
    END;

  BEGIN (* of generate dependencies *)
    dir :=direction(part_from, part_to);
    IF   part_from <> part_to
    THEN BEGIN
           from_elem_nr := start_nr;
           WHILE elements_from <> []
           DO BEGIN
                next_elem(from_elem_nr, elements_from);
                from := number_of_pair(attr_from, from_elem_nr);
                helements_to := elements_to;
                to_elem_nr   := start_nr;
                WHILE helements_to <> []
                DO BEGIN
                     next_elem(to_elem_nr, helements_to);
                     to_ := number_of_pair(attr_to, to_elem_nr);
                     add_a_dependency(from, to_, dir)
                   END
              END
         END
    ELSE BEGIN
           elements_between := elements_from * elements_to;
           elem_nr := start_nr;
           WHILE elements_between <> []
           DO BEGIN
                next_elem(elem_nr, elements_between);
                from := number_of_pair(attr_from, elem_nr);
                to_  := number_of_pair(attr_to, elem_nr);
                add_a_dependency(from, to_, dir)
              END
         END
  END;

6.5 Dependencies in expressions

  [HIDDEN]
  PROCEDURE dep_expr(expr_ptr : pexpr; VAR partlist : tpartlist);
  (* This procedure tests the visibility as described by dep_visibility_EXPR  *)
  (* with EXPR, pointed by expr_ptr, and partlist partlist.                   *)

    PROCEDURE dep_simple_expr;
    (* This procedure tests whether the attribute of this simple expression,  *)
    (* pointed to by expr_ptr is visible from element elem.                   *)
    (* This procedure makes use of the global variables to_attr, to_elements  *)
    (* and to_part, which are assigned in dep_simp_ass.                       *)
    BEGIN
      WITH expr_ptr^,attr^
      DO generate_dependencies(attr_nr,
                               projection(attr_nr, partlist[partnamenr]),
                               partnamenr,
                               to_attr, to_elements, to_part)
    END;

    PROCEDURE dep_sem_func(args : plexpr);
    (* This procedure generates the dependencies for the arguments of the     *)
    (* function with the arguments args.                                      *)
    BEGIN
      WHILE args <> NIL
      DO BEGIN
           dep_expr(args^.first,partlist);
           args := args^.rest
         END
    END;

    PROCEDURE dep_case_expr(partnamenr : integer; partlist : tpartlist);
    (* This procedure generates the dependencies for the case expressions     *)
    (* pointed to by expr_ptr. The variable elem holds the element associated *)
    (* with the partname of this case expressions.                            *)
    VAR
      alt_expr : plalt_expr;

      PROCEDURE dep_alter(selectors : elements; expr : pexpr);
      (* This procedure generates the dependencies for one alternative of a   *)
      (* case expression.                                                     *)
      VAR
        elem_nr   : integer;
      BEGIN
        elem_nr := start_nr;
        WHILE selectors <> []
        DO BEGIN
             next_elem(elem_nr, selectors);
             partlist[partnamenr] := elem_nr;
             dep_expr(expr, partlist)
           END
      END;

    BEGIN (* dep_case_expr *)
      WITH expr_ptr^
      DO BEGIN
           alt_expr := alter;
           WHILE alt_expr <> NIL
           DO BEGIN
                WITH alt_expr^
                DO   dep_alter(selectors, expr);
                alt_expr := alt_expr^.rest
              END
         END
    END;

  BEGIN (* of dep_expr *)
    WITH expr_ptr^
    DO CASE kind OF
         e_atoc : dep_simple_expr;
         e_func : dep_sem_func(args);
         e_case : dep_case_expr(headpnnr, partlist)
       END
  END;

6.6 Dependencies in attribute assignments

  [HIDDEN]
  PROCEDURE dep_lattr_ass(lattr_ass_ptr : plattr_ass;
                          VAR partlist : tpartlist);
  (* This procedure generates all dependencies for the list of assignments    *)
  (* pointed to by lattr_ass_ptr.                                             *)

    PROCEDURE dep_simp_ass;
    (* This procedure generates all dependencies for the case that the first  *)
    (* assignment of lattr_ass_ptr is a simple attribute assignment.          *)
    (* The global variables to_attr, to_element and to_part are set, which    *)
    (* are used in dep_simple_expression.                                     *)

    BEGIN
      WITH lattr_ass_ptr^,attr^
      DO BEGIN
           to_attr     := attr_nr;
           to_elements := projection(attr_nr, partlist[partnamenr]);
           to_part     := partnamenr;
           dep_expr(expr, partlist)
         END
    END;

    PROCEDURE dep_sel_ass(gpartnamenr : integer; partlist : tpartlist);
    (* This procedure generates all the dependencies for the first assignment *)
    (* in the case this is a selective assignment.                            *)
    VAR
      alt_ass : plalt_ass;

      PROCEDURE dep_alter(selector : elements;
                         lattr_ass_ptr : plattr_ass);
      (* This procedure generates the dependencies form one alternative, with *)
      (* the selector , and the list of attribute assignments,                *)
      (* pointed to by lattr_ass_ptr.                                         *)
      VAR
        elem_nr   : integer;

      BEGIN (* of dep_alter *)
        elem_nr := start_nr;
        WHILE selector <> []
        DO BEGIN
             next_elem(elem_nr, selector);
             partlist[gpartnamenr] := elem_nr;
             dep_lattr_ass(lattr_ass_ptr, partlist)
           END
      END;

    BEGIN (* of dep_sel_class *)
      WITH lattr_ass_ptr^
      DO BEGIN
           alt_ass := alter;
           WHILE alt_ass <> NIL
           DO BEGIN
                WITH alt_ass^
                DO dep_alter(selectors, attr_ass);
                alt_ass := alt_ass^.rest
              END
         END
    END;

  BEGIN (* of dep_lattr_ass *)
    WHILE lattr_ass_ptr <> NIL
    DO BEGIN
         WITH lattr_ass_ptr^
         DO CASE kind OF
              a_simp : dep_simp_ass;
              a_sele : dep_sel_ass(headpnnr, partlist)
            END;
         lattr_ass_ptr := lattr_ass_ptr^.rest
       END
  END;

6.7 Generation of all dependencies

  FUNCTION generate_all_dependencies : boolean;
  (* This procedure generates the dependencies for all the attribute          *)
  (* assignments.                                                             *)
  VAR
    elem_nr  : integer;
    partlist : tpartlist;

    PROCEDURE make_partlist(elem_nr : integer; VAR partlist : tpartlist);
    (* This procedure makes a partlist with element pointer elem_ptr.         *)
    VAR
      partnamenr : integer;
      walker     : ptree_rule;

    BEGIN
      partnamenr := 0;
      partlist[partnamenr] := elem_nr;
      walker := element[elem_nr]^.tree_rule;
      WHILE walker <> NIL
      DO BEGIN
           partnamenr := succ(partnamenr);
           WITH walker^
           DO partlist[partnamenr] := element^.elem_nr;
           walker := walker^.rest
         END
    END;

  BEGIN (* of generate_all_dependencies *)

  (*    INITIALIZATION                                                        *)

    initialize_smp_algorithm;

  (*    NUMBERING OF THE PAIRS                                                *)

    IF   with_dep_info
    THEN BEGIN
           write(listing, 'The attribute pairs are:');
           print_newline(2)
         END;

    IF   make_numbering_for_pairs
    THEN BEGIN

  (*    GENERATION OF THE DEPENDENCIES                                        *)

            IF   with_dep_info
            THEN BEGIN
                   print_newline(2);
                   write(listing, 'The dependencies are:');
                   print_newline
                 END;
            perf_start_time(perf_3_g_dep);
            FOR elem_nr := 0 TO nr_of_elem
            DO WITH element[elem_nr]^
               DO IF   kind_of_rule IN [r_dire, r_empt]
                  THEN BEGIN
                         IF   with_dep_info
                         THEN BEGIN
                                print_newline;
                                write(listing, 'With element: ', name);
                                print_newline(2)
                              END;
                         make_partlist(elem_nr, partlist);
                         dep_lattr_ass(attr_ass, partlist)
                       END;
           perf_end_time(perf_3_g_dep);
           generate_all_dependencies := TRUE
         END
    ELSE generate_all_dependencies := FALSE
  END;

END.


My life as a hacker | My home page