X-Git-Url: http://matita.cs.unibo.it/gitweb/?a=blobdiff_plain;f=helm%2FDEVEL%2Flablgtk%2Flablgtk_20001129-0.1.0%2Fvarcc.ml;fp=helm%2FDEVEL%2Flablgtk%2Flablgtk_20001129-0.1.0%2Fvarcc.ml;h=100bee331ee9c55de75919232bfffa016b818578;hb=993347ab3975ccc7c39dc0324255fab4a75bc0e2;hp=0000000000000000000000000000000000000000;hpb=1cd4dd7c3838fee49e5851c0ac7acf42f4fc3d67;p=helm.git 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 index 000000000..100bee331 --- /dev/null +++ b/helm/DEVEL/lablgtk/lablgtk_20001129-0.1.0/varcc.ml @@ -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 ()