Message-Id: <199711271945.UAA26631@jaune.inria.fr>
Subject: Re: hacks using camlp4
In-Reply-To: <Pine.GSO.3.95.971126184733.28210A-100000@gerland> from David Monniaux at "Nov 26, 97 07:00:58 pm"
To: David.Monniaux@ens-lyon.fr (David Monniaux)
Date: Thu, 27 Nov 1997 20:45:55 +0100 (MET)
From: Daniel de Rauglaudre <daniel.de_rauglaudre@inria.fr>
> I lately checked the camlp4 preprocessor. I think this tool may have lots
> of useful applications, since it allows especially custom syntaxes for the
> input of certain kind of objects, in a more programmer-friendly fashion
> than just inputting raw data structures into the source code.
>
> ...
>
> I therefore have three problems:
>
> 1. Precompiled expressions.
> More generally, what would be needed would be some construction to
> evaluate an expression as soon as it is possible.
>
> 2. It would be nice if regexp precompilation could be done at compile or
> preprocessing time (I was thinking of marshalling the precompiled
> regexp, but I fear some C-library private data structure inside the
> regexp type).
A solution is partial evaluation. I have implemented a syntax solution
below (working with ocaml syntax, not righteous one). The idea is to
automatically generate global declarations.
The important file is "partial.ml" which gives a general mechanism of
partial evaluations, in Ocaml (not righteous) syntax. The function
"Partial.eval" generates a global variable and returns a (syntax)
access to it.
Then, an example: partially evaluate strings concatenation (^) when
both parameters are pure strings. The file "concat.ml" changes the
predefined string concatenation to generate a global variable in the
interesting case.
Once these files compiled (see their sources further), here is an
example:
$ cat foo.ml
let foo x =
function
0 -> x
| 1 -> x ^ "aa"
| 2 -> "aa" ^ x
| _ -> "aa" ^ "bb"
;;
No partial evaluation:
$ camlp4o pr_o.cmo foo.ml
let foo x =
function
0 -> x
| 1 -> x ^ "aa"
| 2 -> "aa" ^ x
| _ -> "aa" ^ "bb"
;;
Partial evaluation, automatically generated by partial.cmo + concat.cmo
$ camlp4o pr_o.cmo ./partial.cmo ./concat.cmo foo.ml
let v_1 = "aa" ^ "bb";;
let foo x =
function
0 -> x
| 1 -> x ^ "aa"
| 2 -> "aa" ^ x
| _ -> v_1
;;
Remark: the last case is not pretty printed like this by Camlp4
version 1.06+1; this is just a pretty printing bug fixed in the
version 1.06+2 (patches soon available in the ftp distribution).
Anyway, it works.
Now, the files "partial.ml" and "concat.ml":
========================= partial.ml
open Pcaml;;
Grammar.warning_verbose := false;;
let o2b = function Some _ -> True | None -> False;;
(* Global declarations generated *)
let globals = ref [];;
let add_globals loc si =
match !globals with
[] -> si
| g -> globals := []; <:str_item< declare $list:g @ [si]$ end >>
;;
(* Changes the declarations which holds expressions (cf etc/pa_o.ml) in
order to declare before the possible global declarations *)
EXTEND
str_item:
[ [ "let"; r = OPT "rec"; "_"; "="; e = expr ->
add_globals loc <:str_item< $exp:e$ >>
| "let"; r = OPT "rec"; l = LIST1 let_binding SEP "and"; "in";
x = expr ->
let e = <:expr< let $rec:o2b r$ $list:l$ in $x$ >> in
add_globals loc <:str_item< $exp:e$ >>
| "let"; r = OPT "rec"; l = LIST1 let_binding SEP "and" ->
add_globals loc <:str_item< value $rec:o2b r$ $list:l$ >>
| e = expr ->
add_globals loc <:str_item< $exp:e$ >> ] ]
;
END;;
(* Generates a global variable name. If conflict with program variables,
the user must change the "v_" into something else. *)
let genvar =
let cnt = ref 0 in
fun () -> incr cnt; "v_" ^ string_of_int !cnt
;;
(* [Partial.eval loc e] generates a global variable equal to [e] and returns
an access to it; [loc] is the location of [e] for possible semantic
errors *)
let eval loc e =
let v = genvar () in
globals := !globals @ [ <:str_item< value $lid:v$ = $e$ >> ];
<:expr< $lid:v$ >>
;;
========================= concat.ml
open Pcaml;;
(* Changes the syntax of "^" (cf etc/pa_o.ml) in order to generate
a global variable, using [Partial.eval] when both parameters are
pure strings *)
EXTEND
expr: LEVEL "^"
[ [ e1 = expr;
f = [ op = "^" -> op
| op = "@" -> op ];
e2 = expr ->
let e = <:expr< $lid:f$ $e1$ $e2$ >> in
match f, e1, e2 with
"^", <:expr< $str:_$ >>, <:expr< $str:_$ >> -> Partial.eval loc e
| _ -> e ] ]
;
END;;
=========================
Compilations:
ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I `camlp4 -where` -c partial.ml
ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I `camlp4 -where` -c concat.ml
--------------------------------------------------------------------------
Daniel de RAUGLAUDRE
Projet Cristal - INRIA Rocquencourt
Tel: +33 (01) 39 63 53 51
Email: daniel.de_rauglaudre@inria.fr
Web: http://pauillac.inria.fr/~ddr/
--------------------------------------------------------------------------
This archive was generated by hypermail 2b29 : Sun Jan 02 2000 - 11:58:13 MET