type t type node = [ `Grammar ] Node.t type symbol = [ `Terminal | `NonTerminal | `Parameter ] Node.t type p_symbol = [ `Parameter ] Node.t type n_symbol = [ `NonTerminal ] Node.t type t_symbol = [ `Terminal ] Node.t type partial = Node of n_symbol * partial array | Leaf of node external is_nil : t -> t_symbol -> bool = "caml_grammar_is_nil" external get_tag : t -> t_symbol -> string = "caml_grammar_get_tag" external get_symbol_at : t -> symbol -> node -> symbol = "caml_grammar_get_symbol_at" external first_child : t -> symbol -> node -> node = "caml_grammar_first_child" external next_sibling : t -> symbol -> node -> node = "caml_grammar_next_sibling" let is_non_terminal (n : symbol) = let n = Node.to_int n in n land 3 == 0 let is_terminal (n : symbol) = let n = Node.to_int n in n land 3 == 1 let is_parameter (n : symbol) = let n = Node.to_int n in n land 3 == 2 external parameter : symbol -> p_symbol = "%identity" external terminal : symbol -> t_symbol = "%identity" external non_terminal : symbol -> n_symbol = "%identity" let num_params (n : n_symbol) = let n = Node.to_int n in (n lsr 2) land 0xf external load : Unix.file_descr -> bool -> t = "caml_grammar_load" let traversal g = let start_symbol = (Node.of_int 0) in let rec start_loop idx = if idx >= Node.null then begin let symbol = get_symbol_at g start_symbol idx in if is_terminal symbol then let ts = terminal symbol in if is_nil g ts then () else let str = get_tag g ts in Printf.printf "<%s>%!" str; start_loop (first_child g start_symbol idx); start_loop (next_sibling g start_symbol idx); Printf.printf "%!" str; else let tn = non_terminal symbol in let nparam = num_params tn in let child = ref (first_child g start_symbol idx) in let a_param = Array.init nparam (fun _ -> let c = !child in child := next_sibling g start_symbol c; c) in rule_loop tn a_param end and rule_loop (nterm : [ `NonTerminal | `Terminal ] Node.t) a_param = let in start_loop (Node.of_int 0) ;; let load filename bp = let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0o600 in let g = try load fd bp with | e -> (Unix.close fd; raise e) in Unix.close fd; g