ocaml/camlp4/lib/grammar.ml

975 lines
29 KiB
OCaml

(* camlp4r *)
(***********************************************************************)
(* *)
(* Camlp4 *)
(* *)
(* Daniel de Rauglaudre, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2001 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id$ *)
open Stdpp;
open Gramext;
open Format;
value rec flatten_tree =
fun
[ DeadEnd -> []
| LocAct _ _ -> [[]]
| Node {node = n; brother = b; son = s} ->
List.map (fun l -> [n :: l]) (flatten_tree s) @ flatten_tree b ]
;
value print_str s = print_string ("\"" ^ String.escaped s ^ "\"");
value rec print_symbol =
fun
[ Slist0 s -> do { print_string "LIST0"; print_string " "; print_symbol1 s }
| Slist0sep s t ->
do {
print_string "LIST0";
print_string " ";
print_symbol1 s;
print_string " SEP ";
print_symbol1 t
}
| Slist1 s -> do { print_string "LIST1"; print_string " "; print_symbol1 s }
| Slist1sep s t ->
do {
print_string "LIST1";
print_string " ";
print_symbol1 s;
print_string " SEP ";
print_symbol1 t
}
| Sopt s -> do { print_string "OPT "; print_symbol1 s }
| Stoken (con, prm) when con <> "" && prm <> "" ->
do { print_string con; print_space (); print_str prm }
| Snterml e l ->
do {
print_string e.ename;
print_space ();
print_string "LEVEL";
print_space ();
print_str l
}
| s -> print_symbol1 s ]
and print_symbol1 =
fun
[ Stoken ("", s) -> print_str s
| Snterm e -> print_string e.ename
| Sself -> print_string "SELF"
| Snext -> print_string "NEXT"
| Stoken (con, "") -> print_string con
| Stree t -> print_level print_space (flatten_tree t)
| s -> do { print_string "("; print_symbol s; print_string ")" } ]
and print_rule symbols =
do {
open_hovbox 0;
let _ =
List.fold_left
(fun sep symbol ->
do {
sep ();
print_symbol symbol;
fun () -> do { print_string ";"; print_space () }
})
(fun () -> ()) symbols
in
close_box ()
}
and print_level print_space rules =
do {
open_hovbox 0;
print_string "[ ";
let _ =
List.fold_left
(fun sep rule ->
do {
sep ();
print_rule rule;
fun () -> do { print_space (); print_string "| " }
})
(fun () -> ()) rules
in
print_string " ]";
close_box ()
}
;
value print_levels elev =
let _ =
List.fold_left
(fun sep lev ->
let rules =
List.map (fun t -> [Sself :: t]) (flatten_tree lev.lsuffix) @
flatten_tree lev.lprefix
in
do {
sep ();
open_hovbox 2;
match lev.lname with
[ Some n ->
do {
print_string ("\"" ^ String.escaped n ^ "\"");
print_break 1 2
}
| _ -> () ];
match lev.assoc with
[ LeftA -> print_string "LEFTA"
| RightA -> print_string "RIGHTA"
| NonA -> print_string "NONA" ];
close_box ();
print_break 1 2;
print_level force_newline rules;
fun () -> do { print_cut (); print_string "| " }
})
(fun () -> ()) elev
in
()
;
value print_entry e =
do {
open_vbox 0;
print_string "[ ";
match e.edesc with
[ Dlevels elev -> print_levels elev
| Dparser _ -> print_string "<parser>" ];
print_string " ]";
close_box ();
print_newline ()
}
;
type g = Gramext.grammar;
external grammar_obj : g -> grammar = "%identity";
value floc = ref (fun _ -> failwith "internal error when computing location");
value loc_of_token_interval bp ep =
if bp == ep then
if bp == 0 then (0, 1)
else
let a = snd (floc.val (bp - 1)) in
(a, a + 1)
else
let (bp1, bp2) = floc.val bp in
let (ep1, ep2) = floc.val (pred ep) in
(if bp1 < ep1 then bp1 else ep1, if bp2 > ep2 then bp2 else ep2)
;
value rec name_of_symbol entry =
fun
[ Snterm e -> "[" ^ e.ename ^ "]"
| Snterml e l -> "[" ^ e.ename ^ " level " ^ l ^ "]"
| Sself | Snext -> "[" ^ entry.ename ^ "]"
| Stoken tok -> entry.egram.glexer.Token.text tok
| _ -> "???" ]
;
value rec get_token_list entry tokl last_tok tree =
match tree with
[ Node {node = (Stoken tok as s); son = son; brother = DeadEnd} ->
match entry.egram.glexer.Token.tparse tok with
[ Some _ ->
if tokl = [] then None
else Some (List.rev [last_tok :: tokl], last_tok, tree)
| None -> get_token_list entry [last_tok :: tokl] tok son ]
| _ ->
if tokl = [] then None
else Some (List.rev [last_tok :: tokl], last_tok, tree) ]
;
value rec name_of_symbol_failed entry =
fun
[ Slist0 s -> name_of_symbol_failed entry s
| Slist0sep s _ -> name_of_symbol_failed entry s
| Slist1 s -> name_of_symbol_failed entry s
| Slist1sep s _ -> name_of_symbol_failed entry s
| Sopt s -> name_of_symbol_failed entry s
| Stree t -> name_of_tree_failed entry t
| s -> name_of_symbol entry s ]
and name_of_tree_failed entry =
fun
[ Node {node = s; brother = bro; son = son} ->
let tokl =
match s with
[ Stoken tok when entry.egram.glexer.Token.tparse tok = None ->
get_token_list entry [] tok son
| _ -> None ]
in
match tokl with
[ None ->
let txt = name_of_symbol_failed entry s in
let txt =
match (s, son) with
[ (Sopt _, Node _) -> txt ^ " or " ^ name_of_tree_failed entry son
| _ -> txt ]
in
let txt =
match bro with
[ DeadEnd | LocAct _ _ -> txt
| _ -> txt ^ " or " ^ name_of_tree_failed entry bro ]
in
txt
| Some (tokl, last_tok, son) ->
List.fold_left
(fun s tok ->
(if s = "" then "" else s ^ " ") ^
entry.egram.glexer.Token.text tok)
"" tokl ]
| DeadEnd | LocAct _ _ -> "???" ]
;
value search_tree_in_entry prev_symb tree =
fun
[ Dlevels levels ->
let rec search_levels =
fun
[ [] -> tree
| [level :: levels] ->
match search_level level with
[ Some tree -> tree
| None -> search_levels levels ] ]
and search_level level =
match search_tree level.lsuffix with
[ Some t -> Some (Node {node = Sself; son = t; brother = DeadEnd})
| None -> search_tree level.lprefix ]
and search_tree t =
if tree <> DeadEnd && t == tree then Some t
else
match t with
[ Node n ->
match search_symbol n.node with
[ Some symb ->
Some (Node {node = symb; son = n.son; brother = DeadEnd})
| None ->
match search_tree n.son with
[ Some t ->
Some (Node {node = n.node; son = t; brother = DeadEnd})
| None -> search_tree n.brother ] ]
| _ -> None ]
and search_symbol symb =
match symb with
[ Snterm _ | Snterml _ _ | Slist0 _ | Slist0sep _ _ | Slist1 _ |
Slist1sep _ _ | Sopt _ | Stoken _ | Stree _
when symb == prev_symb ->
Some symb
| Slist0 symb ->
match search_symbol symb with
[ Some symb -> Some (Slist0 symb)
| None -> None ]
| Slist0sep symb sep ->
match search_symbol symb with
[ Some symb -> Some (Slist0sep symb sep)
| None ->
match search_symbol sep with
[ Some sep -> Some (Slist0sep symb sep)
| None -> None ] ]
| Slist1 symb ->
match search_symbol symb with
[ Some symb -> Some (Slist1 symb)
| None -> None ]
| Slist1sep symb sep ->
match search_symbol symb with
[ Some symb -> Some (Slist1sep symb sep)
| None ->
match search_symbol sep with
[ Some sep -> Some (Slist1sep symb sep)
| None -> None ] ]
| Sopt symb ->
match search_symbol symb with
[ Some symb -> Some (Sopt symb)
| None -> None ]
| Stree t ->
match search_tree t with
[ Some t -> Some (Stree t)
| None -> None ]
| _ -> None ]
in
search_levels levels
| _ -> tree ]
;
value error_verbose = ref False;
value tree_failed entry prev_symb_result prev_symb tree =
let txt = name_of_tree_failed entry tree in
let txt =
match prev_symb with
[ Slist0 s ->
let txt1 = name_of_symbol_failed entry s in
txt1 ^ " or " ^ txt ^ " expected"
| Slist1 s ->
let txt1 = name_of_symbol_failed entry s in
txt1 ^ " or " ^ txt ^ " expected"
| Slist0sep s sep ->
match Obj.magic prev_symb_result with
[ [] ->
let txt1 = name_of_symbol_failed entry s in
txt1 ^ " or " ^ txt ^ " expected"
| _ ->
let txt1 = name_of_symbol_failed entry sep in
txt1 ^ " or " ^ txt ^ " expected" ]
| Slist1sep s sep ->
match Obj.magic prev_symb_result with
[ [] ->
let txt1 = name_of_symbol_failed entry s in
txt1 ^ " or " ^ txt ^ " expected"
| _ ->
let txt1 = name_of_symbol_failed entry sep in
txt1 ^ " or " ^ txt ^ " expected" ]
| Sopt _ | Stree _ -> txt ^ " expected"
| _ -> txt ^ " expected after " ^ name_of_symbol entry prev_symb ]
in
do {
if error_verbose.val then do {
let tree = search_tree_in_entry prev_symb tree entry.edesc in
set_formatter_out_channel stderr;
open_vbox 0;
print_newline ();
print_string "----------------------------------";
print_newline ();
printf "Parse error in entry [%s], rule:" entry.ename;
print_break 0 2;
open_vbox 0;
print_level force_newline (flatten_tree tree);
close_box ();
print_newline ();
print_string "----------------------------------";
print_newline ();
close_box ();
print_newline ()
}
else ();
txt ^ " (in [" ^ entry.ename ^ "])"
}
;
value symb_failed entry prev_symb_result prev_symb symb =
let tree = Node {node = symb; brother = DeadEnd; son = DeadEnd} in
tree_failed entry prev_symb_result prev_symb tree
;
external app : Obj.t -> 'a = "%identity";
value is_level_labelled n lev =
match lev.lname with
[ Some n1 -> n = n1
| None -> False ]
;
value level_number entry lab =
let rec lookup levn =
fun
[ [] -> failwith ("unknown level " ^ lab)
| [lev :: levs] ->
if is_level_labelled lab lev then levn else lookup (succ levn) levs ]
in
match entry.edesc with
[ Dlevels elev -> lookup 0 elev
| Dparser _ -> raise Not_found ]
;
value rec top_symb entry =
fun
[ Sself | Snext -> Snterm entry
| Snterml e _ -> Snterm e
| Slist1sep s sep -> Slist1sep (top_symb entry s) sep
| _ -> raise Stream.Failure ]
;
value entry_of_symb entry =
fun
[ Sself | Snext -> entry
| Snterm e -> e
| Snterml e _ -> e
| _ -> raise Stream.Failure ]
;
value top_tree entry =
fun
[ Node {node = s; brother = bro; son = son} ->
Node {node = top_symb entry s; brother = bro; son = son}
| _ -> raise Stream.Failure ]
;
value skip_if_empty bp p strm =
if Stream.count strm == bp then Gramext.action (fun a -> p strm)
else raise Stream.Failure
;
value continue entry bp a s son p1 =
parser
[: a = (entry_of_symb entry s).econtinue 0 bp a;
act = p1 ? tree_failed entry a s son :] ->
Gramext.action (fun _ -> app act a)
;
value do_recover parser_of_tree entry nlevn alevn bp a s son =
parser
[ [: a = parser_of_tree entry nlevn alevn (top_tree entry son) :] -> a
| [: a = skip_if_empty bp (parser []) :] -> a
| [: a =
continue entry bp a s son
(parser_of_tree entry nlevn alevn son) :] ->
a ]
;
value strict_parsing = ref False;
value recover parser_of_tree entry nlevn alevn bp a s son strm =
if strict_parsing.val then raise (Stream.Error (tree_failed entry a s son))
else do_recover parser_of_tree entry nlevn alevn bp a s son strm
;
value std_token_parse =
fun
[ (p_con, "") -> parser [: `(con, prm) when con = p_con :] -> prm
| (p_con, p_prm) ->
parser [: `(con, prm) when con = p_con && prm = p_prm :] -> prm ]
;
value peek_nth n strm =
let list = Stream.npeek n strm in
let rec loop list n =
match (list, n) with
[ ([x :: _], 1) -> Some x
| ([_ :: l], n) -> loop l (n - 1)
| ([], _) -> None ]
in
loop list n
;
value rec parser_of_tree entry nlevn alevn =
fun
[ DeadEnd -> parser []
| LocAct act _ -> parser [: :] -> act
| Node {node = Sself; son = LocAct act _; brother = DeadEnd} ->
parser [: a = entry.estart alevn :] -> app act a
| Node {node = Sself; son = LocAct act _; brother = bro} ->
let p2 = parser_of_tree entry nlevn alevn bro in
parser
[ [: a = entry.estart alevn :] -> app act a
| [: a = p2 :] -> a ]
| Node {node = s; son = son; brother = DeadEnd} ->
let tokl =
match s with
[ Stoken tok when entry.egram.glexer.Token.tparse tok = None ->
get_token_list entry [] tok son
| _ -> None ]
in
match tokl with
[ None ->
let ps = parser_of_symbol entry nlevn s in
let p1 = parser_of_tree entry nlevn alevn son in
let p1 = parser_cont p1 entry nlevn alevn s son in
parser bp [: a = ps; act = p1 bp a :] -> app act a
| Some (tokl, last_tok, son) ->
let p1 = parser_of_tree entry nlevn alevn son in
let p1 = parser_cont p1 entry nlevn alevn (Stoken last_tok) son in
parser_of_token_list p1 tokl ]
| Node {node = s; son = son; brother = bro} ->
let tokl =
match s with
[ Stoken tok when entry.egram.glexer.Token.tparse tok = None ->
get_token_list entry [] tok son
| _ -> None ]
in
match tokl with
[ None ->
let ps = parser_of_symbol entry nlevn s in
let p1 = parser_of_tree entry nlevn alevn son in
let p1 = parser_cont p1 entry nlevn alevn s son in
let p2 = parser_of_tree entry nlevn alevn bro in
parser bp
[ [: a = ps; act = p1 bp a :] -> app act a
| [: a = p2 :] -> a ]
| Some (tokl, last_tok, son) ->
let p1 = parser_of_tree entry nlevn alevn son in
let p1 = parser_cont p1 entry nlevn alevn (Stoken last_tok) son in
let p1 = parser_of_token_list p1 tokl in
let p2 = parser_of_tree entry nlevn alevn bro in
parser
[ [: a = p1 :] -> a
| [: a = p2 :] -> a ] ] ]
and parser_cont p1 entry nlevn alevn s son bp a =
parser
[ [: a = p1 :] -> a
| [: a = recover parser_of_tree entry nlevn alevn bp a s son :] -> a
| [: :] -> raise (Stream.Error (tree_failed entry a s son)) ]
and parser_of_token_list p1 tokl =
loop 1 tokl where rec loop n =
fun
[ [(p_con, "")] ->
let ps strm =
match peek_nth n strm with
[ Some (con, prm) when p_con = "ANY" || con = p_con ->
do { for i = 1 to n do { Stream.junk strm }; Obj.repr prm }
| _ -> raise Stream.Failure ]
in
parser bp [: a = ps; act = p1 bp a :] -> app act a
| [(p_con, p_prm)] ->
let ps strm =
match peek_nth n strm with
[ Some (con, prm)
when (p_con = "ANY" || con = p_con) && prm = p_prm ->
do { for i = 1 to n do { Stream.junk strm }; Obj.repr prm }
| _ -> raise Stream.Failure ]
in
parser bp [: a = ps; act = p1 bp a :] -> app act a
| [(p_con, "") :: tokl] ->
let ps strm =
match peek_nth n strm with
[ Some (con, prm) when p_con = "ANY" || con = p_con -> prm
| _ -> raise Stream.Failure ]
in
let p1 = loop (n + 1) tokl in
parser
[: a = ps; s :] ->
let act = p1 s in
app act a
| [(p_con, p_prm) :: tokl] ->
let ps strm =
match peek_nth n strm with
[ Some (con, prm)
when (p_con = "ANY" || con = p_con) && prm = p_prm ->
prm
| _ -> raise Stream.Failure ]
in
let p1 = loop (n + 1) tokl in
parser
[: a = ps; s :] ->
let act = p1 s in
app act a
| [] -> invalid_arg "parser_of_token_list" ]
and parser_of_symbol entry nlevn =
fun
[ Slist0 s ->
let ps = parser_of_symbol entry nlevn s in
let rec loop al =
parser
[ [: a = ps; s :] -> loop [a :: al] s
| [: :] -> al ]
in
parser [: a = loop [] :] -> Obj.repr (List.rev a)
| Slist0sep symb sep ->
let ps = parser_of_symbol entry nlevn symb in
let pt = parser_of_symbol entry nlevn sep in
let rec kont al =
parser
[ [: v = pt; a = ps ? symb_failed entry v sep symb; s :] ->
kont [a :: al] s
| [: :] -> al ]
in
parser
[ [: a = ps; s :] -> Obj.repr (List.rev (kont [a] s))
| [: :] -> Obj.repr [] ]
| Slist1 s ->
let ps = parser_of_symbol entry nlevn s in
let rec loop al =
parser
[ [: a = ps; s :] -> loop [a :: al] s
| [: :] -> al ]
in
parser [: a = ps; s :] -> Obj.repr (List.rev (loop [a] s))
| Slist1sep symb sep ->
let ps = parser_of_symbol entry nlevn symb in
let pt = parser_of_symbol entry nlevn sep in
let rec kont al =
parser
[ [: v = pt;
a =
parser
[ [: a = ps :] -> a
| [: a =
parser_of_symbol entry nlevn (top_symb entry symb) :] ->
a
| [: :] ->
raise (Stream.Error (symb_failed entry v sep symb)) ];
s :] ->
kont [a :: al] s
| [: :] -> al ]
in
parser [: a = ps; s :] -> Obj.repr (List.rev (kont [a] s))
| Sopt s ->
let ps = parser_of_symbol entry nlevn s in
parser
[ [: a = ps :] -> Obj.repr (Some a)
| [: :] -> Obj.repr None ]
| Stree t ->
let pt = parser_of_tree entry 1 0 t in
parser bp
[: a = pt :] ep ->
let loc = loc_of_token_interval bp ep in
app a loc
| Snterm e -> parser [: a = e.estart 0 :] -> a
| Snterml e l -> parser [: a = e.estart (level_number e l) :] -> a
| Sself -> parser [: a = entry.estart 0 :] -> a
| Snext -> parser [: a = entry.estart nlevn :] -> a
| Stoken ("ANY", v) ->
if v = "" then parser [: `(_, x) :] -> Obj.repr x
else parser [: `(_, x) when x = v :] -> Obj.repr x
| Stoken tok ->
match entry.egram.glexer.Token.tparse tok with
[ Some f -> (Obj.magic f : Stream.t Token.t -> Obj.t)
| None ->
(Obj.magic (std_token_parse tok) : Stream.t Token.t -> Obj.t) ] ]
;
value rec continue_parser_of_levels entry clevn =
fun
[ [] -> fun levn bp a -> parser []
| [lev :: levs] ->
let p1 = continue_parser_of_levels entry (succ clevn) levs in
match lev.lsuffix with
[ DeadEnd -> p1
| tree ->
let alevn =
match lev.assoc with
[ LeftA | NonA -> succ clevn
| RightA -> clevn ]
in
let p2 = parser_of_tree entry (succ clevn) alevn tree in
fun levn bp a strm ->
if levn > clevn then p1 levn bp a strm
else
match strm with parser
[ [: a = p1 levn bp a :] -> a
| [: act = p2 :] ep ->
let a = app act a (loc_of_token_interval bp ep) in
entry.econtinue levn bp a strm ] ] ]
;
value rec start_parser_of_levels entry clevn =
fun
[ [] -> fun levn -> parser []
| [lev :: levs] ->
let p1 = start_parser_of_levels entry (succ clevn) levs in
match lev.lprefix with
[ DeadEnd -> p1
| tree ->
let alevn =
match lev.assoc with
[ LeftA | NonA -> succ clevn
| RightA -> clevn ]
in
let p2 = parser_of_tree entry (succ clevn) alevn tree in
match levs with
[ [] ->
fun levn strm ->
match strm with parser bp
[ [: act = p2 :] ep ->
let a = app act (loc_of_token_interval bp ep) in
entry.econtinue levn bp a strm ]
| _ ->
fun levn strm ->
if levn > clevn then p1 levn strm
else
match strm with parser bp
[ [: act = p2 :] ep ->
let a = app act (loc_of_token_interval bp ep) in
entry.econtinue levn bp a strm
| [: a = p1 levn :] -> a ] ] ] ]
;
value continue_parser_of_entry entry =
match entry.edesc with
[ Dlevels elev ->
let p = continue_parser_of_levels entry 0 elev in
fun levn bp a ->
parser
[ [: a = p levn bp a :] -> a
| [: :] -> a ]
| Dparser p -> fun levn bp a -> parser [] ]
;
value empty_entry ename levn strm =
raise (Stream.Error ("entry [" ^ ename ^ "] is empty"))
;
value start_parser_of_entry entry =
match entry.edesc with
[ Dlevels [] -> empty_entry entry.ename
| Dlevels elev -> start_parser_of_levels entry 0 elev
| Dparser p -> fun levn strm -> p strm ]
;
value parse_parsable entry efun (cs, (ts, fun_loc)) =
let restore =
let old_floc = floc.val in
fun () -> floc.val := old_floc
in
do {
floc.val := fun_loc;
try
let r = efun ts in
do { restore (); r }
with
[ Stream.Failure ->
let loc =
try fun_loc (Stream.count ts) with _ ->
(Stream.count cs, Stream.count cs + 1)
in
do {
restore ();
raise_with_loc loc
(Stream.Error ("illegal begin of " ^ entry.ename))
}
| Stream.Error _ as exc ->
let loc =
try fun_loc (Stream.count ts) with _ ->
(Stream.count cs, Stream.count cs + 1)
in
do { restore (); raise_with_loc loc exc }
| exc ->
let loc = (Stream.count cs, Stream.count cs + 1) in
do { restore (); raise_with_loc loc exc } ]
}
;
value wrap_parse entry efun cs =
let parsable = (cs, entry.egram.glexer.Token.func cs) in
parse_parsable entry efun parsable
;
value create_toktab () = Hashtbl.create 301;
value create lexer = {gtokens = create_toktab (); glexer = lexer};
(* Extend syntax *)
value extend_entry entry position rules =
try
let elev = Gramext.levels_of_rules entry position rules in
do {
entry.edesc := Dlevels elev;
entry.estart :=
fun lev strm ->
let f = start_parser_of_entry entry in
do { entry.estart := f; f lev strm };
entry.econtinue :=
fun lev bp a strm ->
let f = continue_parser_of_entry entry in
do { entry.econtinue := f; f lev bp a strm }
}
with
[ Token.Error s ->
do {
Printf.eprintf "Lexer initialization error.\n%s\n" s;
flush stderr;
failwith "Grammar.extend"
} ]
;
value extend entry_rules_list =
let gram = ref None in
List.iter
(fun (entry, position, rules) ->
do {
match gram.val with
[ Some g ->
if g != entry.egram then do {
Printf.eprintf "Error: entries with different grammars\n";
flush stderr;
failwith "Grammar.extend"
}
else ()
| None -> gram.val := Some entry.egram ];
extend_entry entry position rules
})
entry_rules_list
;
(* Deleting a rule *)
value delete_rule entry sl =
match entry.edesc with
[ Dlevels levs ->
let levs = Gramext.delete_rule_in_level_list entry sl levs in
do {
entry.edesc := Dlevels levs;
entry.estart :=
fun lev strm ->
let f = start_parser_of_entry entry in
do { entry.estart := f; f lev strm };
entry.econtinue :=
fun lev bp a strm ->
let f = continue_parser_of_entry entry in
do { entry.econtinue := f; f lev bp a strm }
}
| _ -> () ]
;
(* Unsafe *)
value clear_entry e =
do {
e.estart := fun _ -> parser [];
e.econtinue := fun _ _ _ -> parser [];
match e.edesc with
[ Dlevels _ -> e.edesc := Dlevels []
| Dparser _ -> () ]
}
;
value reinit_gram g lexer = do { Hashtbl.clear g.gtokens; g.glexer := lexer };
module Unsafe =
struct value clear_entry = clear_entry; value reinit_gram = reinit_gram; end
;
exception EntryFound of g_entry;
value find_entry e s =
let rec find_levels levs =
try
do {
List.iter
(fun lev -> do { find_tree lev.lsuffix; find_tree lev.lprefix })
levs;
raise Not_found
}
with
[ EntryFound e -> e
| _ -> raise Not_found ]
and find_symbol =
fun
[ Snterm e -> if e.ename = s then raise (EntryFound e) else ()
| Snterml e _ -> if e.ename = s then raise (EntryFound e) else ()
| Slist0 s -> find_symbol s
| Slist0sep s _ -> find_symbol s
| Slist1 s -> find_symbol s
| Slist1sep s _ -> find_symbol s
| Sopt s -> find_symbol s
| Stree t -> find_tree t
| _ -> () ]
and find_tree =
fun
[ Node {node = s; brother = bro; son = son} ->
do { find_symbol s; find_tree bro; find_tree son }
| _ -> () ]
in
match e.edesc with
[ Dlevels levs -> find_levels levs
| Dparser _ -> raise Not_found ]
;
value of_entry e = e.egram;
module Entry =
struct
type e 'a = g_entry;
value create g n =
{egram = g; ename = n; estart = empty_entry n;
econtinue _ _ _ = parser []; edesc = Dlevels []}
;
value parse (entry : e 'a) cs : 'a =
Obj.magic (wrap_parse entry (entry.estart 0) cs)
;
value parse_token (entry : e 'a) ts : 'a = Obj.magic (entry.estart 0 ts);
value name e = e.ename;
value of_parser g n (p : Stream.t Token.t -> 'a) : e 'a =
{egram = g; ename = n; estart _ = Obj.magic p;
econtinue _ _ _ = parser []; edesc = Dparser (Obj.magic p)}
;
external obj : e 'a -> Gramext.g_entry = "%identity";
value print e = print_entry (obj e);
value find e = Obj.magic (find_entry (obj e));
end
;
value tokens g con =
let g = grammar_obj g in
let list = ref [] in
do {
Hashtbl.iter
(fun (p_con, p_prm) c ->
if p_con = con then list.val := [(p_prm, c.val) :: list.val] else ())
g.gtokens;
list.val
}
;
value warning_verbose = Gramext.warning_verbose;
(* Functorial interface *)
module type LexerType = sig value lexer : Token.lexer; end;
module type S =
sig
type parsable = 'x;
value parsable : Stream.t char -> parsable;
value tokens : string -> list (string * int);
module Entry :
sig
type e 'a = 'x;
value create : string -> e 'a;
value parse : e 'a -> parsable -> 'a;
value parse_token : e 'a -> Stream.t Token.t -> 'a;
value name : e 'a -> string;
value of_parser : string -> (Stream.t Token.t -> 'a) -> e 'a;
value print : e 'a -> unit;
external obj : e 'a -> Gramext.g_entry = "%identity";
end
;
module Unsafe :
sig
value reinit_gram : Token.lexer -> unit;
value clear_entry : Entry.e 'a -> unit;
end
;
value extend :
Entry.e 'a -> option Gramext.position ->
list
(option string * option Gramext.g_assoc *
list (list Gramext.g_symbol * Gramext.g_action)) ->
unit;
value delete_rule : Entry.e 'a -> list Gramext.g_symbol -> unit;
end
;
module Make (L : LexerType) : S =
struct
type parsable =
(Stream.t char * (Stream.t Token.t * Token.location_function))
;
value gram = create L.lexer;
value parsable cs = (cs, L.lexer.Token.func cs);
value tokens = tokens gram;
module Entry =
struct
type e 'a = g_entry;
value create n =
{egram = gram; ename = n; estart = empty_entry n;
econtinue _ _ _ = parser []; edesc = Dlevels []}
;
value parse (e : e 'a) p : 'a =
Obj.magic (parse_parsable e (e.estart 0) p)
;
value parse_token (e : e 'a) ts : 'a = Obj.magic (e.estart 0 ts);
value name e = e.ename;
value of_parser n (p : Stream.t Token.t -> 'a) : e 'a =
{egram = gram; ename = n; estart _ = Obj.magic p;
econtinue _ _ _ = parser []; edesc = Dparser (Obj.magic p)}
;
external obj : e 'a -> Gramext.g_entry = "%identity";
value print e = print_entry (obj e);
end
;
module Unsafe =
struct
value reinit_gram = Unsafe.reinit_gram gram;
value clear_entry = Unsafe.clear_entry;
end
;
value extend = extend_entry;
value delete_rule e r = delete_rule (Entry.obj e) r;
end
;