Assignment generation module (gass)

Introduction

This module contains the procedures to generate the tree traversing and attribute evaluating procedures of the generated attribute evaluator. A set of tree traversing procedures is generated for each pass.

1 The need to be evaluated attribute relations

In this section we describe how to calculate two relations that are used to determine which attributes have to be evaluated in the current pass. These relations have to be re-calculated for each pass, using the given SMP-solution.

1.1 Formal description

We first define the formal relation "eval attr of" using the set of (attribute,element) pairs "all attr elem pairs", and the function "pass(A)", as defined in [3.3].

```df  eval attr of(E,n)
= {  A
|  (A,E) in all attr elem pairs
and pass((A,E)) = n
and not A in all input attr of(E)
}```

The global variable eval attr is used to represent this formal relation for the current pass. It is calculated for each pass in the procedure gen program [genera 2].

When the code of the assignments starting from an element (with a given part of a certain tree rule) has to be generated, we need to know which attributes have to be evaluated in the class hierarchy at, and under, this element for the current pass. Using the formal relation "eval attr at" we define the formal relation "attributes to be evaluated", which represents these sets of attributes for each element:

```df  attributes to be evaluated(E,n)
= union{  eval attr of(E',n)
|  E' in clos class of and(E)
}```

The global variable attr to eval is used to represent this formal relation for the current pass.

While we generate the assignments we traverse the class hierarchy. At each element we have to decide for which of the attributes code to implement the assignments has to be generated. Because the set of (attribute,element) pairs used to represent the dependency graph differs from the (attribute,element) pairs that are represented in the abstract program tree, the code for the assignments cannot always be generated with the element where the attribute is stored with. When an attribute is stored at a certain class it is possible that it only has to be evaluated at some of the elements of this class. Using the formal relation "eval attr at" we define the formal relation "attributes at all" for each element, which represents all the attributes (of the set of attributes that have to be evaluated) that can be evaluated at all the elements at, and under, this element in the class hierarchy.

```df  attributes at all(E,n)
= eval attr at(E,n)
union if   E in classes
then intersection{  attributes at all(E',n)
|  E' in class(E)
}
else empty
fi```

The global variable attr at all is used to represent this formal relation for the current pass.

1.2 Calculating the formal relations

The procedure maketo eval and at all calculates the relations that are derived from the formal relation "eval attr at". Both the formal relations "attributes to be evaluated" and "attributes at all" are calculated simultaneously in a single pass over all the elements. This procedure does not take into account the clause "not A in all input attr of(E)" in the definition of "eval attr of". The SMP-algorithm puts all the input (attribute,element) pairs in the first pass. The procedure update eval attr is called for the first pass to remove these pairs from the solution. See [genera 2].

1.3 Parametric attributes

The function parametric attributes returns the set of attributes for the element represented by the parameter this elem nr, which have to be passed as arguments of a tree-walking procedure. This function is called in the following procedures: collect parametric attributes (see 3.3.1), gen call to (see subsection 4.1.4), gen ass from (see subsection 4.1) and init gen eval procedures (see subsection 2.2.1).

2 Generation of tree-walking evaluation procedures

The tree-walking evaluation procedures are generated for each pass as local procedures of the pass evaluation procedure. Because these procedures generally call each other recursively, they are first declared forward, before the bodies of the procedure are generated. The procedure gen header generates the heading of a procedure, and the procedure gen eval procedure generates a tree-walking, evaluation procedure. These procedures are described in the following two subsections.

2.1 Generate header of a evaluation procedure

The procedure gen header generates the header of the procedure with the element represented by first the parameter this elem nr. The parameter declaration list for this procedure is either enclosed by round or curly brackets, determined by the value of the second boolean parameter realy. When this parameter is equal to TRUE, round brackets are generated, otherwise they are generated as a comment by surrounding them with curly brackets.

2.2 Generate a tree-walking evaluation procedure

The procedure gen eval procedure generates the tree-walking evaluation procedure for the element represented by the first parameter proc elem nr. When the second boolean parameter L direction is equal to TRUE, a left-to-right tree-walking procedure is generated, otherwise a right-to-left tree-walking procedure is generated.

Firstly, the local procedure init gen eval procedure is called which initializes some variables used by the procedures that generated the assignments and the expressions. Secondly, the procedure gen header is called and this procedure generates a procedure heading (see previous subsection). Thirdly, the local variables used in the expressions are determined and declared as local variables of the tree-walking evaluation procedure. This is done by the local procedure gen variables. Finally, the procedure gen body is called, which generates the body of the procedure. In the following subsections we describe each of these procedures.

2.2.1 Initialization

The local procedure init gen eval procedure initializes the global variables that contain information on the current element (depending on the first parameter proc elem nr of the procedure gen eval procedure) and its tree rule. These variables are described in the subsections 6.2 and 6.3 The procedure initializes the variable plh depth to zero for all the parts, and the variable plh[part nr,0] is initialized with the element of the part with part number part nr.

2.2.2 Generation of the local variables

The local procedure gen variables determines the number and types of the local variables needed, and generates the code for declaring these local variables. To determine the local variable needed, the procedure make all locals (see subsection 3.2) is called for the assignments defined with the parts of the current tree rule. Before this procedure is called, the administration of the local variables is initialized by calling the procedure init loc types, see subsection 3.1 The code is generated by calling the procedure gen locals, see subsection 3.3

2.2.3 Generation of the procedure body

The local procedure gen body generates the body of the tree-walking evaluation procedure. It generates the statements for the inherited attribute assignments and recursive calls with the parts of the current tree rule. The order in which the statements for the parts are generated depends on the value of the second parameter L direction of the procedure gen eval procedure. Following this, the statements for the synthesized attributes with the left-hand side of the current tree rule are calculated. The procedure gen assignments (see section 4) is called to generate the statements belonging to each separate part.

3 Generation of local variables

There are two kinds of local variables needed with the tree walking procedure. The first kind are the local variables used to represent the one pass attributes. These are calculated and generated by the procedure gen one pass locals (see subsection 3.3.1), which is a local procedure of the procedure gen locals (see subsection 3.3).

The second kind are the local variables, which are used to store the intermediate results, of the code that is generated representing the expressions. This is because the function expressions are represented by procedure calls. To construct the set of these local variables all the expressions in the assignments of the current tree rule have to be traversed. The intermediate local variables also have to be assigned to the parts of the expressions. It turns out that each argument of a function which is not an attribute occurrence, needs an intermediate local variable. As a result, the names of the local variables are stored in the field loc rep of the type tlexpr [bintree 1.4], which is used to represent the argument list of a semantic function expression. These fields are used by the procedure gen function expr (see subsection 5.2).

Generating intermediate local variables is done in three steps, which are performed by the procedure gen variables (see subsection 2.2.2). Firstly, the set of possible local variables is initialized to empty by calling the procedure init loc types. Secondly, the transformed assignments of the current tree rule are traversed in search of the needed local variables. This is done by calling the procedure make all locals. Thirdly, the collected local variables are generated by calling the procedure gen locals. These procedures are described in the following subsections.

