package lrgrep
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Analyse the stack of a Menhir-generated LR parser using regular expressions
Install
dune-project
Dependency
Authors
Maintainers
Sources
lrgrep-0.3.tbz
sha256=84a1874d0c063da371e19c84243aac7c40bfcb9aaf204251e0eb0d1f077f2cde
sha512=5a16ff42a196fd741bc64a1bdd45b4dca0098633e73aa665829a44625ec15382891c3643fa210dbe3704336eab095d4024e093e37ae5313810f6754de6119d55
doc/src/kernel/sentence_generation.ml.html
Source file sentence_generation.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176open Utils open Fix.Indexing open Info let find_transition (type g) (g : g grammar) x y = match Lr1.incoming g y with | None -> assert false | Some sym -> match Symbol.desc g sym with | N n -> Transition.of_goto g (Transition.find_goto g x n) | T _ -> IndexSet.choose (IndexSet.inter (Transition.successors g x) (Transition.predecessors g y)) let to_transitions g = function | [] -> invalid_arg "Sentence_generation.to_transitions: empty list" | initial :: rest -> let follow x y = (y, find_transition g x y) in let _, trs = List.fold_left_map follow initial rest in (initial, trs) let to_cells (type g cell) (g : g grammar) ((module R) : (g, cell) Reachability.t_cell) trs = let rec aux = function | [] -> [Terminal.all g, 0, []] | x :: xs -> let candidates = aux xs in let node = R.Tree.leaf x in let post_candidates = Array.to_seqi (R.Tree.post_classes node) |> Seq.filter_map (fun (post, classe) -> let cost, tail = List.fold_left begin fun (bcost, _ as best) (cclasse, ccost, tail) -> if ccost < bcost && IndexSet.quick_subset cclasse classe then (ccost, tail) else best end (max_int, []) candidates in if cost < max_int then Some (post, cost, tail) else None ) |> List.of_seq in let encode = R.Cell.encode node in let pre_candidates = Array.to_seqi (R.Tree.pre_classes node) |> Seq.filter_map (fun (pre, classe) -> let cost, tail = List.fold_left begin fun (bcost, _ as best) (post, cost, tail) -> let cell = encode ~pre ~post in let cost' = R.Analysis.cost cell in if cost' < max_int && cost' + cost < bcost then (cost' + cost, cell :: tail) else best end (max_int, []) post_candidates in if cost < max_int then Some (classe, cost, tail) else None ) |> List.of_seq in pre_candidates in snd ( List.fold_left (fun (bcost, _ as best) (_la, cost, tail') -> if cost < bcost then (cost, tail') else best) (max_int, []) (aux trs) ) let expand_cells (type g cell) (g : g grammar) ((module R) : (g, cell) Reachability.t_cell) cells = let open R in let exception Break of g terminal index list in let rec aux cell acc = let node, i_pre, i_post = Cell.decode cell in match Tree.split node with | L tr -> (* The node corresponds to a transition *) begin match Transition.split g tr with | R shift -> (* It is a shift transition, just shift the symbol *) Transition.shift_symbol g shift :: acc | L goto -> (* It is a goto transition *) let eqn = Tree.goto_equations goto in let c_pre = (Tree.pre_classes node).(i_pre) in let c_post = (Tree.post_classes node).(i_post) in if not (IndexSet.is_empty eqn.nullable_lookaheads) && IndexSet.quick_subset c_post eqn.nullable_lookaheads && not (IndexSet.disjoint c_pre c_post) then (* If a nullable reduction is possible, don't do anything *) acc else (* Otherwise look at all equations that define the cost of the goto transition and recursively visit one of minimal cost *) let current_cost = Analysis.cost cell in match List.find_map begin fun (red, node') -> if IndexSet.disjoint c_post red.lookahead then (* The post lookahead class does not permit reducing this production *) None else match Tree.pre_classes node' with | [|c_pre'|] when IndexSet.disjoint c_pre' c_pre -> (* The pre lookahead class does not allow to enter this branch. *) None | pre' -> (* Visit all lookahead classes, pre and post, and find the mapping between the parent node and this sub-node *) let pred_pre _ c_pre' = IndexSet.quick_subset c_pre' c_pre in let pred_post _ c_post' = IndexSet.quick_subset c_post c_post' in match Misc.array_findi pred_pre 0 pre', Misc.array_findi pred_post 0 (Tree.post_classes node') with | exception Not_found -> None | i_pre', i_post' -> let cell = Cell.encode node' ~pre:i_pre' ~post:i_post' in if Analysis.cost cell = current_cost then (* We found a candidate of minimal cost *) Some cell else None end eqn.non_nullable with | None -> Printf.eprintf "abort, cost = %d\n%!" current_cost; assert false | Some cell' -> (* Solve the sub-node *) aux cell' acc end | R (l, r) -> (* It is an inner node. We decompose the problem in a left-hand and a right-hand sub-problems, and find sub-solutions of minimal cost *) let current_cost = Analysis.cost cell in let coercion = Coercion.infix (Tree.post_classes l) (Tree.pre_classes r) in let l_index = Cell.encode l in let r_index = Cell.encode r in begin try Array.iteri (fun i_post_l all_pre_r -> let l_cost = Analysis.cost (l_index ~pre:i_pre ~post:i_post_l) in Array.iter (fun i_pre_r -> let r_cost = Analysis.cost (r_index ~pre:i_pre_r ~post:i_post) in if l_cost + r_cost = current_cost then ( let acc = aux (r_index ~pre:i_pre_r ~post:i_post) acc in let acc = aux (l_index ~pre:i_pre ~post:i_post_l) acc in raise (Break acc) ) ) all_pre_r ) coercion.Coercion.forward; assert false with Break acc -> acc end in List.fold_right aux cells [] let sentence_of_transitions (type g) (g : g grammar) ((module R) : g Reachability.t) trs = expand_cells g (module R) (to_cells g (module R) trs) let sentence_of_stack (type g) (g : g grammar) ((module R) : g Reachability.t) lr1s = let _initial, transitions = to_transitions g lr1s in let cells = to_cells g (module R) transitions in expand_cells g (module R) cells
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>