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].
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].
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.
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.
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.
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.
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.
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.
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.
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].
This module uses the following modules:
definitions, perform, bintree, allsmp, listing.
The following functions are exported by this module:
FUNCTION flatimplementable : boolean;
This procedure tests whether the grammar is implementable according to the flat implementation. It is described in section 1
FUNCTION generate_all_dependencies : boolean;
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.
[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; |
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; |
(* 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; |
(* 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; |
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; |
[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; |
[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; |
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