The needed intermediate local variables are collected in the global variable loc types (see subsection 6.4). In this global variable only the identifiers representing the type of the global variable are stored. One intermediate local variable of a certain type can be used more than once, even in the representation of a single expression, to store intermediate results of that type.

3.1 Initializing set of intermediate local variables

The procedure init local types initializes the global loc types by assigning all the elements of this array equal to the empty identifier. An empty identifier represents an unused intermediate local variable.

3.2 Collect intermediate local variables

The procedure make all locals collects all the used intermediate local variables used in the expressions of the transformed attribute assignments, represented by the first attribute tr ass rec. The second parameter class points to the class associated with the given transformed attribute assignments. This procedure calls the local procedure make locals for each expression found at the top level of the transformed attribute assignment tree that has to be evaluated according to the global variable attr to eval (see subsection 6.1). It calls itself recursively for all deeper parts of the transformed attribute assignments.

The procedure make locals collects the intermediate local variables in the expression pointed to by the first parameter expr ptr. The second parameter free loc contains the numbers of the local variables that have not been used so far. This procedure calls the local procedure for case when the expression is a case expression, and calls the local procedure for func when the expression is a semantic function expression.

The procedure for case calls the procedure make locals recursively for all the alternatives in the list pointed to by the parameter alter.

The procedure for func generates and collects the intermediate local variables for the list of arguments pointed to by the parameter args. For each of the arguments that is not equal to an attribute occurrence an intermediate local variable has to be generated. This is done by calling the procedure make a local, which also returns the name of the local variable that is stored in the field loc rep of the argument list (see also subsection 5.2). For each of these arguments the procedure make locals is also called recursively.

The procedure make a local generates an intermediate local variable with a type equal to the first parameter type of. The second parameter contains the set of free local variable names, and is updated by the procedure. The name of the intermediate local variable is returned in the third parameter loc rep. The procedure manipulates the global variable loc types. It searches this array for an intermediate local variable, which has been created before, that is free and has the correct type. If such an intermediate local variable does not exist, a new one is created and added to the array.

3.3 Generation of local variables

The procedure gen locals generates the local variable declarations based upon the current tree rule and the collected intermediate local variables, represented by the global variable loc types (see subsection 6.3). The local variable vars and the local procedure genvars are used to correctly generate the syntax of the variable declarations, depending on whether or not local variables are declared. The procedure gen locals calls the procedures gen one pass locals (described in the following subsection) and gen expression locals.

The procedure gen expression locals uses the global variable loc types to generate the declarations of the intermediate local variables.

3.3.1 Generating one pass local variables

The procedure gen one pass locals generates the declarations for the local variables that are used to represent the one pass attributes with the son elements of the current tree rule, which is represented by the global variable tree list (see subsection 6.2). This procedure calls the procedure gen for with the result of the function collect parametric attrs.

The procedure gen for generates the actual declarations for the one pass attributes, represented by the second parameter attrs, for the part with the number equal to the first parameter part nr.

The function collect parametric attributes collects all the attributes that are used as parametric one pass attributes with one of the left-hand side elements found in the class hierarchy beginning with the element represented by the parameter seek elem nr. If the element represented by the parameter is a left-hand side element, then all the one pass attributes are taken from the set of parametric attributes with this element. The function parametric attributes is used to determine the parametric attributes (see subsection 1.3), and the boolean function here one pass is used to determine whether a parametric attribute is also a one pass attribute with the given part of the tree rule.

If the element represented by the parameter seek elem nr is not a left-hand side element, then the union is returned from the recursive calls of the function parametric attributes for all elements in the class definition with this element.

It might seem that the approach taken here is somewhat inefficient (although that might be doubted), but it is a very clear and safe approach. If the definition of the function parametric attributes itself was changed, then the code for generating these local variables need not be changed.

4 Generation of assignments

The procedure gen assignments generate all the code (assignment statements and calls to tree walking procedures) which implement the attribute assignments for the part with number equal to the first parameter part nr. The second parameter kind attrs determines the kind of attributes (inherited or synthesized) for which the assignment statements have to be generated. This procedure is called by the procedure gen body (see subsection 2.2.3), with either the set of synthesized attributes or the set of inherited attributes as the value of the second parameter.

This procedure initializes the context variables ass p nr and ass p depth. The local variable sem rules is initialized. This variable contains pointers to the current branch of transformed assignments tree which belongs to the current part list history of the part for which code is generated. This variable is used by the local function find expr with, see subsection 4.1.2

This procedure calls the procedure gen ass from which traverses by recursive calls the transformed assignments tree of the current part. While traversing, it generates assignment statements and calls tree walking procedures that are needed for this pass. This procedure is described in the following subsection.

4.1 Generate assignments from a certain point

The procedure gen ass from generates the code from the position in the transformed assignments tree described by the context variables, see subsections 6.4 and 6.5 The first parameter this elem nr contains the element with the current position in the transformed assignments tree. The second parameter attrs to ass contains the set of attributes for which assignment statements have to be generated by this procedure.

This procedure generates code for the following three parts: the assignment statements for the current position in the transformed assignments tree, the code for deeper nested positions in the transformed assignments tree, and calls to the tree walking procedures. These three parts are described in the following three subsections. Each part is generated only when needed.

These three parts are included in a with-statement when the current part is not equal to the main part, or when the current depth (represented by the variable ass p depth) is not equal to zero. The local boolean variable with is used to indicated whether a with statement is used or not. The procedure gen with selector is called to generate the record variable list (selection field) of the with-statement.

When the current depth is equal to zero, the procedure gen with selector generates a record variable based on the current part name. The generated record variable is part of the typing used to represent the tree rule. When the current depth is not equal to zero, the procedure uses the parameter sel elem nr to generate a record variable which is part of the typing representing the class rules.

The local boolean variable block is used to indicated whether the statement in the with-statement is a compound statement or not.

4.1.2 Generate code for the assignments

The procedure gen all ass generates the assignment statements for the set of attributes represented by the parameter attr to ass. It is possible that this procedure is called with an empty set, in which case no assignments statements are generated at all. For each of the attributes the procedure gen expression (see section 5) is called. This procedure requires two arguments. The first argument represents the expression for which code has to be generated. This expression is found by calling the local function find expr with. The second parameter represents the name of the variable representing the attribute to which the assignment has to be made. This name is returned by the local function make attr name.

The function find expr with finds the expression belonging to the attribute represented by the parameter with attr nr in the current branch in the transformed assignments tree. The current branch is stored in the local variable sem rules.

The function make attr name returns the variable name representing the attribute occurrence of the attribute with attribute number equal to the first parameter this attr nr, at the part represented by the second parameter part nr.

4.1.3 Generate code for deeper positions

The procedure gen class generates the code for the positions in the transformed attribute assignment tree below the current position. This procedure is only called when the element with the current position is a class. The first parameter represents the attributes for which so far no assignment statements at higher positions has been generated. The second parameter class represents the class rule with the element of the current position. The third parameter ass ptr points to parts of the transformed assignments tree belonging to the elements of the class at the current position.

