yacclook.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. {
  2. Yacc lookahead computation. This implementation is based on the
  3. lookahead set algorithm described in Aho/Sethi/Ullman, 1986,
  4. Section 4.7.
  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: 1.2 $
  19. $Modtime: 96-07-31 14:09 $
  20. $History: YACCLOOK.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 YaccLook;
  28. interface
  29. procedure lookaheads;
  30. (* computes the LALR lookahead sets and enters corresponding reductions
  31. into the redn table (sorted w.r.t. rule numbers) *)
  32. implementation
  33. uses YaccBase, YaccTabl;
  34. (* This implementation is based on algorithms 4.12 and 4.13 in Aho/Sethi/
  35. Ullman 1986 (with some optimizations added), which avoid the need to
  36. construct the full LR(1) set, and are able to compute lookaheads from
  37. LR(0) kernel items only.
  38. We start off with the LR(0) state set together with corresponding (shift
  39. and goto) transitions already computed. We compute the LALR(1) lookahead
  40. sets for kernel items and also record all corresponding reduce actions
  41. in the reduction table (where we also have to consider nonkernel items
  42. with empty right-hand side; these items also call for a reduction, but
  43. never appear in the kernel item table).
  44. This implementation uses some simple optimizations to speed up the
  45. algorithm. The lookahead sets are represented by (IntSet) pointers.
  46. Lookahead sets are associated with each kernel item in the item table,
  47. and with each reduction in the reduction table. A kernel item
  48. calling for a reduction shares its lookahead set pointer with the
  49. corresponding entry in the reduction table. The lookahead set for
  50. a nonkernel reduction item (item with empty right-hand side) only
  51. appears in the reduction table.
  52. The algorithm consists of two phases:
  53. 1. Initialization:
  54. The initialization phase consists of a single traversal of the LR(0)
  55. set, where we compute lookahead sets generated spontaneously (lookaheads
  56. which are passed on from nonkernel items to the corresponding items in
  57. successor states), initialize lookahead sets and enter them into the
  58. lookahead and reduction table. Furthermore, during the initialization
  59. phase we also initialize the links for the propagation of lookaheads
  60. in the second phase.
  61. To determine lookaheads and propagation links, we compute the look-
  62. aheads for the closures of single LR(0) sets "in the small", according
  63. to the method in Aho/Sethi/Ullman 1986 (with some modifications),
  64. where we associate with each kernel item i a corresponding endmarker
  65. symbol #i as its lookahead symbol.
  66. The initialization phase proceeds as follows:
  67. 1) Initialize all nonkernel item lookahead sets to empty.
  68. Now we pass over each state s in the LR0 set, repeating steps 2) thru
  69. 5) specified below:
  70. 2) Compute the closure closure(K(s)) of the states's kernel set K(s).
  71. 3) Compute the lookahead sets for closure(K(s)) (described in detail
  72. below) where each kernel item i is associated with a special
  73. endmarker symbol #i as lookahead.
  74. Now the lookahead symbols, reductions and propagation links are entered
  75. into the corresponding tables as follows:
  76. 4) Process kernel items: Add a propagation link from the kernel item
  77. to the lookahead set of the linked item in the corresponding
  78. successor state (as specified by the next field). If there is no
  79. successor item (kernel item calling for a reduction), add a
  80. corresponding entry into the reduction table instead.
  81. 5) Process nonkernel items: find the corresponding kernel item in the
  82. successor state which is generated spontaneously from the nonkernel
  83. item. Add the spontaneous lookahead symbols (except endmarker
  84. symbols) of the nonkernel item determined in step 3) to the kernel
  85. item. If the nonkernel item has an empty right-hand side (nonkernel
  86. item calling for a reduction), add a corresponding entry into the
  87. reduction table instead. Furthermore, for each endmarker symbol
  88. #i in the spontaneous lookahead set of the nonkernel item, add
  89. a corresponding propagation link from the ith kernel item to the
  90. lookahead set of the spontaneous kernel item.
  91. To compute the spontaneous lookaheads (step 3)), we proceed as follows:
  92. 3a) First compute the first sets of tail strings of all items in
  93. closure(K(s)). The "tail string" of an item [ X -> v.Yw ], where
  94. Y is a nonterminal, is the symbol sequence w, whose first set
  95. induces corresponding spontaneous lookaheads in the nonkernel
  96. items of the state with left-hand side Y; note that the first
  97. sets of "tail strings" in items [ X -> v.yw ], where y is a
  98. *terminal* symbol, are not required and hence it is not
  99. necessary to compute them. We also record for each item whether
  100. its tail string is "nullable", i.e., may be derived to the empty
  101. string. In this case, the item also passes on its own lookaheads,
  102. in addition to the first symbols of its tail string. First sets
  103. and nullable flags are computed using the information in YaccTable's
  104. first and nullable tables.
  105. 3b) Now follows an initialization part in which each item [ X -> v.Yw ]
  106. passes on the first symbols of its tail string to the lookahead
  107. sets of each corresponding nonkernel item [ Y -> .u ].
  108. 3c) Finally, we repeatedly pass over the item set, passing on
  109. lookaheads from items with nullable tail strings. Each item
  110. [ X -> v.Yw ] with nullable w propagates its own lookaheads to
  111. all corresponding nonkernel items [ Y -> .u]. Step 3c) terminates
  112. as soon as no lookahead sets have been modified during the previous
  113. pass.
  114. 2. Propagation:
  115. The second phase of the lookahead computation algorithm now is quite
  116. simple. We repeatedly pass over all kernel items, propagating lookaheads
  117. according to the propagation links determined in the initialization
  118. phase. The algorithm terminates as soon as no lookahead sets have been
  119. modified during the previous pass. *)
  120. (* Data structures used in lookahead computation: *)
  121. type
  122. SymSetArray = array [1..max_set_items] of IntSet;
  123. BoolArray = array [1..max_set_items] of Boolean;
  124. var
  125. item_set : ItemSet;
  126. lookahead_set : SymSetArray;
  127. n_kernel_items : Integer;
  128. procedure spontaneous_lookaheads;
  129. (* compute spontaneous lookaheads for item_set; negative symbols are
  130. used for endmarkers (-i denotes endmarker #i) *)
  131. var count, last_count, i : Integer;
  132. first_syms : SymSetArray;
  133. nullable : BoolArray;
  134. function sym_count ( n : Integer ) : Integer;
  135. (* count lookahead symbols *)
  136. var count, i : Integer;
  137. begin
  138. count := 0;
  139. for i := 1 to n do
  140. inc(count, size(lookahead_set[i]));
  141. sym_count := count;
  142. end(*sym_count*);
  143. procedure compute_first_syms ( i : Integer );
  144. (* compute first set and nullable flag for tail string of item
  145. number i *)
  146. var j : Integer;
  147. begin
  148. empty(first_syms[i]); nullable[i] := true;
  149. with item_set, item[i], rule_table^[rule_no]^ do
  150. if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) then
  151. begin
  152. j := pos_no+1;
  153. while (j<=rhs_len) and nullable[i] do
  154. begin
  155. if rhs_sym[j]<0 then
  156. begin
  157. setunion(first_syms[i], first_set_table^[-rhs_sym[j]]^);
  158. nullable[i] := YaccTabl.nullable^[-rhs_sym[j]];
  159. end
  160. else
  161. begin
  162. include(first_syms[i], rhs_sym[j]);
  163. nullable[i] := false;
  164. end;
  165. inc(j);
  166. end;
  167. end;
  168. end(*compute_first_syms*);
  169. procedure init_lookaheads ( i : Integer );
  170. (* compute initial lookaheads induced by first sets of tail string
  171. of item i *)
  172. var sym, j : Integer;
  173. begin
  174. with item_set, item[i], rule_table^[rule_no]^ do
  175. if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) then
  176. begin
  177. sym := rhs_sym[pos_no];
  178. for j := n_kernel_items+1 to n_items do
  179. with item[j], rule_table^[rule_no]^ do
  180. if lhs_sym=sym then
  181. setunion(lookahead_set[j], first_syms[i]);
  182. end
  183. end(*initial_lookaheads*);
  184. procedure propagate ( i : Integer );
  185. (* propagate lookahead symbols of item i *)
  186. var sym, j : Integer;
  187. begin
  188. with item_set, item[i], rule_table^[rule_no]^ do
  189. if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) and nullable[i] then
  190. begin
  191. sym := rhs_sym[pos_no];
  192. for j := n_kernel_items+1 to n_items do
  193. with item[j], rule_table^[rule_no]^ do
  194. if lhs_sym=sym then
  195. setunion(lookahead_set[j], lookahead_set[i]);
  196. end
  197. end(*propagate*);
  198. begin(*spontaneous_lookaheads*)
  199. with item_set do
  200. begin
  201. (* initialize kernel lookahead sets: *)
  202. for i := 1 to n_kernel_items do singleton(lookahead_set[i], -i);
  203. (* compute first sets and nullable flags: *)
  204. for i := 1 to n_items do compute_first_syms(i);
  205. (* initialize nonkernel lookahead sets: *)
  206. for i := n_kernel_items+1 to n_items do empty(lookahead_set[i]);
  207. for i := 1 to n_items do init_lookaheads(i);
  208. (* repeated passes until no more lookaheads have been added
  209. during the previous pass: *)
  210. count := sym_count(n_items);
  211. repeat
  212. last_count := count;
  213. for i := 1 to n_items do
  214. propagate(i);
  215. count := sym_count(n_items);
  216. until last_count=count;
  217. end;
  218. end(*spontaneous_lookaheads*);
  219. {$ifndef fpc}{$F+}{$endif}
  220. function redns_less ( i, j : Integer ) : Boolean;
  221. {$ifndef fpc}{$F-}{$endif}
  222. begin
  223. redns_less := redn_table^[i].rule_no<redn_table^[j].rule_no
  224. end(*redns_less*);
  225. {$ifndef fpc}{$F+}{$endif}
  226. procedure redns_swap ( i, j : Integer );
  227. {$ifndef fpc}{$F-}{$endif}
  228. var x : RednRec;
  229. begin
  230. x := redn_table^[i];
  231. redn_table^[i] := redn_table^[j];
  232. redn_table^[j] := x;
  233. end(*redns_swap*);
  234. procedure sort_redns;
  235. (* sort reduction entries in act_state w.r.t. rule numbers *)
  236. begin
  237. with state_table^[act_state] do
  238. quicksort(redns_lo, redns_hi, {$ifdef fpc}@{$endif}redns_less,
  239. {$ifdef fpc}@{$endif}redns_swap);
  240. end(*sort_redns*);
  241. procedure initialize;
  242. (* initialization phase of lookahead computation algorithm *)
  243. procedure add_prop ( i : Integer; symset : IntSetPtr );
  244. (* add a propagation link to kernel item i *)
  245. var prop : PropList;
  246. begin
  247. new(prop);
  248. prop^.symset := symset;
  249. prop^.next := prop_table^[i];
  250. prop_table^[i] := prop;
  251. end(*add_prop*);
  252. var i, j, k : Integer;
  253. lookaheads : IntSetPtr;
  254. begin
  255. (* initialize lookahead sets and propagation links: *)
  256. for i := 1 to n_items do lookahead_table^[i] := newEmptyIntSet;
  257. for i := 1 to n_items do prop_table^[i] := nil;
  258. act_state := 0;
  259. repeat
  260. with state_table^[act_state], item_set do
  261. begin
  262. start_redns;
  263. get_item_set(act_state, item_set);
  264. n_kernel_items := n_items;
  265. (* compute LR(0) closure: *)
  266. closure(item_set);
  267. (* compute spontaneous lookaheads: *)
  268. spontaneous_lookaheads;
  269. (* process kernel items: *)
  270. for i := 1 to n_kernel_items do with item[i] do
  271. if next>0 then
  272. (* add propagation link: *)
  273. add_prop(item_lo+i-1, lookahead_table^[next])
  274. else
  275. (* enter reduce action: *)
  276. add_redn(lookahead_table^[item_lo+i-1], rule_no);
  277. (* process nonkernel items: *)
  278. (* find successor items: *)
  279. for k := trans_lo to trans_hi do
  280. with trans_table^[k] do
  281. for i := n_kernel_items+1 to n_items do
  282. with item[i], rule_table^[rule_no]^ do
  283. if pos_no>rhs_len then
  284. next := 0
  285. else if rhs_sym[pos_no]=sym then
  286. next := find_item(next_state, rule_no, pos_no+1);
  287. (* add spontaneous lookaheads and propagation links: *)
  288. for i := n_kernel_items+1 to n_items do with item[i] do
  289. if next>0 then
  290. (* lookaheads are generated spontaneously for successor
  291. item: *)
  292. for j := 1 to size(lookahead_set[i]) do
  293. if lookahead_set[i][j]>=0 then
  294. include(lookahead_table^[next]^, lookahead_set[i][j])
  295. else
  296. add_prop(item_lo+(-lookahead_set[i][j])-1,
  297. lookahead_table^[next])
  298. else
  299. (* nonkernel reduction item: *)
  300. begin
  301. lookaheads := newEmptyIntSet;
  302. for j := 1 to size(lookahead_set[i]) do
  303. if lookahead_set[i][j]>=0 then
  304. include(lookaheads^, lookahead_set[i][j])
  305. else
  306. add_prop(item_lo+(-lookahead_set[i][j])-1,
  307. lookaheads);
  308. add_redn(lookaheads, rule_no);
  309. end;
  310. end_redns;
  311. sort_redns;
  312. end;
  313. inc(act_state);
  314. until act_state=n_states;
  315. end(*initialize*);
  316. procedure propagate;
  317. (* propagation phase of lookahead computation algorithm *)
  318. var i, l : Integer;
  319. done : Boolean;
  320. prop : PropList;
  321. begin
  322. (* repeated passes over the kernel items table until no more lookaheads
  323. could be added in the previous pass: *)
  324. repeat
  325. done := true;
  326. for i := 1 to n_items do
  327. begin
  328. prop := prop_table^[i];
  329. while prop<>nil do with prop^ do
  330. begin
  331. l := size(symset^);
  332. setunion(symset^, lookahead_table^[i]^);
  333. if size(symset^)>l then done := false;
  334. prop := next;
  335. end;
  336. end;
  337. until done;
  338. end(*propagate*);
  339. procedure lookaheads;
  340. begin
  341. initialize;
  342. propagate;
  343. end(*lookaheads*);
  344. end(*YaccLookaheads*).