open Format type terminal = string type non_terminal = string type symbol = Terminal of terminal NonTerminal of non_terminal type production = symbol list type rule = non_terminal * production type grammar = { start : non_terminal; rules : rule list; } (* point fixe *) let rec fixpoint f x0 = let (x1,isnew) = f x0 in if isnew then fixpoint f x1 else x1 (* calcul des null *) module Ntset = Set.Make(String) type nulls = Ntset.t let is_null_production nulls p = let is_null_symbol = function Terminal _ -> false NonTerminal nt -> Ntset.mem nt nulls in List.for_all is_null_symbol p let null g = let step nulls = List.fold_left (fun ((n,_) as nb) (nt,p) -> if (not (Ntset.mem nt n)) && is_null_production n p then (Ntset.add nt n, true) else nb) (nulls,false) g.rules in fixpoint step Ntset.empty (* calcul des first *) module Ntmap = Map.Make(String) module Tset = Set.Make(String) type firsts = Tset.t Ntmap.t let empty_map g = List.fold_left (fun f (s,_) -> Ntmap.add s Tset.empty f) Ntmap.empty g.rules let first_production_step nulls firsts p = let rec fold_prod = function [] -> Tset.empty Terminal c :: _ -> Tset.add c Tset.empty NonTerminal nt :: p -> if Ntset.mem nt nulls then Tset.union (Ntmap.find nt firsts) (fold_prod p) else Ntmap.find nt firsts in fold_prod p let first g nulls = let step firsts = List.fold_left (fun (f,b) (nt,p) -> let fnt = Ntmap.find nt f in let fp = first_production_step nulls f p in if Tset.subset fp fnt then (f,b) else (Ntmap.add nt (Tset.union fnt fp) f, true)) (firsts,false) g.rules in fixpoint step (empty_map g) (* follow *) type follows = Tset.t Ntmap.t let follow g nulls firsts = let update (follows,b) nt s = let ntn = Ntmap.find nt follows in if Tset.subset s ntn then (follows,b) else (Ntmap.add nt (Tset.union s ntn) follows,true) in let rec update_prod ((follows,b) as acc) nty = function [] -> acc NonTerminal ntx :: beta -> let acc' = update acc ntx (first_production_step nulls firsts beta) in let acc'' = if is_null_production nulls beta then update acc' ntx (Ntmap.find nty follows) else acc' in update_prod acc'' nty beta Terminal _ :: beta -> update_prod acc nty beta in let step follows = List.fold_left (fun acc (nt,p) -> update_prod acc nt p) (follows,false) g.rules in fixpoint step (empty_map g) (* table d'analyse descendante *) module Tmap = Map.Make(String) module Pset = Set.Make(struct type t = production let compare = compare end) type expansion_table = Pset.t Tmap.t Ntmap.t let add_entry table nt t p = let line = try Ntmap.find nt table with Not_found -> Tmap.empty in let s = try Tmap.find t line with Not_found -> Pset.empty in Ntmap.add nt (Tmap.add t (Pset.add p s) line) table let expansions g = let nulls = null g in let firsts = first g nulls in let follows = follow g nulls firsts in List.fold_left (fun table (nt,p) -> let ts = first_production_step nulls firsts p in let ts' = if is_null_production nulls p then Tset.union ts (Ntmap.find nt follows) else ts in Tset.fold (fun t table -> add_entry table nt t p) ts' table) Ntmap.empty g.rules let g1 = { start = "S#"; rules = ["S#", [NonTerminal "S"; Terminal "#"]; "S", []; "S", [Terminal "a"; NonTerminal "A"; NonTerminal "S"]; "S", [Terminal "b"; NonTerminal "B"; NonTerminal "S"]; "A", [Terminal "a"; NonTerminal "A"; NonTerminal "A"]; "A", [Terminal "b"]; "B", [Terminal "b"; NonTerminal "B"; NonTerminal "B"]; "B", [Terminal "a"]; ] };; #use "pp.ml";; let is_ll1 t = try Ntmap.iter (fun _ m -> Tmap.iter (fun _ rs -> if Pset.cardinal rs > 1 then raise Exit) m) t; true with Exit -> false let analyze start table w = let rec scan = function [], [] -> true NonTerminal n :: s, (t :: _ as w) -> let p = Pset.choose (Tmap.find t (Ntmap.find n table)) in scan (p @ s, w) Terminal t' :: s, t :: w when t' = t -> scan (s, w) _ -> raise Not_found in try scan ([NonTerminal start], w @ ["#"]) with Not_found -> false let explode s = let n = String.length s in let rec make i = if i = n then [] else String.make 1 s.[i] :: make (i+1) in make 0 let test1 s = analyze g1.start (expansions g1) (explode s) (* positifs *) let _ = test1 "" let _ = test1 "ab" let _ = test1 "ba" let _ = test1 "abab" let _ = test1 "aaabbb" let _ = test1 "aaabababbbababab" (* négatifs *) let _ = test1 "a" let _ = test1 "b" let _ = test1 "aab" let _ = test1 "aaabbba" let _ = test1 "aaabbbaabab" let _ = test1 "aaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb"
This document was generated using caml2html