This procedure generates a case-statement. For each element in the set of elements represented by the parameter class an alternative is generated. The procedure gen ass from is called recursively to generate the statement of the alternative. Before and after calling this procedure the parameters representing the context (see 6.4 and 6.5) are updated.

4.1.4 Generate code for calling tree walking procedures

The procedure gen call to generates the call to a tree walking procedure which belongs to the element represented by the parameter call elem nr.

The local variable attrs is used to represent the attributes that has to be given to the procedure as parameters. The procedure parametric attributes is used to calculate this set of attributes. See subsection 3.3.1

The procedure here one pass is called to determine which attributes are implemented as one pass attributes.

5 Generation of expressions

The procedure gen expression generates the code for the expression represented by the first parameter expr ptr of type pexpr [bintree 1.4], whose value has to be assigned to the variable with the name equal to the second parameter localname.

The function take alter returns the expression of a specific alternative taken from the list of alternatives (pointed to by the second parameter alter of type plalt expr [bintree 1.4]). The alternative chosen is the one which has the element represented by the first parameter alter elem nr in its selector.

The procedure gen expression calls local procedures or itself recursively, depending on the kind of expression represented by the parameter expr ptr. If the expression is a simple expression, the local procedure gen simple expr is called. If the expression is a semantic function application, the local procedure gen function expr is called. If the expression is a case expression, either the local procedure gen case expr is called, or the procedure calls itself recursively. It calls itself recursively if the context in which the expression is generated already has a selection made on the part name of the case expression. The variables ass p nr, ass p depth and plh depth represent the context, see subsections 6.4 and 6.5

5.1 Generate simple expression

The procedure gen simple expr generates the assignment to the variable, represented by the parameter localname, with the value of the attribute occurrence which has the part name, represented by the first parameter part nr, and the attribute, represented by the second parameter with attr nr. The code representing this attribute occurrence is generated by the procedure gen applied attribute (see subsection 5.4).

5.2 Generate semantic function expression

The procedure gen function expr generates the code representing the semantic function call of the function with the name equal to the first parameter func name, and the arguments represented by the second parameter args of type plexpr [bintree 1.4].

The semantic functions are represented by procedures such that the first parameter is a reference parameter in which the result of the function is returned, and the other parameters contain the values of the argument expressions passed to the function.

In the most general case for the expression func(expr1,..,exprn) and the variable localname having the value "result", the following code is generated:

```BEGIN (* func *)
{ code for expr1 assigning result to loc1 };
....
{ code for exprn assigning result to locn };
func(result,loc1,..,locn)
END```

The local names (loc1 to locn) used in this piece of code are found in the record field loc rep of the type tlexpr [bintree 1.4]. This type is used to represent the argument list of the semantic function expression. These record fields have been initialized earlier by calling the procedure make all locals (see section 3.2). The code representing the expressions of the arguments is generated by calling the procedure gen expression recursively with the expression and the representation of the local variable to which the value has to be assigned.

There are two possible optimizations. Firstly, if one of the argument expressions is a simple expression (an attribute occurrence), there is no need to introduce a local variable, but the attribute occurrence can be generated as an argument of the generated procedure.

Secondly, if no local variables are needed at all, only the code for the procedure call to the procedure with the name func name is generated. For the "trivial" expression func(), and the variable localname having the value "result", the following code will be generated:

`func(result)`

5.3 Generate case expression

The procedure gen case expression generates the code representing the case expression on the part represented by the first parameter part nr, and the alternatives pointed to by the parameter alter of type plalt expr [bintree 1.4]. This procedure generates a case statement. The selector of the case expression is generated by the local procedure gen case kind. This procedure makes use of the context to generate the correct selector variable. The case list elements of the case statement are generated by calling the procedure gen alt. This procedure is called for each element of the current class of the part name of the case expression, with the right alternative taken from the list of alternatives pointed to by the parameter alter.

The procedure gen alt generates the code representing the expression pointed to by the second parameter expr, for the alternative with the element represented by the first parameter alt elem nr. This procedure generates the case label list of the case statement, which represents the element with the alternative. The context stored in the variable plh is updated, and the code for the expression is generated by calling the procedure gen expression recursively.

The part list history as represented by the variables plh and plh_depth is updated by the procedures gen case expr and gen alt, before the expressions in the alternatives are processed, and is restored afterwards.

5.4 Generate applied attribute occurrence

The procedure gen applied attribute generates the code for the applied attribute occurrence, with the attribute represented by the first parameter with attr nr, and the part represented by the second parameter part nr. This procedure first determines whether the attribute occurrence is stored in the abstract program tree, or whether it is passed as an argument to the evaluation procedure, or whether it is a one pass attribute. The local procedure normal is called when the attribute occurrence is stored in the abstract program tree. This local procedure uses the part list history and the information of the nested selective attribute assignments, to determine the correct way to address the storage of the attribute occurrence in the abstract program tree. The procedure gen part name is called to generate the representation of the part names. This procedure is described in the following subsection.

5.5 Generate part name

The procedure gen part name generates the code for the part name represented by the first parameter part nr. The second parameter condition is used to determine whether the extra record selection field name "" has to be generated. (See also [gtypes 2.3.2].)

6 Variables

In this section we describe the global variables that are local for this module. Some are used to represent relations and others to pass values from one procedure to another.

6.1 Representation of attribute relations

The global variable eval attr is used to represent the formal relation "eval attr of" for the current pass. See subsection 1.1

The global variable attr to eval is used to represent the formal relation "attributes to be evaluated" for the current pass. See subsection 1.1

The global variable attr at all is used to represent the formal relation "attributes at all" for the current pass. See subsection 1.1

6.2 Representation of local variables

While collecting the intermediate local variables (see subsection 3.2) the global variable loc types is used. This variable consists of an array of type identifiers. Each element represents a local variable. Whenever an element of this array has a non-empty type identifier it represents a local variable with the type equal its value. These are generated by the procedure gen locals, see subsection 3.3

6.3 Representation of the current element and tree rule

The variables in this subsection are initialized at the beginning of the procedure gen eval procedure, by the procedure init gen eval procedure, and are used in the procedures that generate the expressions and the assignments. The current element is the element represented by the first parameter of the procedure gen eval procedure, see subsection 2.2

The variable tree_list of type t_tree_list and the integer variable nr_of_parts represent the tree rule of the current element.

The variable imported of type t imported [bintree 1.7] contains the imported attributes (see [onepassrel 1]) of the elements defined with the parts of the current tree rule.

The variable imp root attr of type attributes contains the parametric attributes (see subsection 1.3) of the current element.

6.4 Representation of the part list history

The notion of a part list, as introduced in [2.11.2], can be extended to a part list history (plh). In this part list history the incremental updates on each part of the part list are recorded. The part list history is stored in the variable plh of type tplh, and the variable plh depth of type tplh depth. The variable plh depth represent the depth of the history (initially zero), and the elements plh[part nr,0] to plh[part nr,plh depth[part nr]] represent the history of the part with part number part nr. The part list is represented by the elements plh[part nr,plh depth[part nr]], where part nr varies. These variables are initialized by the procedure init gen eval procedure (see subsection 2.2.1), and are updated by the procedures gen case expression, gen alt (see subsection 5.3) and gen class (see subsection 4.1.3).

6.5 Representation of context while generating assignments

Together with the part list history, as described in the previous subsection, there are a number of variables used to describe the context while generating the assignments. The variable ass p nr is used to store the part number for which assignments are generated. The variable ass p depth contains the depth belonging to the part list history of the part equal to ass p nr. It is possible that the value of ass p depth is greater than the value of plh depth[ass p nr]. This happens in the case an assignment to an attributed associated with a class has to be made only for some of the elements in this class. See subsections 4.1.3 and 5

7 Interface

This module uses declarations from the following modules:

`screen, definitions, bintree, genpro.`

7.1 Exported procedures

We list the exported procedures, followed by a short description of their usage:

`PROCEDURE maketo_eval_and_at_all;`

This procedure calculates the relations "attributes to evaluate(E)" and "evaluate at all(E)" based on the relation "eval attr of(E)", which is stored in the global variable eval attr. The calculated relations are stored in the global variables attr to eval and attr at all, (respectively).

`PROCEDURE gen_header(this_elem_nr : integer; realy : boolean);`

This procedure generates the header for the evaluation procedure with element number this elem nr. When the boolean parameter realy is equal to TRUE, a real header is generated, otherwise curly brackets are substituted for the round brackets around the parameter declaration.

```PROCEDURE gen_eval_procedure(proc_elem_nr : integer;
L_direction : boolean);```

This procedure generates the evaluation procedure for the element with the number equal to the parameter proc elem nr. The boolean parameter L direction indicates whether a procedure for a left-to-right or right-to-left evaluation pass must be generated.

8 The listing

 ```[ENVIRONMENT ('gass.pen'), INHERIT ('[-.screen]screen.pen', 'definitions.pen', 'bintree.pen', 'genpro.pen')]MODULE genassignments(output); CONST max_nesting = 10; max_loc_nr = 71; TYPE (* Begin of the declaration for the free local variables *) loc_range = 0..max_loc_nr; tfree_loc = SET OF loc_range; tloc_types = ARRAY[0..max_loc_nr] OF alfa; (* Begin of the declarations for the part list history *) tplh_depth = ARRAY[0..max_part_nr] OF integer; tplh = ARRAY[0..max_part_nr, 0..max_nesting] OF integer; tassh = ARRAY[0..max_nesting] OF ttr_ass; (* VARIABLE DECLARATION *) VAR (* defined in GENERA, shared with this program and GASS, are : *) imported : t_imported; (* contains imported attributes *) eval_attr : tattr_at_elem; (* the attributes of the last pass *) (* local defined are : *) attr_to_eval , (* for attributes_to_eval(elem_nr) *) attr_at_all : tattr_at_elem; (* for evaluate_at_all(elem_nr) *) tree_list : t_tree_list; (* array that contains tree rule *) imp_root_attr : attributes; (* imported attributes at current elem_nr *) nr_of_parts , (* number of parts of current tree rule *) ass_p_nr , (* number of part name current assignment *) ass_p_depth : integer; (* depth of nested selective assignments *) plh : tplh; (* part list history *) plh_depth : tplh_depth; (* depths with part list history *) msg : [HIDDEN] text_info; (* used for add_level_inf *) ```

8.1 Here one pass function

 ``` FUNCTION here_one_pass(this_attr_nr, part_nr : integer) : boolean; (* This function tests whether the attribute at this part, in the context *) (* determined by the partlist history (in plh and plh_depth), is a one_pass *) (* attribute. In this case TRUE is returned, otherwise FALSE. *) VAR depth : integer; found : boolean; BEGIN enter_level('here_one_pass'); add_level_info( 'attr : ' + attribute[this_attr_nr]^.name + ' part : ' + tree_list[part_nr]^.partname); (* initialize depth to begin with : *) depth := succ(plh_depth[part_nr]); (* from this depth search back the element on which the attribute *) (* attribute is defined : *) REPEAT depth := pred(depth); found := this_attr_nr IN element[plh[part_nr, depth]]^.attr[nor_gen]; UNTIL found OR (depth = 0); (* find out whether it is a one pass attribute or not : *) IF found THEN here_one_pass := this_attr_nr IN implone_pass[plh[part_nr, depth]] ELSE (* test whether it is an imported one pass attribute *) here_one_pass := NOT (this_attr_nr IN imported[part_nr]); exit_level END; ```

8.2 Make attr-to-eval and attr-at-all

The procedure on this page generates two relations and a set that are used when generating the assignments.

 ``` PROCEDURE update_eval_attr; (* This procedure updates the relation eval_attr, which contains all the *) (* attributes with the elements that have to be evaluated in this pass, by *) (* subtracting all the input attributes. Because the SMP-algorithm always *) (* decides that those have to be evaluated in the first pass, this *) (* procedure is only called with the first pass. *) VAR elem_nr : integer; BEGIN FOR elem_nr := 0 TO nr_of_elem DO eval_attr[elem_nr] := eval_attr[elem_nr] - element[elem_nr]^.attr[all_in] END; PROCEDURE maketo_eval_and_at_all; (* This procedure generates the relations attributes_to_evaluate(E) and *) (* evaluate_at_all(E), which are implemented as attr_to_eval[elem_nr] and *) (* attr_at_all[elem_nr]. This procedure initializes attr_to_eval and *) (* attr_at_all, based on the relation eval_attr_of(E), implemented as the *) (* global variable eval_attr[elem_nr]. *) (* The relation attributes_to_eval(E) represents all attributes that have *) (* to be evaluated in the class-tree beginning with E. The formal *) (* definition is : *) (* *) (* DF attributes_to_eval(E) *) (* = eval_attr_of(E) *) (* UNION FORALL E' IN class(E) *) (* UNION attributes_to_eval(E') *) (* *) (* The relation evaluate_at_all(E) represents all the attributes that can *) (* be evaluated, everywhere where they have to be evaluated in the *) (* class-tree beginning with E. The formal definition is : *) (* *) (* DF attributes_at_all(E) *) (* = eval_attr_of(E) *) (* UNION IF E IN node types *) (* THEN EMPTY *) (* ELSE FORALL E' IN class(E) *) (* INTERSECTION attributes_at_all(E') *) (* FI *) VAR dummy1, dummy2 : attributes; done : elements; elem_nr : integer; PROCEDURE make_both(this_elem_nr : integer; VAR t_attr_to_eval, t_attr_at_all : attributes); (* This procedure returns the values for the two relations with element. *) (* If they have not been generated yet, this is done first. *) VAR n_attr_to_eval , n_attr_at_all : attributes; new_nr : integer; class : elements; BEGIN add_level_info('elem : ' + element[this_elem_nr]^.name); IF this_elem_nr IN done THEN BEGIN t_attr_to_eval := attr_to_eval[this_elem_nr]; t_attr_at_all := attr_at_all [this_elem_nr] END ELSE BEGIN class := element[this_elem_nr]^.class_rule; t_attr_to_eval := eval_attr[this_elem_nr]; IF class = [] THEN t_attr_at_all := [] ELSE BEGIN t_attr_at_all := [0..nr_of_elem]; new_nr := start_nr; REPEAT next_elem(new_nr, class); make_both(new_nr, n_attr_to_eval, n_attr_at_all); t_attr_to_eval := t_attr_to_eval + n_attr_to_eval; t_attr_at_all := t_attr_at_all * n_attr_at_all; UNTIL class = [] END; attr_to_eval[this_elem_nr] := t_attr_to_eval; attr_at_all [this_elem_nr] := t_attr_at_all + eval_attr[this_elem_nr]; done := done + [this_elem_nr] END END; BEGIN (* of make_to_eval_and_at_all *) enter_level('make_to_eval_and_at_all'); done := []; FOR elem_nr := 0 TO nr_of_elem DO make_both(elem_nr, dummy1, dummy2); exit_level END; FUNCTION parametric_attributes(this_elem_nr : integer) : attributes; (* This procedure returns the attributes that are implemented on the *) (* argument stack and have to generated as arguments and parameters of the *) (* evaluation procedures. *) (* Makes use of the global variables under_imple_one_pass and attr_to_eval. *) (* Called in gen_call_to, gen_header, gen_ass_from and *) (* init_gen_eval_procedure. *) BEGIN WITH element[this_elem_nr]^ DO parametric_attributes := (attr[all_gen] - attr[nor_gen] + under_impl_one_pass[this_elem_nr]) * attr_to_eval[this_elem_nr] END; ```

