From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from majordomo@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id MAA27960; Fri, 25 Oct 2002 12:30:01 +0200 (MET DST) X-Authentication-Warning: pauillac.inria.fr: majordomo set sender to owner-caml-list@pauillac.inria.fr using -f Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id MAA28574 for ; Fri, 25 Oct 2002 12:30:00 +0200 (MET DST) Received: from verdot.inria.fr (verdot.inria.fr [128.93.11.7]) by concorde.inria.fr (8.11.1/8.11.1) with ESMTP id g9PATx520367 for ; Fri, 25 Oct 2002 12:29:59 +0200 (MET DST) Received: (from ddr@localhost) by verdot.inria.fr (8.9.3/8.9.3) id MAA11956 for caml-list@inria.fr; Fri, 25 Oct 2002 12:29:59 +0200 Date: Fri, 25 Oct 2002 12:29:59 +0200 From: Daniel de Rauglaudre To: caml-list@inria.fr Subject: Re: [Caml-list] Again on pattern matching and strings Message-ID: <20021025122959.C21492@verdot.inria.fr> References: <3DB73515.90705@baretta.com> <15799.14325.887770.501722@karryall.dnsalias.org> <3DB7A4B9.1030607@baretta.com> <20021024105136.C12351@verdot.inria.fr> <20021024095045.GB11324@cs.unibo.it> <20021024145904.K12351@verdot.inria.fr> <15799.62120.815873.654039@hector.lesours> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="dDRMvlgZJXvWKvBx" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <15799.62120.815873.654039@hector.lesours>; from basile@starynkevitch.net on Thu, Oct 24, 2002 at 03:16:24PM +0200 Sender: owner-caml-list@pauillac.inria.fr Precedence: bulk --dDRMvlgZJXvWKvBx Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, Here attached, a proposition of Camlp4 standard syntax extension for macros. The file is named "pa_macro.ml". To compile it do: ocamlc -pp camlp4r -I +camlp4 -c pa_macro.ml To use it for a file "foo.ml", do: To compile: ocamlc -pp "camlp4o ./pa_macro.cmo" foo.ml To just pretty print the resulting source: camlp4o ./pa_macro.cmo pr_o.cmo foo.ml The added statements are indicated in the beginning of the file pa_macro.ml. Keywords uppercase or lowercase? I choosed to write the keywords in uppercase because I consider that they must be visible in the source, just like the "#define" and other "#ifdef" of C are visible, because of the "#" and because of the fact that they are in the first column. And I have considered also that in an expression, it is important to differentiate "ifs" as conditional compilation and normal "ifs". On Thu, Oct 24, 2002 at 03:16:24PM +0200, Basile STARYNKEVITCH wrote: > #ifdef WANT_DEBUG > #define DEBUGME(V) if (debugflag) printf("%d", V) > #else > #define DEBUGME(V) {} > #endif With pa_macro.cmo, you can write it like this: IFDEF WANT_DEBUG THEN DEFINE DEBUGME(v) = if (debugflag) then printf("%d", v) ELSE DEFINE DEBUGME(v) = () END To define "WANT_DEBUG" you can either insert in the source: DEFINE DEBUGME Or add "-DWANT_DEBUG" as option: camlp4o ./pa_macros.cmo pr_o.cmo -DWANT_DEBUG foo.ml ocamlc -pp "camlp4o ./pa_macros.cmo -DWANT_DEBUG" foo.ml > 5. having the equivalent of __FILE__ and __LINE__ is very useful Ok file __FILE__. For __LINE__, it is complicated. I added __LOCATION__. Any comments? -- Daniel de RAUGLAUDRE http://cristal.inria.fr/~ddr/ --dDRMvlgZJXvWKvBx Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pa_macro.ml" (* camlp4r *) (* $Id$ *) (* Added statements: At toplevel (structure item): DEFINE DEFINE = DEFINE () = IFDEF THEN END IFDEF THEN ELSE END IFNDEF THEN END IFNDEF THEN ELSE END In expressions: IFDEF THEN ELSE END IFNDEF THEN ELSE END __FILE__ __LOCATION__ As Camlp4 options: -D -U After having used a DEFINE followed by "= ", you can use it in expressions *and* in patterns. If the expression defining the macro cannot be used as a pattern, there is an error message if it is used in a pattern. The expression __FILE__ returns the current compiled file name. The expression __LOCATION__ returns the current location of itself. *) #load "pa_extend.cmo"; #load "q_MLast.cmo"; open Pcaml; type item_or_def 'a = [ SdStr of 'a | SdDef of string and option (list string * MLast.expr) | SdUnd of string | SdNop ] ; value rec list_remove x = fun [ [(y, _) :: l] when y = x -> l | [d :: l] -> [d :: list_remove x l] | [] -> [] ] ; value defined = ref [("OCAML_305", None); ("CAMLP4_300", None); ("NEWSEQ", None)] ; value is_defined i = List.mem_assoc i defined.val; value loc = (0, 0); value subst mloc env = loop where rec loop = fun [ <:expr< if $e1$ then $e2$ else $e3$ >> -> <:expr< if $loop e1$ then $loop e2$ else $loop e3$ >> | <:expr< $e1$ $e2$ >> -> <:expr< $loop e1$ $loop e2$ >> | <:expr< $lid:x$ >> | <:expr< $uid:x$ >> as e -> try <:expr< $anti:List.assoc x env$ >> with [ Not_found -> e ] | <:expr< ($list:x$) >> -> <:expr< ($list:List.map loop x$) >> | <:expr< { $list:pel$ } >> -> let pel = List.map (fun (p, e) -> (p, loop e)) pel in <:expr< { $list:pel$ } >> | e -> e ] ; value substp mloc env = loop where rec loop = fun [ <:expr< $e1$ $e2$ >> -> <:patt< $loop e1$ $loop e2$ >> | <:expr< $lid:x$ >> -> try <:patt< $anti:List.assoc x env$ >> with [ Not_found -> <:patt< $lid:x$ >> ] | <:expr< $uid:x$ >> -> try <:patt< $anti:List.assoc x env$ >> with [ Not_found -> <:patt< $uid:x$ >> ] | <:expr< $int:x$ >> -> <:patt< $int:x$ >> | <:expr< ($list:x$) >> -> <:patt< ($list:List.map loop x$) >> | <:expr< { $list:pel$ } >> -> let ppl = List.map (fun (p, e) -> (p, loop e)) pel in <:patt< { $list:ppl$ } >> | x -> Stdpp.raise_with_loc mloc (Failure "this macro cannot be used in a pattern (see its definition)") ] ; value incorrect_number loc l1 l2 = Stdpp.raise_with_loc loc (Failure (Printf.sprintf "expected %d parameters; found %d" (List.length l2) (List.length l1))) ; value define eo x = do { match eo with [ Some ([], e) -> EXTEND expr: LEVEL "simple" [ [ UIDENT $x$ -> Pcaml.expr_reloc (fun _ -> loc) 0 e ] ] ; patt: LEVEL "simple" [ [ UIDENT $x$ -> let p = substp loc [] e in Pcaml.patt_reloc (fun _ -> loc) 0 p ] ] ; END | Some (sl, e) -> EXTEND expr: LEVEL "apply" [ [ UIDENT $x$; param = SELF -> let el = match param with [ <:expr< ($list:el$) >> -> el | e -> [e] ] in if List.length el = List.length sl then let env = List.combine sl el in let e = subst loc env e in Pcaml.expr_reloc (fun _ -> loc) 0 e else incorrect_number loc el sl ] ] ; patt: LEVEL "simple" [ [ UIDENT $x$; param = SELF -> let pl = match param with [ <:patt< ($list:pl$) >> -> pl | p -> [p] ] in if List.length pl = List.length sl then let env = List.combine sl pl in let p = substp loc env e in Pcaml.patt_reloc (fun _ -> loc) 0 p else incorrect_number loc pl sl ] ] ; END | None -> () ]; defined.val := [(x, eo) :: defined.val]; } ; value undef x = try do { let eo = List.assoc x defined.val in match eo with [ Some ([], _) -> do { DELETE_RULE expr: UIDENT $x$ END; DELETE_RULE patt: UIDENT $x$ END; } | Some (_, _) -> do { DELETE_RULE expr: UIDENT $x$; SELF END; DELETE_RULE patt: UIDENT $x$; SELF END; } | None -> () ]; defined.val := list_remove x defined.val; } with [ Not_found -> () ] ; EXTEND GLOBAL: expr str_item sig_item; str_item: FIRST [ [ x = macro_def -> match x with [ SdStr [si] -> si | SdStr sil -> <:str_item< declare $list:sil$ end >> | SdDef x eo -> do { define eo x; <:str_item< declare end >> } | SdUnd x -> do { undef x; <:str_item< declare end >> } | SdNop -> <:str_item< declare end >> ] ] ] ; macro_def: [ [ "DEFINE"; i = ident; def = opt_macro_value -> SdDef i def | "UNDEF"; i = ident -> SdUnd i | "IFDEF"; i = ident; "THEN"; d = str_item_or_macro; "END" -> if is_defined i then d else SdNop | "IFDEF"; i = ident; "THEN"; d1 = str_item_or_macro; "ELSE"; d2 = str_item_or_macro; "END" -> if is_defined i then d1 else d2 | "IFNDEF"; i = ident; "THEN"; d = str_item_or_macro; "END" -> if is_defined i then SdNop else d | "IFNDEF"; i = ident; "THEN"; d1 = str_item_or_macro; "ELSE"; d2 = str_item_or_macro; "END" -> if is_defined i then d2 else d1 ] ] ; str_item_or_macro: [ [ d = macro_def -> d | si = LIST1 str_item -> SdStr si ] ] ; opt_macro_value: [ [ "("; pl = LIST1 LIDENT SEP ","; ")"; "="; e = expr -> Some (pl, e) | "="; e = expr -> Some ([], e) | -> None ] ] ; expr: LEVEL "top" [ [ "IFDEF"; i = ident; "THEN"; e1 = expr; "ELSE"; e2 = expr; "END" -> if is_defined i then e1 else e2 | "IFNDEF"; i = ident; "THEN"; e1 = expr; "ELSE"; e2 = expr; "END" -> if is_defined i then e2 else e1 ] ] ; expr: LEVEL "simple" [ [ LIDENT "__FILE__" -> <:expr< $str:Pcaml.input_file.val$ >> | LIDENT "__LOCATION__" -> let bp = string_of_int (fst loc) in let ep = string_of_int (snd loc) in <:expr< ($int:bp$, $int:ep$) >> ] ] ; ident: [ [ i = UIDENT -> i ] ] ; END; Pcaml.add_option "-D" (Arg.String (define None)) " Define for IFDEF instruction." ; Pcaml.add_option "-U" (Arg.String undef) " Undefine for IFDEF instruction." ; --dDRMvlgZJXvWKvBx-- ------------------- To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners