This module contains the procedure that generates the PASCAL code for the attribute evaluator.
The procedure gen program generates the entire program, based on the grammar read by the first pass, which is stored in types described in [bintree]. The parameters partition, part dir, one pass set and nr of passes describe the Simple Multi Pass solution that must be used. See also [allsmp].
Before any part of the program is generated two initializations are done. Firstly, the procedure make tree list is called, which constructs an alternative representation [bintree 1.7]. This alternative representation is used by the procedures that generated the tree walking procedures [gass 2].
Secondly, the one pass attribute relations are constructed. The global variable one pass attr [onepassrel 1] is initialized by calling the procedure make attr at elem for [allsmp 2.2], and the other relations derived from this relation are constructed by calling the procedure makeone pass relations [onepassrel 2].
After the generation file has been opened (by calling open genfl [genpro 1]), the header of the program is generated. Next, the global variables and the external procedure declarations are generated by calling the local procedures gen global variables and gen extern procedures, respectively.
In each pass, where the number of passes is determined by the parameter nr of passes, an evaluation procedure is generated, representing the attribute evaluations of that pass. To do this the following actions are taken. Firstly, the set of attributes that have to be evaluated is calculated by calling the procedure make attr at elem for [allsmp 2.2], and using the parameter partition. Secondly, the procedures update eval attr and maketo eval and at all [gass 1.2] are called, which constructs a number of attribute relations, which are used while generating the tree walking procedures. The procedure update eval attr is only called for the first pass. Thirdly, the procedure gen this pass is called, with the indication of the evaluation direction of the pass, taken from the parameter part dir. This procedure is described in the following section.
Finally the body of the program is generated, which consists of calls to the procedures that implement each pass.
The procedure gen this pass generates the PASCAL code for the pass with the number equal to the first parameter nr, and an evaluation direction determined by the second parameter L direction. A left-to-right evaluation strategy is used when L direction is TRUE, otherwise a right-to-left evaluation strategy is used.
The generated pass evaluation procedure consists of three parts: the header, the declaration of local procedures, and the body. The local procedures that are generated represent the tree walking and attribute evaluating procedures. For each left side element such a tree walking procedure is generated. The body of the generated pass evaluation procedure consists of a call to the appropriate local tree walking procedure for the root element.
For each left hand side element a tree walking and attribute evaluating procedure must be generated. The generated tree walking procedures call each other recursively. Because of this, the forward declarations of the headers of the tree walking procedures are first generated. This is done by calling the procedure gen header [gass 2.1]. Next, the bodies of the tree walking procedures are generated by calling the procedure gen eval procedure [gass 2.2].
This module uses declarations from the following modules:
screen, perform, definitions, bintree, allsmp, genpro, onepassrel, gtypes, gass.
The following procedure is exported by this module:
PROCEDURE gen_program(partition : tpartition; part_dir : tpart_dir; one_pass_set : tset_node; nr_of_passes : integer);
[ENVIRONMENT ('generator.pen'), INHERIT ('[-.screen]screen.pen', 'perform.pen', 'definitions.pen', 'bintree.pen', 'allsmp.pen', 'genpro.pen', 'onepassrel.pen', 'gtypes.pen', 'gass.pen')] MODULE generator; CONST apsgn_file = '-inputfile :'; apsgn_question = '-question : '; yes_or_no = '(y/n)'; question_length = 20; TYPE query = VARYING[question_length] OF char; |
PROCEDURE gen_global_variables; (* This procedure generates the global variables for the evaluator. *) (* Those are: s_root. *) BEGIN enter_level('gen_global_variables'); gen_newline(1); gen_keyw(k_var); gen_newline(1); gen_('s_root : t_' + m_elem(root^.elem_nr) + ';'); gen_keyw(k_s_end); exit_level END; PROCEDURE gen_extern_procedures; (* This procedure generates the extern procedure declarations, using the *) (* information stored on the function save file, generated by PARSER. *) (* The functions in the semantic rules are implemented as procedures, with *) (* one VAR result argument, followed by n arg<i> arguments. The semantic *) (* function declaration : *) (* *) (* <func_name>(<arg_type1>, .. ,<arg_typen>) : <result_type>. *) (* *) (* PROCEDURE <func_name>(VAR result : <result_type>; *) (* arg_A : <arg_type1>; .. arg_x : <arg_typen>); EXTERN; *) (* *) PROCEDURE seek_functions(root : pnode); (* seeks for the function definitions in the binary identifier tree and *) (* generates the external procedures that belong to it. *) PROCEDURE gen_a_extern_procedure(func : pnode); (* This procedure generates one external procedure. *) VAR result_type : alfa; hold : integer; PROCEDURE gen_arguments(args : pltype); (* This procedure generates the arguments declaration. *) VAR ch : char; BEGIN ch := 'A'; WHILE args <> NIL DO BEGIN gen_('; arg_' + ch + ' : ' + args^.first.type_name^.name); ch := succ(ch); args := args^.rest END END; BEGIN (* of gen_a_extern_procedures *) enter_level('gen_a_extern_procedure'); WITH func^ DO BEGIN gen_newline(1); gen_keyw(k_procedure); gen_(name + '('); set_left_margin(hold); gen_keyw(k_varref); gen_('result : ' + type_of_func.type_name^.name); gen_arguments(args); gen_('); EXTERN;'); reset_left_margin(hold) END; exit_level END; BEGIN (* of seek_functions *) IF root <> NIL THEN WITH root^ DO BEGIN seek_functions(left); add_level_info(name); IF kind = n_func THEN gen_a_extern_procedure(root); seek_functions(right) END END; BEGIN (* of gen_extern_procedures *) enter_level('seek_functions'); seek_functions(nametree); exit_level END; |
PROCEDURE gen_program(partition : tpartition; part_dir : tpart_dir; one_pass_set : tset_node; nr_of_passes : integer); (* This procedure generates the whole program, making use of the *) (* information stored in the bintree and the variables element and *) (* attribute, which are global for this procedure and the procedures that *) (* are called. The generation process is controlled by the input parameters *) (* that contain the SMP-solution. *) (* nr_of_passes = the number of passes of the solution. *) (* partition = for each pass the attribute-element pairs that have to *) (* evaluated in the pass. *) (* part_dir = for each pass the evaluation direction of the pass. *) (* one_pass_attr = the attribute-element pairs that have the one-pass *) (* property. *) (* remark: both partition and one_pass_set make use of the internal graph *) (* representation used in the SMP-algorithm. For conversion we make *) (* use of the procedure make_attr_at_elem_for, as explained further *) (* on. *) (* *) (* BEGIN *) (* make_tree_lists; *) (* gen_program_header; *) (* gen_types; *) (* gen_global_variables; *) (* gen_extern_procedures; *) (* *) (* make_attr_at_elem_for( one_pass_set, one_pass_attr ); *) (* makeone_pass_relations; *) (* *) (* FOR pass_nr := 1 TO nr_of_passes *) (* DO BEGIN *) (* make_attr_at_elem_for( partition[pass_nr], eval_attr ); *) (* make_to_eval_and_at_all; *) (* gen_this_pass( pass_nr, part_dir[pass_nr] = left ) *) (* END; *) (* *) (* gen_body_of_program *) (* END *) (* *) (* Global variables used : *) (* one_pass_attr : tattr_at_elem = for each element the attributes at the *) (* element that have the one-pass property. *) (* eval_attr : tattr_at_elem = for each element the attributes at the *) (* element to be evaluated in the current pass. *) VAR pass_nr : integer; PROCEDURE make_tree_lists; (* This procedure fills the tree_list and nr_of_parts fields of all *) (* left side elements. The tree_list field contains an alternative *) (* representation of the information already stored in the trans_ass and *) (* tree_rule fields of the element. The nr_of_parts field will contain *) (* the number of part names in the tree rule. These fields are used in the*) (* generation procedures. *) (* *) (* functionality of the tree_list and nr_of_parts : *) (* *) (* ALL left_side_elem_nr IN left_side_elements *) (* WITH element[left_side_elem_nr]^ *) (* ALL 0 <= nr <= nr_of_parts *) (* WITH tree_list^[nr]^ *) (* partname = name of part nr, whereby name of part 0 = "#" *) (* element = element of part nr *) (* trans_ass = transformed attribute assignments of part nr *) VAR left_elem_nr : integer; htree_rule : ptree_rule; msg : VARYING[60] OF char; BEGIN enter_level('make_tree_lists'); FOR left_elem_nr := 0 TO nr_of_elem DO IF left_elem_nr IN left_side_elements THEN WITH element[left_elem_nr]^ DO BEGIN add_level_info('elem : ' + name); (* add element for part 0 at tree_rule in htree_rule : *) new(htree_rule); htree_rule^.partname := main_part_name; htree_rule^.element := element[left_elem_nr]; htree_rule^.trans_ass := trans_ass; htree_rule^.rest := tree_rule; new(tree_list); (* fill tree_list with content of htree_rule : *) nr_of_parts := start_nr; WHILE htree_rule <> NIL DO BEGIN nr_of_parts := nr_of_parts + 1; tree_list^[nr_of_parts] := htree_rule; htree_rule := htree_rule^.rest END END; exit_level END; PROCEDURE gen_this_pass(nr : integer; L_direction : boolean); (* This procedure generates the evaluation procedures for the nr-th pass *) (* in a left-to-right pass if L_direction is TRUE, otherwise in a right- *) (* to-left pass. *) (* *) (* BEGIN *) (* gen_main_procedure_heading_for_this_pass; *) (* *) (* FOR left_elem_nr := 0 TO nr_of_elems *) (* DO IF left_elem_nr IN left_side_elements *) (* THEN BEGIN *) (* gen_header(left_elem_nr, TRUE); *) (* gen_('FORWARD;') *) (* END; *) (* *) (* FOR left_elem_nr := 0 TO nr_of_elems *) (* DO IF left_elem_nr IN left_side_elements *) (* THEN gen_eval_procedure(left_elem_nr, L_direction); *) (* *) (* gen_body_main_evaluation_procedure_for_this_pass *) (* END; *) (* *) VAR left_elem_nr : integer; msg : text_info; BEGIN enter_level('gen_this_pass'); writev(msg, 'pass nr : ', nr:2); add_level_info(msg); (* Generate procedure heading for this pass *) gen_newline(1); gen_keyw(k_procedure); write(genfl, 'e_valpass', nr:1, ';'); shift_margin(2); gen_newline(1); (* Generate forward declarations for all procedures *) FOR left_elem_nr := 0 TO nr_of_elem DO IF left_elem_nr IN left_side_elements THEN BEGIN gen_newline(1); gen_header(left_elem_nr, TRUE); gen_keyw(k_forward); gen_(';') END; (* Generate procedure bodies *) FOR left_elem_nr := 0 TO nr_of_elem DO IF left_elem_nr IN left_side_elements THEN gen_eval_procedure(left_elem_nr,L_direction); shift_margin(-2); gen_newline(2); (* Generate body of evaluation procedure *) gen_keyw(k_begin); write(genfl, '(* of e_valpass', nr:1 ,' *)'); gen_newline(1); gen_('e_' + m_elem(root^.elem_nr) + '(s_root)'); gen_keyw(k_end); gen_(';'); exit_level END; BEGIN (* of gen_program *) perf_start_time(perf_g_decl); make_tree_lists; (* make one pass relations *) make_attr_at_elem_for(one_pass_set, one_pass_attr); makeone_pass_relations; (* generate program header and types *) open_genfl; gen_keyw(k_program); gen_('evaluator;'); gen_newline(3); gentypes; (* generate extern procedures *) gen_newline(2); gen_global_variables; gen_newline(2); shift_margin(2); gen_extern_procedures; gen_page; {gen_readtree;} perf_end_time (perf_g_decl); (* generate evaluation procedures for the passes *) perf_start_time(perf_g_prgr); FOR pass_nr := 1 TO nr_of_passes DO BEGIN gen_page; make_attr_at_elem_for(partition[pass_nr], eval_attr); IF pass_nr = 1 THEN update_eval_attr; maketo_eval_and_at_all; gen_this_pass(pass_nr, part_dir[pass_nr] = left) END; shift_margin(-2); gen_page; (* generate body of program *) gen_keyw(k_begin); gen_newline(1); {gen_('r_eadtree;');} FOR pass_nr := 1 TO nr_of_passes DO BEGIN gen_newline(1); gen_('e_valpass' + chr(pass_nr MOD 10 + ord('0'))); END; gen_keyw(k_end); gen_('.'); perf_end_time (perf_g_prgr) END; END. |
My life as a hacker | My home page