8.3 Make locals

The procedures on this page are concerned with the generation of local variables. They operate on the global variable loc types, which contains the alfa representation of the types of the locals. During the generation of the local variables, the variable free loc will contain the numbers of local variables that are not used. If they have been used loc types will still held the corresponding type, otherwise the alfa representation of the type equals empty alfa.

 ```VAR loc_types : tloc_types; PROCEDURE init_loc_types; (* This procedure initializes the loc_type variable, with only empty_alfa *) VAR nr : integer; BEGIN FOR nr := 0 TO max_loc_nr DO loc_types[nr].length := 0 END; PROCEDURE make_all_locals(tr_ass_rec : ttr_ass; class : pnode); (* This procedure generates all local variables for the transformed *) (* assignments represented by tr_ass_rec. *) VAR top_walker : plexpr; deeper_walker : pltr_ass; walk_attr_nr , deeper_elem_nr : integer; PROCEDURE make_locals(expr_ptr : pexpr; free_loc : tfree_loc); (* This procedure generates all local variables for the expression, *) (* pointed by expr_ptr, with the free local variables free_loc. *) PROCEDURE make_a_local(type_of :alfa; VAR free_loc : tfree_loc; VAR loc_rep : alfa); (* This procedure seeks the first local that can be taken as a local of *) (* type type_of, from the list of free locals, represented by free_loc. *) (* The number is subtracted from the set free_loc, and the *) (* representation is stored in loc_rep. *) VAR found : boolean; loc_nr : integer; BEGIN enter_level('make_a_local'); add_level_info('type : ' + type_of); IF free_loc = [] THEN (* max number of locals in one procedure exceeded *) loc_nr := max_loc_nr + 1 ELSE BEGIN loc_nr := start_nr; found := FALSE; REPEAT loc_nr := succ(loc_nr); IF loc_nr IN free_loc THEN IF loc_types[loc_nr] = type_of THEN found := TRUE ELSE IF loc_types[loc_nr].length = 0 THEN BEGIN loc_types[loc_nr] := type_of; found := TRUE END UNTIL found; free_loc := free_loc - [loc_nr] END; loc_rep := m_local(loc_nr); exit_level END; PROCEDURE for_func(args : plexpr); (* This procedure generates the local variables if the expression is a *) (* function expression. For every argument that is not a simple *) (* expression a local variable is generated. *) BEGIN add_level_info('for_func'); WHILE args <> NIL DO BEGIN WITH args^ DO IF first^.kind <> e_atoc THEN BEGIN make_a_local(type_of_arg, free_loc, loc_rep); make_locals(first, free_loc) END; args := args^.rest END END; PROCEDURE for_case(alter : plalt_expr); BEGIN add_level_info('for_case'); WHILE alter <> NIL DO BEGIN make_locals(alter^.expr, free_loc); alter := alter^.rest END END; BEGIN (* of make_locals *) enter_level('make_locals'); WITH expr_ptr^ DO CASE kind OF e_atoc : (* nothing *); e_func : for_func(args); e_case : for_case(alter) END; exit_level END; BEGIN (* of make_all_locals *) enter_level('make_all_locals'); WITH tr_ass_rec DO BEGIN top_walker := top; walk_attr_nr := start_nr; WHILE top_walker <> NIL DO BEGIN REPEAT walk_attr_nr := succ(walk_attr_nr) UNTIL walk_attr_nr IN ass_attr; IF walk_attr_nr IN attr_to_eval[class^.elem_nr] THEN make_locals(top_walker^.first, [0..max_loc_nr]); top_walker := top_walker^.rest END; deeper_walker := deeper; deeper_elem_nr := start_nr; WHILE deeper_walker <> NIL DO BEGIN WITH class^ DO REPEAT deeper_elem_nr := succ(deeper_elem_nr) UNTIL deeper_elem_nr IN class_rule; make_all_locals(deeper_walker^.first, element[deeper_elem_nr]); deeper_walker := deeper_walker^.rest END END; exit_level END; PROCEDURE gen_locals; (* This procedure generates the declaration of the local variables which *) (* are the variables used for the representation of one pass attributes *) (* and that are used when calculating expressions. *) VAR vars : boolean; PROCEDURE genvars; (* This procedure generates the keyword VAR, as this has not been done. *) BEGIN IF NOT vars THEN BEGIN gen_newline(1); gen_keyw(k_var); vars := TRUE END END; PROCEDURE gen_one_pass_locals; VAR part_nr : integer; PROCEDURE gen_for(part_nr : integer;{) with (}attrs : attributes); VAR this_attr_nr : integer; BEGIN enter_level('gen_for'); add_level_info( 'part : ' + tree_list[part_nr]^.partname); IF attrs <> [] THEN BEGIN genvars; this_attr_nr := start_nr; REPEAT next_attr(this_attr_nr, attrs); WITH attribute[this_attr_nr]^ DO BEGIN gen_newline(1); gen_(m_1p_attr(part_nr, this_attr_nr) + ' : ' + type_of_attr.type_name^.name + ';'); END UNTIL attrs = [] END; exit_level END; FUNCTION collect_parametric_attrs(seek_elem_nr : integer) : attributes; VAR result , class : elements; elem_nr : integer; attrs : attributes; walk_attr_nr : integer; BEGIN result := []; IF seek_elem_nr IN left_side_elements THEN BEGIN attrs := parametric_attributes(seek_elem_nr); walk_attr_nr := start_nr; WHILE attrs <> [] DO BEGIN next_attr(walk_attr_nr, attrs); IF here_one_pass(walk_attr_nr, part_nr) THEN result := result + [walk_attr_nr] END END ELSE BEGIN class := element[seek_elem_nr]^.class_rule; elem_nr := start_nr; WHILE class <> [] DO BEGIN next_elem(elem_nr, class); result := result + collect_parametric_attrs(elem_nr) END END; collect_parametric_attrs := result; END; BEGIN (* of gen_one_pass_locals *) enter_level('gen_one_pass_locals'); FOR part_nr := 1 TO nr_of_parts DO gen_for(part_nr, collect_parametric_attrs(tree_list[part_nr]^.element^.elem_nr)); exit_level END; PROCEDURE gen_expression_locals; VAR loc_nr : integer; more : boolean; BEGIN enter_level('gen_expression_locals'); IF loc_types[0].length <> 0 THEN (* local variables needed *) BEGIN genvars; loc_nr := 0; more := TRUE; WHILE more DO BEGIN gen_newline(1); gen_(m_local(loc_nr)); gen_tab(20); gen_(' : '); gen_(loc_types[loc_nr]+';'); loc_nr := succ(loc_nr); IF loc_nr > max_loc_nr THEN more := FALSE ELSE more := loc_types[loc_nr].length <> 0 END END; exit_level END; BEGIN (* of gen_locals *) enter_level('gen_locals'); vars := FALSE; gen_one_pass_locals; gen_expression_locals; IF vars THEN gen_keyw(k_s_end); exit_level END; ```

