1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- $Id: syntext.html,v 6.3 2012-01-09 14:22:20 deraugla Exp $ -->
<!-- Copyright (c) INRIA 2007-2012 -->
<title>Extensions of syntax</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<link rel="stylesheet" type="text/css" href="styles/base.css"
title="Normal" />
</head>
<body>
<div id="menu">
</div>
<div id="content">
<h1 class="top">Extensions of syntax</h1>
<p>Camlp5 allows one to extend the syntax of the OCaml language, and
even change the entire syntax.</p>
<p>It uses for that one of its parsing tools:
the <a href="grammars.html">extensible grammars</a>.</p>
<p>To understand the whole syntax in the examples given in this
chapter, it is good to understand this parsing tool (the extensible
grammars), but we shall try to give some minimal explanations to
allow the reader to follow them.</p>
<p>A syntax extension is an OCaml object file (ending with ".cmo" or
".cma") which is loaded inside Camlp5. The source of this file uses
calls to the specific statement EXTEND applied to entries defined in
the Camlp5 module "<tt>Pcaml</tt>".</p>
<div id="tableofcontents">
</div>
<h2>Entries</h2>
<p>The grammar of OCaml contains several entries, corresponding to the
major notions of the language, which are modifiable this way, and
even erasable. They are defined in this module "<tt>Pcaml</tt>".</p>
<p>Most important entries:</p>
<ul>
<li><tt>expr</tt>: the expressions.</li>
<li><tt>patt</tt>: the patterns.</li>
<li><tt>ctyp</tt>: the types.</li>
<li><tt>str_item</tt>: the structure items, i.e. the items between
"struct" and "end", and the toplevel phrases in a ".ml" file.</li>
<li><tt>sig_item</tt>: the signature items, i.e. the items between
"sig" and "end", and the toplevel phrases in a ".mli" file.</li>
<li><tt>module_expr</tt>: the module expressions.</li>
<li><tt>module_type</tt>: the module types.</li>
</ul>
<p>Entries of object programming:</p>
<ul>
<li><tt>class_expr</tt>: the class expressions.</li>
<li><tt>class_type</tt>: the class types.</li>
<li><tt>class_str_item</tt>: the objects items.</li>
<li><tt>class_sig_item</tt>: the objects types items.</li>
</ul>
<p>Main entries of files and interactive toplevel parsing:</p>
<ul>
<li><tt>implem</tt>: the phrases that can be found in a ".ml" file.</li>
<li><tt>interf</tt>: the phrases that can be found in a ".mli" file.</li>
<li><tt>top_phrase</tt>: the phrases of the interactive toplevel.</li>
<li><tt>use_file</tt>: the phrases that can be found in a file
included by the directive "use".</li>
</ul>
<p>Extra useful entries also accessible:</p>
<ul>
<li><tt>let_binding</tt>: the bindings "expression = pattern" found in
the "let" statement.</li>
<li><tt>type_declaration</tt>: the bindings "name = type" found in
the "type" statement.</li>
</ul>
<h2>Syntax tree quotations</h2>
<p>A grammar rule is a list of rule symbols followed by the semantic
action, i.e. the result of the rule. This result is a syntax tree,
whose type is the type of the extended entry. The description of the
types of the syntax tree are in the Camlp5 module
"<tt>MLast</tt>".</p>
<p>There is however a simpler way to make values of these syntax tree
types: the system quotations (see chapters
about <a href="quot.html">quotations</a>
and <a href="ml_ast.html">syntax tree</a>). With this system, it is
possible to represent syntax tree in concrete syntax, between
specific parentheses, namely "<tt><<</tt>" and
"<tt>>></tt>", or between "<tt><:name<</tt>" and
"<tt>>></tt>".</p>
<p>For example, the syntax node of the "if" statement is, normally:</p>
<pre>
MLast.ExIfe loc e1 e2 e3
</pre>
<p>where loc is the source location, and e1, e2, e3 are the
expressions constituting the if statement. With quotations, it is
possible to write it like this (which is stricly equivalent because
this is evaluated at parse time, not execution time):</p>
<pre>
<:expr< if $e1$ then $e2$ else $e3$ >>
</pre>
<p>With quotations, it is possible to build pieces of program as
complex as desired. See the chapter
about <a href="ml_ast.html">syntax trees</a>.</p>
<h2>An example : repeat..until</h2>
<p>A classical extension is the creation of the "repeat" statement.
The "repeat" statement is like a "while" except that the loop is
executed at least one time and that the test is at the end of the
loop and is inverted. The equivalent of:</p>
<pre>
repeat x; y; z until c
</pre>
<p>is:</p>
<pre>
do {
x; y; z;
while not c do { x; y; z }
}
</pre>
<p>or, with a loop:</p>
<pre>
loop () where rec loop () = do {
x; y; z;
if c then () else loop ()
}
</pre>
<h3>The code</h3>
<p>This syntax extension could be written like this (see the detail of
syntax in the chapter about <a href="grammars.html">extensible
grammars</a> and the syntax tree quotations in the chapter
about <a href="ml_ast.html">them</a>):</p>
<pre>
#load "pa_extend.cmo";
#load "q_MLast.cmo";
open Pcaml;
EXTEND
expr:
[ [ "repeat"; el = LIST1 expr SEP ";"; "until"; c = expr ->
let el = el @ [<:expr< while not $c$ do { $list:el$ } >>] in
<:expr< do { $list:el$ } >> ] ]
;
END;
</pre>
<p>Alternatively, with the loop version:</p>
<pre>
#load "pa_extend.cmo";
#load "q_MLast.cmo";
open Pcaml;
EXTEND
expr:
[ [ "repeat"; el = LIST1 expr SEP ";"; "until"; c = expr ->
let el = el @ [<:expr< if $c$ then () else loop () >>] in
<:expr< loop () where rec loop () = do { $list:el$ } >> ] ]
;
END;
</pre>
<p>The first "<tt>#load</tt>" in the code (in both files) means that a
syntax extension has been used in the file, namely the "EXTEND"
statement. The second "<tt>#load</tt>" means that abstract
tree <a href="quot.html">quotations</a> has been used, namely the
"<tt><:expr< ... >></tt>".</p>
<p>The quotation, found in the second version:</p>
<pre>
<:expr< loop () where rec loop () = do { $list:el$ } >>
</pre>
<p>is especially interesting. Written with abstract syntax tree, it would
be:</p>
<pre>
MLast.ExLet loc True
[(MLast.PaLid loc "loop",
MLast.ExFun loc [(MLast.PaUid loc "()", None, MLast.ExSeq loc el)])]
(MLast.ExApp loc (MLast.ExLid loc "loop") (MLast.ExUid loc "()"));
</pre>
<p>This shows the interest of writing abstract syntax tree with quotations:
it is easier to program and to understand.</p>
<h3>Compilation</h3>
<p>If the file "foo.ml" contains one of these versions, it is possible to
compile it like this:</p>
<pre>
ocamlc -pp camlp5r -I +camlp5 -c foo.ml
</pre>
<p>Notice that the ocamlc option "-c" means that we are interested
only in generating the object file "foo.cmo", not achieving the
compilation by creating an executable. Anyway the link would not
work because of usage of modules specific to Camlp5.</p>
<h3>Testing</h3>
<h4>In the OCaml toplevel</h4>
<pre>
ocaml -I +camlp5 camlp5r.cma
Objective Caml version ...
Camlp5 Parsing version ...
# #load "foo.cmo";
# value x = ref 42;
value x : ref int = {val=42}
# repeat
print_int x.val; print_endline ""; x.val := x.val + 3
until x.val > 70;
42
45
48
51
54
57
60
63
66
69
- : unit = ()
</pre>
<h4>In a file</h4>
<p>The code, above, used in the toplevel, can be written in a file,
say "bar.ml":</p>
<pre>
#load "./foo.cmo";
value x = ref 42;
repeat
print_int x.val;
print_endline "";
x.val := x.val + 3
until x.val > 70;
</pre>
<p>with a subtile difference: the loaded file must be "<tt>./foo.cmo</tt>"
and not just "<tt>foo.cmo</tt>" because Camlp5 does not have, by default,
the current directory in its path.</p>
<p>The file can be compiled like this:</p>
<pre>
ocamlc -pp camlp5r bar.ml
</pre>
<p>or in native code:</p>
<pre>
ocamlopt -pp camlp5r bar.ml
</pre>
<p>And it is possible to check the resulting program by typing:</p>
<pre>
camlp5r pr_r.cmo bar.ml
</pre>
<p>whose displayed result is:</p>
<pre>
#load "./foo.cmo";
value x = ref 42;
do {
print_int x.val;
print_endline "";
x.val := x.val + 3;
while not (x.val > 70) do {
print_int x.val;
print_endline "";
x.val := x.val + 3
}
};
</pre>
<p>See also the <a href="opretty.html#a:Example-:-repeat--until">same
example</a> pretty printed in its original syntax, using the
extendable <a href="opretty.html">programs printing</a>.</p>
<div class="trailer">
</div>
</div>
</body>
</html>
|