123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- {
- Yacc closure and first set construction algorithms. See Aho/Sethi/Ullman,
- 1986, Sections 4.4 and 4.7, for further explanation.
- Copyright (c) 1990-92 Albert Graef <[email protected]>
- Copyright (C) 1996 Berend de Boer <[email protected]>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Revision: 1.2 $
- $Modtime: 96-07-31 14:09 $
- $History: YACCCLOS.PAS $
- *
- * ***************** Version 2 *****************
- * User: Berend Date: 96-10-10 Time: 21:16
- * Updated in $/Lex and Yacc/tply
- * Updated for protected mode, windows and Delphi 1.X and 2.X.
- }
- unit YaccClos;
- interface
- procedure closures;
- (* compute the closure sets *)
- procedure first_sets;
- (* compute first sets and nullable flags *)
- implementation
- uses YaccBase, YaccTabl;
- 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*).
|