8.4 Generation of expressions

The following pages contain procedures that generate de code for the expressions.

 ```(* Information about the part list history is stored in the global variables *) (* plh and plh_depth. Plh_depth indicates how far plh is filled, in *) (* combination with ass_p_nr and ass_p_depth. For ass_p_nr plh is filled *) (* till the maximum of ass_p_depth and plh_depth[ass_p_nr]. *) (* For all allowed part_nr, plh[part_nr, 0] contains the element of the tree *) (* rule with part_nr, including the main element number. *) (* The global variable tree_list contains the information from the tree *) (* rule, together with information about the imported attributes at the *) (* elements with the tree rule. *) PROCEDURE gen_expression(expr_ptr : pexpr; localname : alfa); (* This procedure generates the code for the expression represented by *) (* expr_ptr, which value have to be stored in the variable with the name *) (* localname. *) PROCEDURE gen_part_name(part_nr : integer; condition : boolean); (* This procedure generates the part prefix. In case of the main symbol *) (* this is 'r_root.', otherwise the part name, with the postfix "r_.", if *) (* this part has imported attributes, and the condition is TRUE. *) BEGIN enter_level('gen_part_name'); writev(msg, condition:5); add_level_info( 'part : ' + tree_list[part_nr]^.partname + ' condition : ' + msg); IF part_nr <> main_part_nr THEN BEGIN gen_(tree_list[part_nr]^.partname+'.'); IF (imported[part_nr] <> []) AND condition THEN gen_('r_.') END ELSE gen_('r_root.'); exit_level END; PROCEDURE gen_applied_attribute(with_attr_nr, part_nr : integer); (* This procedure generates an applied attribute occurrence using the *) (* attribute with_attr_nr and the part part_nr, together with the global *) (* variables plh, ass_p_nr and ass_p_depth. *) PROCEDURE normal; (* This procedure takes care of the generation of the string in the *) (* normal case. *) VAR depth : integer; BEGIN IF part_nr = ass_p_nr THEN depth := ass_p_depth ELSE BEGIN gen_part_name(part_nr, NOT(with_attr_nr IN imported[part_nr])); depth := 0 END; WHILE NOT (with_attr_nr IN element[plh[part_nr, depth]]^.attr[all_gen]) DO BEGIN depth := succ(depth); gen_('n_' + m_elem(plh[part_nr, depth]) + '^.'); END; gen_(m_attr(with_attr_nr)) END; BEGIN (* of gen_applied_attribute *) enter_level('gen_applied_att'); add_level_info('attr : ' + attribute[with_attr_nr]^.name + ' part : ' + tree_list[part_nr]^.partname); IF part_nr = main_part_nr THEN IF with_attr_nr IN imp_root_attr THEN gen_('i_' + m_attr(with_attr_nr)) ELSE normal ELSE IF here_one_pass(with_attr_nr, part_nr) THEN gen_(m_1p_attr(part_nr, with_attr_nr)) ELSE normal; exit_level END; PROCEDURE gen_simple_expr(part_nr, with_attr_nr : integer); (* This procedure generates the code for a simple expression, using the *) (* localname, as the name of the variable in which the result is stored. *) BEGIN enter_level('gen_simple_expr'); gen_(localname + ' := '); gen_applied_attribute(with_attr_nr, part_nr); exit_level END; PROCEDURE gen_function_expr(func_name : alfa; args : plexpr); (* This procedure generates the code for the function call, for the *) (* function with the name name, and with arguments args. *) VAR hargs : plexpr; with_block : boolean; BEGIN enter_level('gen_function_ex'); add_level_info('name : ' + func_name); with_block := FALSE; hargs := args; WHILE hargs <> NIL DO BEGIN WITH hargs^,first^ DO IF kind <> e_atoc THEN BEGIN IF NOT with_block THEN BEGIN gen_keyw(k_begin); gen_(' (* ' + func_name + ' *)'); gen_newline(1); with_block := TRUE END; gen_expression(first, loc_rep); gen_(';'); gen_newline(1); END; hargs := hargs^.rest END; gen_(func_name + '(' + localname); hargs := args; WHILE hargs <> NIL DO BEGIN gen_(','); WITH hargs^, first^ DO IF kind <> e_atoc THEN gen_(loc_rep) ELSE gen_applied_attribute(attr^.attr_nr, partnamenr); hargs := hargs^.rest END; gen_(')'); IF with_block THEN gen_keyw(k_end); exit_level END; PROCEDURE gen_case_expr(part_nr : integer; alter : plalt_expr); (* This procedure generates the actual code for the case expression on *) (* part part_nr and with the alternatives represented by alter. *) VAR selector : elements; case_elem_nr : integer; PROCEDURE gen_case_kind; (* This procedure generates the selection variable for the case. *) VAR start , depth : integer; BEGIN enter_level('gen_case_kind'); IF part_nr = ass_p_nr THEN start := succ(ass_p_depth) ELSE BEGIN gen_part_name(part_nr, TRUE); start := 1 END; FOR depth := start TO plh_depth[part_nr] DO gen_('n_' + m_elem(plh[part_nr, depth]) + '^.'); gen_('k_ '); exit_level END; PROCEDURE gen_alt(alt_elem_nr : integer; expr : pexpr); (* This procedure generates one alternative of the case expression. *) VAR hold : integer; BEGIN enter_level('gen_alt'); add_level_info('elem : ' + element[alt_elem_nr]^.name); gen_newline(1); gen_(m_elem(alt_elem_nr) + ' : '); set_left_margin(hold); plh[part_nr, plh_depth[part_nr]] := alt_elem_nr; gen_expression(alter^.expr, localname); gen_(';'); reset_left_margin(hold); exit_level END; BEGIN (* gen_case_expression *) enter_level('gen_case_expres'); add_level_info('part : ' + tree_list[part_nr]^.partname); gen_keyw(k_case); gen_case_kind; gen_keyw(k_of); plh_depth[part_nr] := succ(plh_depth[part_nr]); WHILE alter <> NIL DO BEGIN selector := alter^.selectors; case_elem_nr := start_nr; WHILE selector <> [] DO BEGIN next_elem(case_elem_nr, selector); gen_alt(case_elem_nr, alter^.expr) END; alter := alter^.rest END; plh_depth[part_nr] := pred(plh_depth[part_nr]); gen_keyw(k_end); exit_level END; FUNCTION take_alter(alter_elem_nr : integer; alter : plalt_expr) : pexpr; (* This procedure returns the alternative from the alternatives *) (* represented by alter_ptr, that has alter_elem_nr in its selectors. *) BEGIN enter_level('take_alter'); add_level_info('elem_nr : ' + element[alter_elem_nr]^.name); WHILE NOT (alter_elem_nr IN alter^.selectors) DO alter := alter^.rest; take_alter := alter^.expr; exit_level END; BEGIN (* of gen_expression *) enter_level('gen_expression'); WITH expr_ptr^ DO CASE kind OF e_atoc : gen_simple_expr(partnamenr, attr^.attr_nr); e_func : gen_function_expr(func^.name, args); e_case : IF (headpnnr = ass_p_nr) AND (plh_depth[headpnnr] < ass_p_depth) THEN BEGIN plh_depth[headpnnr] := succ(plh_depth[headpnnr]); gen_expression (take_alter(plh[headpnnr, plh_depth[headpnnr]], alter) ,localname); plh_depth[headpnnr] := pred(plh_depth[headpnnr]) END ELSE gen_case_expr(headpnnr, alter) END; exit_level END; ```

