home *** CD-ROM | disk | FTP | other *** search
-
- unit YaccClosure;
-
- (* 2-16-91 AG *)
-
- (* Copyright (c) 1990,91 by Albert Graef, Schillerstr. 18,
- 6509 Schornsheim/Germany
- All rights reserved *)
-
- interface
-
- (* Yacc closure and first set construction algorithms. See Aho/Sethi/Ullman,
- 1986, Sections 4.4 and 4.7, for further explanation. *)
-
- procedure closures;
- (* compute the closure sets *)
-
- procedure first_sets;
- (* compute first sets and nullable flags *)
-
- implementation
-
- uses YaccBase, YaccTables;
-
- procedure closures;
-
- (* The closure set of a nonterminal X is the set of all nonterminals Y
- s.t. Y appears as the first symbol in a rightmost derivation from the
- nonterminal X (i.e. X =>+ Y ... in a rightmost derivation). We can
- easily compute closure sets as follows:
- - Initialize the closure set for any nonterminal X to contain all
- nonterminals Y for which there is a rule X : Y ...
- - Now repeatedly pass over the already constructed sets, and for
- any nonterminal Y which has already been added to the closure set
- of some nonterminal X, also include the closure elements of Y in
- the closure set of X.
- The algorithm terminates as soon as no additional symbols have been
- added during the previous pass. *)
-
- var sym, i, count, prev_count : Integer;
- act_syms : IntSet;
-
- begin
- (* initialize closure sets: *)
- prev_count := 0;
- count := 0;
- for sym := 1 to n_nts do
- begin
- closure_table^[sym] := newEmptyIntSet;
- with rule_offs^[sym] do
- for i := rule_lo to rule_hi do
- with rule_table^[rule_no^[i]]^ do
- if (rhs_len>0) and (rhs_sym[1]<0) then
- include(closure_table^[sym]^, rhs_sym[1]);
- inc(count, size(closure_table^[sym]^));
- end;
- (* repeated passes until no more symbols have been added during the last
- pass: *)
- while prev_count<count do
- begin
- prev_count := count;
- count := 0;
- for sym := 1 to n_nts do
- begin
- act_syms := closure_table^[sym]^;
- for i := 1 to size(act_syms) do
- setunion(closure_table^[sym]^, closure_table^[-act_syms[i]]^);
- inc(count, size(closure_table^[sym]^));
- end;
- end;
- end(*closures*);
-
- procedure first_sets;
-
- (* The first set of a nonterminal X is the set of all literal symbols
- y s.t. X =>+ y ... in some derivation of the nonterminal X. In
- addition, X is nullable if the empty string can be derived from X.
- Using the first set construction algorithm of Aho/Sethi/Ullman,
- Section 4.4, the first sets and nullable flags are computed as
- follows:
-
- For any production X -> y1 ... yn, where the yi are grammar symbols,
- add the symbols in the first set of y1 (y1 itself if it is a literal)
- to the first set of X; if y1 is a nullable nonterminal, then proceed
- with y2, etc., until either all yi have been considered or yi is non-
- nullable (or a literal symbol). If all of the yi are nullable (in
- particular, if n=0), then also set nullable[X] to true.
-
- This procedure is repeated until no more symbols have been added to any
- first set and none of the nullable flags have been changed during the
- previous pass. *)
-
- var i, j, l, sym : Integer;
- n, null, done : Boolean;
-
- begin
- (* initialize tables: *)
- for sym := 1 to n_nts do
- begin
- nullable^[sym] := false;
- first_set_table^[sym] := newEmptyIntSet;
- end;
- (* repeated passes until no more symbols added and no nullable flags
- modified: *)
- repeat
- done := true;
- for i := 1 to n_rules do
- with rule_table^[i]^ do
- begin
- l := size(first_set_table^[-lhs_sym]^);
- n := nullable^[-lhs_sym];
- null := true;
- j := 1;
- while (j<=rhs_len) and null do
- begin
- if rhs_sym[j]<0 then
- begin
- setunion( first_set_table^[-lhs_sym]^,
- first_set_table^[-rhs_sym[j]]^ );
- null := nullable^[-rhs_sym[j]];
- end
- else
- begin
- include( first_set_table^[-lhs_sym]^,
- rhs_sym[j] );
- null := false;
- end;
- inc(j);
- end;
- if null then nullable^[-lhs_sym] := true;
- if (l<size(first_set_table^[-lhs_sym]^)) or
- (n<>nullable^[-lhs_sym]) then
- done := false;
- end;
- until done;
- end(*first_sets*);
-
- end(*YaccClosure*).
-
-