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/lrgrep.runtime/lrgrep_runtime.ml.html
Source file lrgrep_runtime.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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287type lr1 = int type clause = int type register = int (* Representation of automaton as sparse tables and bytecoded programs *) let get_uint24_be str i = (String.get_uint16_be str i) lor (String.get_uint8 str (i + 2) lsl 16) module Sparse_table = struct type row = int type col = int type value = int let get1 str i = if i < 0 || i + 1 > String.length str then min_int else String.get_uint8 str i let get2 str i = let i = i * 2 in if i < 0 || i + 2 > String.length str then min_int else String.get_uint16_be str i let get3 str i = let i = i * 3 in if i < 0 || i + 3 > String.length str then min_int else get_uint24_be str i let get4 str i = let i = i * 4 in if i < 0 || i + 4 > String.length str then min_int else Int32.to_int (String.get_int32_be str i) type t = { displacement: int -> int; offset: int; keys: int -> int; values: int -> int; } let lookup coded (row : row) (col : col) : value option = assert (row >= 0 && col >= 0); let displacement = coded.displacement col in if displacement = min_int then None else let offset = displacement - coded.offset + row in if coded.keys offset = row + 1 then Some (coded.values offset) else None end type program_code = string type program_counter = int type priority = int type program_instruction = | Store of register | Move of register * register | Swap of register * register | Clear of register | Yield of program_counter | Accept of clause * priority * register option array | Match of Sparse_table.row | Priority of clause * priority * priority | Halt type 'a register_value = | Empty | Location of Lexing.position * Lexing.position | Value of 'a type 'a register_values = 'a register_value array let get_int table ~offset = function | 1 -> String.get_uint8 table offset | 2 -> String.get_uint16_be table offset | 3 -> (String.get_uint16_be table offset) lor (String.get_uint8 table (offset + 2) lsl 16) | 4 -> Int32.to_int (String.get_int32_be table offset) | _ -> assert false let program_step (t : program_code) (r : program_counter ref) : program_instruction = let pc = !r in match t.[pc] with | '\x01' -> r := !r + 2; Store (String.get_uint8 t (pc + 1)) | '\x02' -> r := !r + 3; Move (String.get_uint8 t (pc + 1), String.get_uint8 t (pc + 2)) | '\x09' -> r := !r + 3; Swap (String.get_uint8 t (pc + 1), String.get_uint8 t (pc + 2)) | '\x03' -> r := !r + 2; Clear (String.get_uint8 t (pc + 1)) | '\x04' -> r := !r + 4; Yield (get_int t ~offset:(pc + 1) 3) | '\x05' -> let clause = String.get_uint16_be t (pc + 1) in let priority = String.get_uint8 t (pc + 3) in let arity = String.get_uint8 t (pc + 4) in let registers = Array.init arity (fun i -> let x = String.get_uint8 t (pc + 5 + i) in if x = 255 then None else Some x ) in r := !r + 5 + arity; Accept (clause, priority, registers) | '\x06' -> r := !r + 4; Match (get_uint24_be t (pc + 1)) | '\x07' -> r := !r + 1; Halt | '\x08' -> r := !r + 5; Priority (String.get_uint16_be t (pc + 1), String.get_uint8 t (pc + 3), String.get_uint8 t (pc + 4)) | x -> Printf.ksprintf failwith "Invalid opcode: %02X at 0x%04X" (Char.code x) pc type program = { registers : int; initial : program_counter; table : Sparse_table.t; code : program_code; } module type Parser = sig type 'a env type element val current_state_number : 'a env -> int val top : 'a env -> element option val pop : 'a env -> 'a env option val positions: 'a env -> Lexing.position * Lexing.position end let debug = false let eprintf = Printf.eprintf let print_regs bank regs = Printf.sprintf "[%s]" (String.concat ", " (List.map (function | None -> "None" | Some i -> "%" ^ string_of_int i ^ " = " ^ match bank.(i) with | Empty -> "Empty" | Location _ -> "Location _" | Value _ -> "Value _" ) (Array.to_list regs))) let add_candidate candidates ~clause ~priority registers bank = let may_get = function | None -> Empty | Some i -> bank.(i) in let mk () = let arguments = Array.map may_get registers in (clause, priority, arguments) in let rec loop = function | [] -> [mk ()] | ((clause', priority', _) :: xs) as xxs when clause = clause' -> if priority <= priority' then mk () :: xs else xxs | ((clause', _, _) :: _) as xxs when clause' > clause -> mk () :: xxs | x :: xs -> x :: loop xs in candidates := loop !candidates let remap_candidate candidates ~(clause : clause) p1 p2 = let rec loop = function | (clause', p1', args) :: rest when clause' = clause && p1 = p1' -> (clause', p2, args) :: rest | ((clause', _, _) as x) :: xs when clause' < clause -> x :: loop xs | _ -> raise Not_found in match loop !candidates with | exception Not_found -> if debug then eprintf "Remap skipped\n"; () | candidates' -> if debug then eprintf "Remap applied\n"; candidates := candidates' let rec interpret_last program bank candidates pc = match program_step program.code pc with | Accept (clause, priority, registers) -> if debug then eprintf "Accept (%d,%s) (bottom)\n" clause (print_regs bank registers); add_candidate candidates ~clause ~priority registers bank; interpret_last program bank candidates pc | _ -> () type 'a candidate = clause * 'a register_values module Interpreter (P : Parser) = struct let interpret program bank env candidates (pc : program_counter) = let pc = ref pc in let rec loop () = match program_step program.code pc with | Store reg -> if debug then eprintf "Store %d\n" reg; bank.(reg) <- (match P.top env with | Some x -> Value x | None -> let s, e = P.positions env in Location (s, e)); loop () | Move (r1, r2) -> if debug then eprintf "Move %d -> %d\n" r1 r2; bank.(r2) <- bank.(r1); loop () | Swap (r1, r2) -> if debug then eprintf "Swap %d <-> %d\n" r1 r2; let v2 = bank.(r2) in bank.(r2) <- bank.(r1); bank.(r1) <- v2; loop () | Clear r1 -> if debug then eprintf "Clear %d\n" r1; bank.(r1) <- Empty; loop () | Yield pc' -> if debug then prerr_endline "Yield"; Some pc' | Accept (clause, priority, registers) -> if debug then eprintf "Accept (%d,%d,%s)\n" clause priority (print_regs bank registers); add_candidate candidates ~clause ~priority registers bank; loop () | Match index -> let state = P.current_state_number env in let () = match Sparse_table.lookup program.table index state with | Some pc' -> if debug then eprintf "Match %d %d: success, jump to 0x%04X\n" index state pc'; pc := pc' | None -> if debug then eprintf "Match %d %d: failure\n" index state in loop () | Halt -> if debug then prerr_endline "Halt"; None | Priority (clause, p1, p2) -> if debug then eprintf "Priority: clause %d remapped %d -> %d\n" clause p1 p2; remap_candidate candidates ~clause p1 p2; loop () in loop () let lrgrep_run program env = let bank = Array.make program.registers Empty in let candidates = ref [] in let rec loop env pc = match interpret program bank env candidates pc with | None -> () | Some pc' -> match P.pop env with | None -> interpret_last program bank candidates (ref pc') | Some env -> loop env pc' in begin try loop env program.initial; with exn -> Printf.eprintf "LRgrep internal error: %s\n" (Printexc.to_string exn) end; List.map (fun (k,_,v) -> (k, v)) !candidates end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>