8.5 Generation of assignments

 ``` PROCEDURE gen_assignments(part_nr : integer; kind_attrs : attributes); (* This procedure generates all the assignments for the part with part_nr. *) (* Where kind_attrs is either equal to g_syn_attrs or g_inh_attrs, depending on *) (* the kind of attributes that have to be evaluated. *) VAR sem_rules : ARRAY[0..max_nesting] OF ttr_ass; PROCEDURE gen_ass_from(this_elem_nr : integer; attrs_to_ass : attributes); (* This procedure generates the assignments from the semantic rules *) (* represented by sem_rules[ass_p_depth], with element this_elem_nr and *) (* the set of attributes attrs_to_evaluate, that have to be assigned. *) VAR block , with_ : boolean; PROCEDURE gen_with_selector(sel_elem_nr : integer); (* This procedure generates an field selector for a with statement at *) (* the selector assignment level, or a root pointer for an evaluation *) (* procedure. This procedure makes use of the global variables *) (* ass_p_nr and ass_p_depth. *) BEGIN enter_level('gen_with_select'); add_level_info('elem_nr : ' + element[sel_elem_nr]^.name); IF ass_p_depth = 0 THEN (* on top level *) BEGIN IF ass_p_nr <> main_part_nr THEN BEGIN gen_(tree_list[ass_p_nr]^.partname); IF imported[ass_p_nr] <> [] THEN gen_('.r_') END END ELSE gen_('n_' + m_elem(sel_elem_nr) + '^'); exit_level END; PROCEDURE gen_all_ass(attr_to_ass : attributes); (* This procedure generates assignments to the attributes *) (* attr_to_ass. *) VAR walk_attr_nr : integer; FUNCTION find_expr_with(with_attr_nr : integer) : pexpr; (* This function finds the expression that belongs with this attr_nr, *) (* using the rules in the global variable sem_rules, in combination *) (* with ass_p_nr and ass_p_depth. *) VAR depth , h_attr_nr : integer; lexpr_ptr : plexpr; BEGIN enter_level('find_expr_with'); writev(msg, 'attr : ', attribute[with_attr_nr]^.name, ' depth : ', ass_p_depth:2); add_level_info(msg); depth := ass_p_depth; WHILE NOT (with_attr_nr IN sem_rules[depth].ass_attr) DO depth := pred(depth); WITH sem_rules[depth] DO BEGIN lexpr_ptr := top; h_attr_nr := 0; WHILE h_attr_nr <> with_attr_nr DO BEGIN IF h_attr_nr IN ass_attr THEN lexpr_ptr := lexpr_ptr^.rest; h_attr_nr := succ(h_attr_nr) END END; find_expr_with := lexpr_ptr^.first; exit_level END; FUNCTION make_attr_name(this_attr_nr, part_nr : integer) : beta; (* This procedure generates the name of the attribute that has to *) (* be assigned. *) BEGIN enter_level('make_attr_name'); add_level_info('attr : ' + attribute[this_attr_nr]^.name + ' part : ' + tree_list[part_nr]^.partname); IF part_nr = main_part_nr THEN IF this_attr_nr IN imp_root_attr THEN make_attr_name := 'i_' + m_attr(this_attr_nr) ELSE make_attr_name := m_attr(this_attr_nr) ELSE IF here_one_pass(this_attr_nr, part_nr) THEN make_attr_name := m_1p_attr(part_nr, this_attr_nr) ELSE make_attr_name := m_attr(this_attr_nr); exit_level END; BEGIN (* gen_all_ass *) enter_level('gen_all_ass'); walk_attr_nr := start_nr; WHILE attr_to_ass <> [] DO BEGIN next_attr(walk_attr_nr, attr_to_ass); gen_newline(1); gen_expression(find_expr_with(walk_attr_nr), make_attr_name(walk_attr_nr, ass_p_nr)); gen_(';') END; exit_level END; PROCEDURE gen_class(left_over : attributes; class : elements; ass_ptr : pltr_ass); (* This procedure generates the code for the class elements in class *) (* with the assignments represented by ass_ptr. With the attributes *) (* left_over, which have not been assigned yet. *) VAR new_nr , hold : integer; BEGIN enter_level('gen_class'); gen_newline(1); gen_keyw(k_case); gen_('k_ '); gen_keyw(k_of); ass_p_depth := succ(ass_p_depth); new_nr := start_nr; WHILE class <> [] DO BEGIN next_elem(new_nr, class); sem_rules[ass_p_depth] := ass_ptr^.first; ass_ptr := ass_ptr^.rest; plh[ass_p_nr, ass_p_depth] := new_nr; gen_newline(1); gen_(m_elem(new_nr) + ' : '); set_left_margin(hold); gen_ass_from(new_nr, left_over); IF class <> [] THEN gen_(';'); reset_left_margin(hold) END; ass_p_depth := pred(ass_p_depth); gen_keyw(k_end); gen_(';'); exit_level END; PROCEDURE gen_call_to(call_elem_nr : integer); (* This procedure generates a call to the evaluation procedure for the *) (* the element with call_elem_nr. *) VAR attrs : attributes; walk_attr_nr , hold : integer; BEGIN enter_level('gen_call_to'); add_level_info( 'elem_nr : ' + element[call_elem_nr]^.name); gen_('e_' + m_elem(call_elem_nr) + '('); set_left_margin(hold); IF ass_p_depth = 0 THEN BEGIN gen_(tree_list[ass_p_nr]^.partname); IF imported[ass_p_nr] <> [] THEN gen_('.r_') END ELSE gen_('n_' + m_elem(call_elem_nr) + '^'); attrs := parametric_attributes(call_elem_nr); walk_attr_nr := start_nr; WHILE attrs <> [] DO BEGIN next_elem(walk_attr_nr, attrs); gen_(','); IF here_one_pass(walk_attr_nr, ass_p_nr) THEN gen_(m_1p_attr(ass_p_nr, walk_attr_nr)) ELSE gen_(m_attr(walk_attr_nr)) END; gen_(')'); reset_left_margin(hold); exit_level END; BEGIN (* of gen_ass_from *) enter_level('gen_ass_from'); block := FALSE; with_ := FALSE; WITH element[this_elem_nr]^ DO IF (attr_to_eval[this_elem_nr] * kind_attrs <> []) OR ( (ass_p_nr <> main_part_nr) AND (clos_class * left_side_elements <> [])) THEN BEGIN IF (ass_p_nr <> main_part_nr) OR (ass_p_depth <> 0) THEN BEGIN gen_keyw(k_with); gen_with_selector(this_elem_nr); gen_newline(1); gen_keyw(k_do); with_ := TRUE END; gen_keyw(k_begin); block := TRUE; attrs_to_ass := attrs_to_ass + attr_to_eval[this_elem_nr] * attr[nor_gen] * kind_attrs; gen_all_ass(attrs_to_ass * attr_at_all[this_elem_nr]); IF kind = n_class THEN gen_class(attrs_to_ass - attr_at_all[this_elem_nr], class_rule, sem_rules[ass_p_depth].deeper); END; IF (this_elem_nr IN left_side_elements) AND (ass_p_nr <> main_part_nr) THEN BEGIN IF block THEN gen_newline(1); gen_call_to(this_elem_nr); END; IF block THEN gen_keyw(k_end); IF with_ THEN gen_keyw(k_od); exit_level END; BEGIN (* of gen_assignments *) enter_level('gen_assignments'); add_level_info('part : ' + tree_list[part_nr]^.partname); gen_newline(1); ass_p_nr := part_nr; ass_p_depth := 0; sem_rules[ass_p_depth] := tree_list[ass_p_nr]^.trans_ass; WITH tree_list[part_nr]^.element^ DO gen_ass_from(elem_nr, attr_to_eval[elem_nr] * attr[all_gen] * kind_attrs); gen_(';'); exit_level END; ```
 ``` PROCEDURE gen_header(this_elem_nr : integer; realy : boolean); (* This procedure generates the header for the evaluation procedure with *) (* element number this_elem_nr. When the boolean realy is true, a real *) (* header is generated, when it is false the round brackets are *) (* substituted for comment brackets. *) VAR attr_parameters : attributes; walk_attr_nr , hold : integer; BEGIN gen_keyw(k_procedure); gen_('e_' + m_elem(this_elem_nr)); IF realy THEN gen_('(') ELSE gen_('{'); set_left_margin(hold); gen_keyw(k_varref); gen_('r_root : t_' + m_elem(this_elem_nr)); attr_parameters := parametric_attributes(this_elem_nr); walk_attr_nr := start_nr; WHILE attr_parameters <> [] DO BEGIN next_attr(walk_attr_nr, attr_parameters); gen_('; '); gen_keyw(k_varref); gen_('i_' + m_attr(walk_attr_nr) + ' : ' + attribute[walk_attr_nr]^.type_of_attr.type_name^.name); END; IF realy THEN gen_(');') ELSE gen_('};'); reset_left_margin(hold) END; PROCEDURE gen_eval_procedure(proc_elem_nr : integer; L_direction : boolean); (* This procedure generates the evaluation procedure that belongs with *) (* element proc_elem_nr. It makes use of global information stored in the *) (* global variables. *) PROCEDURE init_gen_eval_procedure; (* This procedure does the initialization of the global variables used in *) (* the generation process for this generation of an evaluation procedure. *) (* It initializes the variable tree_list, which will contain the tree *) (* list of the current element. And also nr_of_parts. *) (* It initializes the variable imported, which holds for every part name *) (* the imported attributes, equal to the all_gen minus the nor_gen *) (* attributes, of the elements associated with it. *) (* It initializes the partlist history, together with the ass_nr_depth *) (* variable. *) VAR part_nr : integer; BEGIN enter_level('init_gen_eval_procedure'); imp_root_attr := parametric_attributes(proc_elem_nr); tree_list := element[proc_elem_nr]^.tree_list^; nr_of_parts := element[proc_elem_nr]^.nr_of_parts; FOR part_nr := 0 TO nr_of_parts DO WITH tree_list[part_nr]^.element^ DO BEGIN imported[part_nr] := impattr_at[elem_nr]; plh_depth[part_nr] := 0; plh[part_nr, 0] := elem_nr END; exit_level END; PROCEDURE gen_variables; (* This procedure generates the variables for this evaluation procedure. *) VAR part_nr : integer; BEGIN enter_level('gen_variables'); init_loc_types; FOR part_nr := 0 TO nr_of_parts DO WITH tree_list[part_nr]^ DO make_all_locals(trans_ass, element); gen_locals; exit_level END; PROCEDURE gen_body; (* This procedure generates the body of the evaluation procedure. *) VAR part_nr : integer; BEGIN enter_level('gen_body'); gen_newline(1); gen_keyw(k_begin); gen_newline(1); gen_keyw(k_with); gen_('r_root'); gen_newline(1); gen_keyw(k_do); gen_keyw(k_begin); IF L_direction THEN FOR part_nr := 1 TO nr_of_parts DO gen_assignments(part_nr, g_inh_attr) ELSE FOR part_nr := nr_of_parts DOWNTO 1 DO gen_assignments(part_nr, g_inh_attr); gen_assignments(main_part_nr, g_syn_attr); gen_keyw(k_end); gen_keyw(k_od); gen_keyw(k_end); gen_(';'); gen_newline(1); exit_level END; BEGIN (* of gen_eval_procedure *) enter_level('gen_eval_procedure'); writev(msg, 'elem : ', element[proc_elem_nr]^.name, ' Left : ',L_direction:5); add_level_info(msg); init_gen_eval_procedure; gen_newline(2); gen_header(proc_elem_nr, FALSE); (* not forward *) gen_variables; gen_body; exit_level END; END. ```