lexopt.pas 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. {
  2. DFA optimization algorithm.
  3. This is an efficient (O(n log(n)) DFA optimization procedure based on the
  4. algorithm given in Aho/Sethi/Ullman, 1986, Section 3.9.
  5. Copyright (c) 1990-92 Albert Graef <[email protected]>
  6. Copyright (C) 1996 Berend de Boer <[email protected]>
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. $Revision$
  19. $Modtime: 96-08-01 6:29 $
  20. $History: LEXOPT.PAS $
  21. *
  22. * ***************** Version 2 *****************
  23. * User: Berend Date: 96-10-10 Time: 21:16
  24. * Updated in $/Lex and Yacc/tply
  25. * Updated for protected mode, windows and Delphi 1.X and 2.X.
  26. }
  27. unit LexOpt;
  28. interface
  29. procedure optimizeDFATable;
  30. (* optimize the state table *)
  31. implementation
  32. uses LexBase, LexTable;
  33. (* Partition table used in DFA optimization: *)
  34. const
  35. max_parts = max_states; (* number of partitions of equivalent states; at
  36. worst, each state may be in a partition by
  37. itself *)
  38. type
  39. PartTable = array [0..max_states-1] of IntSetPtr;
  40. (* state partitions (DFA optimization) *)
  41. StatePartTable = array [0..max_states-1] of Integer;
  42. (* partition number of states *)
  43. var
  44. (* partition table: *)
  45. n_parts : Integer;
  46. part_table : ^PartTable;
  47. state_part : ^StatePartTable;
  48. (* optimized state and transition table: *)
  49. n_opt_states : Integer;
  50. n_opt_trans : Integer;
  51. opt_state_table : ^StateTable;
  52. opt_trans_table : ^TransTable;
  53. function equivStates(i, j : Integer) : Boolean;
  54. (* checks whether states i and j are equivalent; two states are considered
  55. equivalent iff:
  56. - they cover the same marker positions (/ and endmarkers of rules)
  57. - they have transitions on the same symbols/characters, and corresponding
  58. transitions go to states in the same partition
  59. two different start states are never considered equivalent *)
  60. var ii, jj, k : Integer;
  61. mark_pos_i, mark_pos_j : IntSet;
  62. begin
  63. (* check for start states: *)
  64. if (i<=2*n_start_states+1) and (j<=2*n_start_states+1) and
  65. (i<>j) then
  66. begin
  67. equivStates := false;
  68. exit;
  69. end;
  70. (* check end positions: *)
  71. empty(mark_pos_i);
  72. with state_table^[i] do
  73. for k := 1 to size(state_pos^) do
  74. if pos_table^[state_pos^[k]].pos_type=mark_pos then
  75. include(mark_pos_i, state_pos^[k]);
  76. empty(mark_pos_j);
  77. with state_table^[j] do
  78. for k := 1 to size(state_pos^) do
  79. if pos_table^[state_pos^[k]].pos_type=mark_pos then
  80. include(mark_pos_j, state_pos^[k]);
  81. if not equal(mark_pos_i, mark_pos_j) then
  82. begin
  83. equivStates := false;
  84. exit
  85. end;
  86. (* check transitions: *)
  87. if n_state_trans(i)<>n_state_trans(j) then
  88. equivStates := false
  89. else
  90. begin
  91. ii := state_table^[i].trans_lo;
  92. jj := state_table^[j].trans_lo;
  93. for k := 0 to pred(n_state_trans(i)) do
  94. if (trans_table^[ii+k].cc^<>trans_table^[jj+k].cc^) then
  95. begin
  96. equivStates := false;
  97. exit
  98. end
  99. else if state_part^[trans_table^[ii+k].next_state]<>
  100. state_part^[trans_table^[jj+k].next_state] then
  101. begin
  102. equivStates := false;
  103. exit
  104. end;
  105. equivStates := true;
  106. end
  107. end(*equivStates*);
  108. procedure optimizeDFATable;
  109. var
  110. i, ii, j : Integer;
  111. act_part, new_part, n_new_parts : Integer;
  112. begin
  113. n_parts := 0;
  114. (* Initially, create one partition containing ALL states: *)
  115. n_parts := 1;
  116. part_table^[0] := newIntSet;
  117. for i := 0 to n_states-1 do
  118. begin
  119. include(part_table^[0]^, i);
  120. state_part^[i] := 0;
  121. end;
  122. (* Now, repeatedly pass over the created partitions, breaking up
  123. partitions if they contain nonequivalent states, until no more
  124. partitions have been added during the last pass: *)
  125. repeat
  126. n_new_parts := 0; act_part := 0;
  127. new_part := n_parts;
  128. part_table^[new_part] := newIntSet;
  129. while (n_parts<n_states) and (act_part<n_parts) do
  130. begin
  131. for i := 2 to size(part_table^[act_part]^) do
  132. if not equivStates(part_table^[act_part]^[1],
  133. part_table^[act_part]^[i]) then
  134. (* add to new partition: *)
  135. include(part_table^[new_part]^, part_table^[act_part]^[i]);
  136. if size(part_table^[new_part]^)<>0 then
  137. begin
  138. (* add new partition: *)
  139. inc(n_parts); inc(n_new_parts);
  140. (* remove new partition from old one: *)
  141. setminus(part_table^[act_part]^, part_table^[new_part]^);
  142. (* update partition assignments: *)
  143. for i := 1 to size(part_table^[new_part]^) do
  144. state_part^[part_table^[new_part]^[i]] := new_part;
  145. inc(new_part);
  146. part_table^[new_part] := newIntSet;
  147. end;
  148. inc(act_part);
  149. end;
  150. until n_new_parts=0;
  151. (* build the optimized state table: *)
  152. n_opt_states := n_parts;
  153. n_opt_trans := 0;
  154. for i := 0 to n_parts-1 do
  155. begin
  156. ii := part_table^[i]^[1];
  157. opt_state_table^[i] := state_table^[ii];
  158. with opt_state_table^[i] do
  159. begin
  160. trans_lo := n_opt_trans+1;
  161. trans_hi := n_opt_trans+1+state_table^[ii].trans_hi-
  162. state_table^[ii].trans_lo;
  163. for j := 2 to size(part_table^[i]^) do
  164. setunion(state_pos^, state_table^[
  165. part_table^[i]^[j]].state_pos^);
  166. end;
  167. for j := state_table^[ii].trans_lo to state_table^[ii].trans_hi do
  168. begin
  169. inc(n_opt_trans);
  170. opt_trans_table^[n_opt_trans] := trans_table^[j];
  171. with opt_trans_table^[n_opt_trans] do
  172. next_state := state_part^[next_state];
  173. end;
  174. end;
  175. (* update state table: *)
  176. n_states := n_opt_states;
  177. n_trans := n_opt_trans;
  178. state_table^ := opt_state_table^;
  179. trans_table^ := opt_trans_table^;
  180. end(*optimizeDFATable*);
  181. begin
  182. new(part_table);
  183. new(state_part);
  184. new(opt_state_table);
  185. new(opt_trans_table);
  186. end(*LexOpt*).