home *** CD-ROM | disk | FTP | other *** search
-
- unit LexOpt;
-
- (* 2-5-91 AG *)
-
- (* Copyright (c) 1990,91 by Albert Graef, Schillerstr. 18,
- 6509 Schornsheim/Germany
- All rights reserved *)
-
- interface
-
- (* DFA optimization algorithm.
- This is an efficient (O(n log(n)) DFA optimization procedure based on the
- algorithm given in Aho/Sethi/Ullman, 1986, Section 3.9. *)
-
- procedure optimizeDFATable;
- (* optimize the state table *)
-
- implementation
-
- uses LexBase, LexTables;
-
- (* Partition table used in DFA optimization: *)
-
- const
-
- max_parts = max_states; (* number of partitions of equivalent states; at
- worst, each state may be in a partition by
- itself *)
-
- type
-
- PartTable = array [0..max_states-1] of IntSetPtr;
- (* state partitions (DFA optimization) *)
-
- StatePartTable = array [0..max_states-1] of Integer;
- (* partition number of states *)
-
- var
-
- (* partition table: *)
-
- n_parts : Integer;
- part_table : ^PartTable;
- state_part : ^StatePartTable;
-
- (* optimized state and transition table: *)
-
- n_opt_states : Integer;
- n_opt_trans : Integer;
- opt_state_table : ^StateTable;
- opt_trans_table : ^TransTable;
-
-
- function equivStates(i, j : Integer) : Boolean;
- (* checks whether states i and j are equivalent; two states are considered
- equivalent iff:
- - they cover the same marker positions (/ and endmarkers of rules)
- - they have transitions on the same symbols/characters, and corresponding
- transitions go to states in the same partition
- two different start states are never considered equivalent *)
- var ii, jj, k : Integer;
- mark_pos_i, mark_pos_j : IntSet;
- begin
- (* check for start states: *)
- if (i<=2*n_start_states+1) and (j<=2*n_start_states+1) and
- (i<>j) then
- begin
- equivStates := false;
- exit;
- end;
- (* check end positions: *)
- empty(mark_pos_i);
- with state_table^[i] do
- for k := 1 to size(state_pos^) do
- if pos_table^[state_pos^[k]].pos_type=mark_pos then
- include(mark_pos_i, state_pos^[k]);
- empty(mark_pos_j);
- with state_table^[j] do
- for k := 1 to size(state_pos^) do
- if pos_table^[state_pos^[k]].pos_type=mark_pos then
- include(mark_pos_j, state_pos^[k]);
- if not equal(mark_pos_i, mark_pos_j) then
- begin
- equivStates := false;
- exit
- end;
- (* check transitions: *)
- if n_state_trans(i)<>n_state_trans(j) then
- equivStates := false
- else
- begin
- ii := state_table^[i].trans_lo;
- jj := state_table^[j].trans_lo;
- for k := 0 to pred(n_state_trans(i)) do
- if (trans_table^[ii+k].cc^<>trans_table^[jj+k].cc^) then
- begin
- equivStates := false;
- exit
- end
- else if state_part^[trans_table^[ii+k].next_state]<>
- state_part^[trans_table^[jj+k].next_state] then
- begin
- equivStates := false;
- exit
- end;
- equivStates := true;
- end
- end(*equivStates*);
-
- procedure optimizeDFATable;
-
- var
- i, ii, j : Integer;
- act_part, new_part, n_new_parts : Integer;
-
- begin
-
- n_parts := 0;
-
- (* Initially, create one partition containing ALL states: *)
-
- n_parts := 1;
- part_table^[0] := newIntSet;
- for i := 0 to n_states-1 do
- begin
- include(part_table^[0]^, i);
- state_part^[i] := 0;
- end;
-
- (* Now, repeatedly pass over the created partitions, breaking up
- partitions if they contain nonequivalent states, until no more
- partitions have been added during the last pass: *)
-
- repeat
- n_new_parts := 0; act_part := 0;
- new_part := n_parts;
- part_table^[new_part] := newIntSet;
- while (n_parts<n_states) and (act_part<n_parts) do
- begin
- for i := 2 to size(part_table^[act_part]^) do
- if not equivStates(part_table^[act_part]^[1],
- part_table^[act_part]^[i]) then
- (* add to new partition: *)
- include(part_table^[new_part]^, part_table^[act_part]^[i]);
- if size(part_table^[new_part]^)<>0 then
- begin
- (* add new partition: *)
- inc(n_parts); inc(n_new_parts);
- (* remove new partition from old one: *)
- setminus(part_table^[act_part]^, part_table^[new_part]^);
- (* update partition assignments: *)
- for i := 1 to size(part_table^[new_part]^) do
- state_part^[part_table^[new_part]^[i]] := new_part;
- inc(new_part);
- part_table^[new_part] := newIntSet;
- end;
- inc(act_part);
- end;
- until n_new_parts=0;
-
- (* build the optimized state table: *)
-
- n_opt_states := n_parts;
- n_opt_trans := 0;
- for i := 0 to n_parts-1 do
- begin
- ii := part_table^[i]^[1];
- opt_state_table^[i] := state_table^[ii];
- with opt_state_table^[i] do
- begin
- trans_lo := n_opt_trans+1;
- trans_hi := n_opt_trans+1+state_table^[ii].trans_hi-
- state_table^[ii].trans_lo;
- for j := 2 to size(part_table^[i]^) do
- setunion(state_pos^, state_table^[
- part_table^[i]^[j]].state_pos^);
- end;
- for j := state_table^[ii].trans_lo to state_table^[ii].trans_hi do
- begin
- inc(n_opt_trans);
- opt_trans_table^[n_opt_trans] := trans_table^[j];
- with opt_trans_table^[n_opt_trans] do
- next_state := state_part^[next_state];
- end;
- end;
-
- (* update state table: *)
-
- n_states := n_opt_states;
- n_trans := n_opt_trans;
- state_table^ := opt_state_table^;
- trans_table^ := opt_trans_table^;
-
- end(*optimizeDFATable*);
-
- begin
- new(part_table);
- new(state_part);
- new(opt_state_table);
- new(opt_trans_table);
- end(*LexOpt*).