 ### More beautiful grammar of expressions, using binary unions instead

`of flat lists.`
parent 74b133ce
 ... @@ -887,45 +887,35 @@ end ... @@ -887,45 +887,35 @@ end symbols (in a first pass), then solve the constraints (in a second symbols (in a first pass), then solve the constraints (in a second pass). *) pass). *) (* A member of an equation's right-hand side is either a variable (named after (* An equation's right-hand side is a set expression. *) a nonterminal symbol) or a constant (a set of terminal symbols). *) type member = type expr = | MemberVar of Nonterminal.t | EVar of Nonterminal.t | MemberConstant of TerminalSet.t | EConstant of TerminalSet.t | EUnion of expr * expr (* 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 (* A system of equations is represented as an array, which maps nonterminal symbols to right-hand sides. *) symbols to expressions. *) type equations = type equations = rhs array expr array (* This solver computes the least solution of a set of equations. *) (* This solver computes the least solution of a set of equations. *) let solve (eqs : equations) : Nonterminal.t -> TerminalSet.t = let solve (eqs : equations) : Nonterminal.t -> TerminalSet.t = let member m get = let rec expr e get = match m with match e with | MemberVar nt -> | EVar nt -> get nt get nt | MemberConstant c -> | EConstant c -> c c in | EUnion (e1, e2) -> TerminalSet.union (expr e1 get) (expr e2 get) let rhs rhs get = (* Union of all members. *) List.fold_left (fun accu m -> TerminalSet.union accu (member m get) ) TerminalSet.empty rhs in in let nonterminal nt get = let nonterminal nt get = rhs eqs.(nt) get expr eqs.(nt) get in in let module F = let module F = ... @@ -1054,15 +1044,15 @@ let follow : Nonterminal.t -> TerminalSet.t = ... @@ -1054,15 +1044,15 @@ let follow : Nonterminal.t -> TerminalSet.t = symbols. *) symbols. *) let follow : equations = let follow : equations = Array.make Nonterminal.n [] Array.make Nonterminal.n (EConstant TerminalSet.empty) in in (* Iterate over all start symbols. *) (* Iterate over all start symbols. *) let sharp = MemberConstant (TerminalSet.singleton Terminal.sharp) in let sharp = EConstant (TerminalSet.singleton Terminal.sharp) in for nt = 0 to Nonterminal.start - 1 do for nt = 0 to Nonterminal.start - 1 do assert (Nonterminal.is_start nt); assert (Nonterminal.is_start nt); (* Add # to FOLLOW(nt). *) (* Add # to FOLLOW(nt). *) follow.(nt) <- sharp :: follow.(nt) follow.(nt) <- EUnion (sharp, follow.(nt)) done; done; (* We need to do this explicitly because our start productions are (* We need to do this explicitly because our start productions are of the form S' -> S, not S' -> S #, so # will not automatically of the form S' -> S, not S' -> S #, so # will not automatically ... @@ -1080,11 +1070,11 @@ let follow : Nonterminal.t -> TerminalSet.t = ... @@ -1080,11 +1070,11 @@ let follow : Nonterminal.t -> TerminalSet.t = and first = FIRST.production prod (i+1) in and first = FIRST.production prod (i+1) in (* The FIRST set of the remainder of the right-hand side (* The FIRST set of the remainder of the right-hand side contributes to the FOLLOW set of [nt2]. *) contributes to the FOLLOW set of [nt2]. *) follow.(nt2) <- MemberConstant first :: follow.(nt2); follow.(nt2) <- EUnion (EConstant first, follow.(nt2)); (* If the remainder of the right-hand side is nullable, (* If the remainder of the right-hand side is nullable, FOLLOW(nt1) contributes to FOLLOW(nt2). *) FOLLOW(nt1) contributes to FOLLOW(nt2). *) if nullable then if nullable then follow.(nt2) <- MemberVar nt1 :: follow.(nt2) follow.(nt2) <- EUnion (EVar nt1, follow.(nt2)) ) rhs ) rhs ) Production.table; ) Production.table; ... ...
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!