]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/lablgtk/lablgtk_20001129-0.1.0/varcc.ml
lablgtk_20001129* created
[helm.git] / helm / DEVEL / lablgtk / lablgtk_20001129-0.1.0 / varcc.ml
diff --git a/helm/DEVEL/lablgtk/lablgtk_20001129-0.1.0/varcc.ml b/helm/DEVEL/lablgtk/lablgtk_20001129-0.1.0/varcc.ml
new file mode 100644 (file)
index 0000000..100bee3
--- /dev/null
@@ -0,0 +1,157 @@
+(* $Id$ *)
+
+(* Compile a list of variant tags into CPP defines *) 
+
+(* hash_variant, from ctype.ml *)
+
+let hash_variant s =
+  let accu = ref 0 in
+  for i = 0 to String.length s - 1 do
+    accu := 223 * !accu + Char.code s.[i]
+  done;
+  (* reduce to 31 bits *)
+  accu := !accu land (1 lsl 31 - 1);
+  (* make it signed for 64 bits architectures *)
+  if !accu > 0x3FFFFFFF then !accu - (1 lsl 31) else !accu
+
+open Genlex
+
+let lexer = make_lexer ["type"; "public"; "="; "["; "]"; "`"; "|"]
+
+let may_string = parser
+    [< ' String s >] -> s
+  | [< >] -> ""
+
+let may_bar = parser
+    [< ' Kwd "|" >] -> ()
+  | [< >] -> ()
+
+let rec ident_list = parser
+    [< ' Kwd "`"; ' Ident x; trans = may_string; _ = may_bar; s >] ->
+      (x, trans) :: ident_list s
+  | [< >] -> []
+
+let static = ref false
+let may_public = parser
+    [< ' Kwd "public" >] -> true
+  | [< ' Kwd "private" >] -> false
+  | [< >] -> not !static
+
+open Printf
+
+let hashes = Hashtbl.create 57
+
+let declaration ~hc ~cc = parser
+    [< ' Kwd "type"; public = may_public; ' Ident name; ' Kwd "=";
+       prefix = may_string; ' Kwd "["; _ = may_bar;
+       tags = ident_list; ' Kwd "]"; suffix = may_string >] ->
+    let oh x = fprintf hc x and oc x = fprintf cc x in
+    (* Output tag values to headers *)
+    let first = ref true in
+    List.iter tags ~f:
+      begin fun (tag, _) ->
+        let hash = hash_variant tag in
+        try
+         let tag' = Hashtbl.find hashes hash in
+         if tag <> tag' then
+           failwith (String.concat ~sep:" " ["Doublon tag:";tag;"and";tag'])
+        with Not_found ->
+         Hashtbl.add ~key:hash ~data:tag hashes;
+          if !first then begin
+            oh "/* %s : tags and macros */\n" name; first := false
+          end;
+         oh "#define MLTAG_%s\tVal_int(%d)\n" tag hash;
+      end;
+    (* compute C name *)
+    let ctag tag trans =
+      if trans <> "" then trans else
+      let tag =
+       if tag.[0] = '_' then
+         String.sub tag ~pos:1 ~len:(String.length tag -1)
+       else tag
+      in
+      match
+       if prefix = "" then None, ""
+       else
+         Some (prefix.[String.length prefix - 1]), 
+         String.sub prefix ~pos:0 ~len:(String.length prefix - 1)
+      with
+       Some '#', prefix ->
+         prefix ^ String.uncapitalize tag ^ suffix
+      |        Some '^', prefix ->
+         prefix ^ String.uppercase tag ^ suffix
+      |        _ ->
+         prefix ^ tag ^ suffix
+    and cname =
+      String.capitalize name
+    in
+    let tags =
+      Sort.list tags
+       ~order:(fun (tag1,_) (tag2,_) -> hash_variant tag1 < hash_variant tag2)
+    in
+    (* Output table to code file *)
+    oc "/* %s : conversion table */\n" name;
+    let static = if not public then "static " else "" in
+    oc "%slookup_info ml_table_%s[] = {\n" static name;
+    oc "  { 0, %d },\n" (List.length tags);
+    List.iter tags ~f:
+      begin fun (tag,trans) ->
+       oc "  { MLTAG_%s, %s },\n" tag (ctag tag trans)
+      end;
+    oc "};\n\n";
+    (* Output macros to headers *)
+    if not !first then oh "\n";
+    if public then oh "extern lookup_info ml_table_%s[];\n" name;
+    oh "#define Val_%s(data) ml_lookup_from_c (ml_table_%s, data)\n"
+      name name;
+    oh "#define %s_val(key) ml_lookup_to_c (ml_table_%s, key)\n\n"
+      cname name;
+  | [< >] -> raise End_of_file
+
+
+let process ic ~hc ~cc =  
+  let chars = Stream.of_channel ic in
+  let s = lexer chars in
+  try
+    while true do declaration s ~hc ~cc done
+  with End_of_file -> ()
+  | Stream.Error err ->
+      failwith
+        (Printf.sprintf "Parsing error \"%s\" at character %d on input stream"
+           err (Stream.count chars))
+
+let main () =
+  let inputs = ref [] in
+  let header = ref "" in
+  let code = ref "" in
+  Arg.parse ~errmsg:"usage: varcc [options] file.var" ~keywords:
+    [ "-h", Arg.String ((:=) header), "file to output macros (file.h)";
+      "-c", Arg.String ((:=) code),
+      "file to output conversion tables (file.c)";
+      "-static", Arg.Set static, "do not export conversion tables" ]
+    ~others:(fun s -> inputs := s :: !inputs);
+  let inputs = List.rev !inputs in
+  begin match inputs with
+  | [] ->
+      if !header = "" then header := "a.h";
+      if !code = "" then code := "a.c"
+  | ip :: _ ->
+      let rad =
+        if Filename.check_suffix ip ".var" then Filename.chop_extension ip
+        else ip in
+      if !header = "" then header := rad ^ ".h";
+      if !code = "" then code := rad ^ ".c"
+  end;
+  let hc = open_out !header and cc = open_out !code in
+  let chars = Stream.of_channel stdin in
+  if inputs = [] then process stdin ~hc ~cc else begin
+    List.iter inputs ~f:
+      begin fun file ->
+        let ic = open_in file in
+        try process ic ~hc ~cc; close_in ic
+        with exn -> close_in ic; prerr_endline ("Error in " ^ file); raise exn
+      end
+  end;
+  close_out hc; close_out cc
+
+let _ = Printexc.print main ()