Commit 8e270475 authored by POTTIER Francois's avatar POTTIER Francois
Browse files

Temporary state where the new FOLLOW computation is checked to

produce the same result as the old one.
parent 5238c909
......@@ -881,6 +881,61 @@ end = struct
end
(* ------------------------------------------------------------------------ *)
(* The computation of FOLLOW sets does not follow the above model. Instead, we
need to explicitly compute a system of equations over sets of terminal
symbols (in a first pass), then solve the constraints (in a second
pass). *)
(* A member of an equation's right-hand side is either a variable (named after
a nonterminal symbol) or a constant (a set of terminal symbols). *)
type member =
| MemberVar of Nonterminal.t
| MemberConstant of TerminalSet.t
(* A right-hand side is a list of members. *)
type rhs =
member list
(* A system of equations is represented as an array, which maps nonterminal
symbols to right-hand sides. *)
type equations =
rhs array
(* This solver computes the least solution of a set of equations. *)
let solve (eqs : equations) : Nonterminal.t -> TerminalSet.t =
let member m get =
match m with
| MemberVar nt ->
get nt
| MemberConstant c ->
c
in
let rhs rhs get =
(* Union of all members. *)
List.fold_left (fun accu m ->
TerminalSet.union accu (member m get)
) TerminalSet.empty rhs
in
let nonterminal nt get =
rhs eqs.(nt) get
in
let module F =
Fix.Make
(Maps.ConsecutiveIntegerKeysToImperativeMaps(Nonterminal))
(TerminalSet)
in
F.lfp nonterminal
(* ------------------------------------------------------------------------ *)
(* Generic support for fixpoint computations.
......@@ -1158,6 +1213,56 @@ let () =
done
)
(* ------------------------------------------------------------------------ *)
(* Compute FOLLOW sets. *)
let follow' =
let follow : equations =
Array.make Nonterminal.n []
in
(* Iterate over all start symbols. *)
let sharp = MemberConstant (TerminalSet.singleton Terminal.sharp) in
for nt = 0 to Nonterminal.start - 1 do
assert (Nonterminal.is_start nt);
(* Add # to FOLLOW(nt). *)
follow.(nt) <- sharp :: follow.(nt)
done;
(* We need to do this explicitly because our start productions are
of the form S' -> S, not S' -> S #, so # will not automatically
appear into FOLLOW(S) when the start productions are examined. *)
(* Iterate over all productions. *)
Array.iteri (fun prod (nt1, rhs) ->
(* Iterate over all nonterminal symbols [nt2] in the right-hand side. *)
Array.iteri (fun i symbol ->
match symbol with
| Symbol.T _ ->
()
| Symbol.N nt2 ->
let nullable = NULLABLE.production prod (i+1)
and first = FIRST.production prod (i+1) in
(* The FIRST set of the remainder of the right-hand side
contributes to the FOLLOW set of [nt2]. *)
follow.(nt2) <- MemberConstant first :: follow.(nt2);
(* If the remainder of the right-hand side is nullable,
FOLLOW(nt1) contributes to FOLLOW(nt2). *)
if nullable then
follow.(nt2) <- MemberVar nt1 :: follow.(nt2)
) rhs
) Production.table;
solve follow
(* Sanity check. *)
let () =
for nt = 0 to Nonterminal.n - 1 do
let f = follow nt
and f'= follow' nt in
assert (TerminalSet.equal f f')
done
(* ------------------------------------------------------------------------ *)
(* Provide explanations about FIRST sets. *)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment