Using Camlp4

From Gallium

Jump to: navigation, search

This article describes how to use Camlp4 command-line tools to pre-process and pretty-print.


A review of different camlp4 commands

Camlp4 may be called using a bunch of executables:

  • camlp4
  • camlp4o
  • camlp4r
  • camlp4orf
  • ...

This section deals with the differences between those executables, first by detailing the features and languages understood by each of them, then by showing where those differences come from.

Camlp4 executables functionalities

Here is a table that sums up the different executables functionalities:

  • "host" language means the language outside quotations (here <<...>> here).
  • "embedded" language means the language inside quotations (... <<here>> ...).
  • "reflective" is true when extending the syntax of the host language will also extend the embedded one.
  • "3.09 equivalent" only concerns equivalence with quotations in 3.09 version.
camlp4 host embedded reflective 3.09 equivalent
camlp4of original original Yes N/A
camlp4rf revised revised Yes N/A
camlp4r -parser rq revised revised No camlp4r q_MLast.cmo
camlp4orf original revised No camlp4o q_MLast.cmo
camlp4oof original original No N/A

A few notes:

  • the ending "f" means full, that is all standard extensions (parsers, grammars, quotations, macros, and list comprehensions).
  • with the old camlp4 most of the libraries are written in a style understood by camlp4orf. However being able to write them in the original syntax was a very waited feature. Sadly camlp4of is still experimental since the original syntax doesn't fit well with quotations so there may be unsupported things with camlp4of.

How does it work?

Those executables are actually syntactic sugar for calling camlp4 with different modules, as can be seen using the -loaded-modules option:

$ camlp4 -loaded-modules

$ camlp4o -loaded-modules

$ camlp4rf -loaded-modules

As you can see, the camlp4 executable does not load any modules.

Camlp4 module system

Modules are searched for in the $OCAMLLIB/camlp4 folder, and loaded using the DynLink module. You may have seen that there are also native versions, which therefore cannot dynamically load code (the Natdynlink module is not (yet?) in the main CVS branch of OCaml). This is accomplished by embedding the modules in the executables in the correct order; more on that can be seen on How to create a standalone camlp4 executable.

Interestingly enough, using camlp4 in a standalone manner is not exactly the same as using it as a pre-processor. The difference is the printer module used:

  • in standalone mode, camlp4* executables default to Camlp4.Printers.OCaml, which pretty-prints code in OCaml regular syntax.
  • in pre-processor mode, camlp4* executables use Camlp4Printers.DumpOCamlAst, which outputs code in a format understood by the Objective Caml compiler (by marshaling an OCaml AST).

Equivalence table

The following table gives some equivalences between camlp4* executables and camlp4 commands.

executable equivalent command parsers loaded printers loaded
camlp4r camlp4 -parser r -parser rp -printer a Camlp4RevisedParserParser, Camlp4OCamlRevisedParser Camlp4Printers.Camlp4AutoPrinter
camlp4o camlp4 -parser o -parser op -printer a Camlp4OCamlParser, Camlp4OCamlParserParser, Camlp4OCamlRevisedParser, Camlp4OCamlRevisedParserParser Camlp4Printers.Camlp4AutoPrinter

A few notes

  • Camlp4 model sees OCaml original (regular) syntax as a syntax extension of OCaml revised syntax, hence the Camlp4OCamlRevisedParser is always loaded.
  • Modules ended by ParserParser is for the syntax for stream parsers. Here again the original syntax is an extension of the revised one.
  • The list of abbreviations for the parsers is in the file
  • The Camlp4AutoPrinter (also abbreviated -printer a) is either Camlp4OCamlPrinter (see below) if the output is a terminal (tty) or the Camlp4OCamlAstDumper otherwise.
  • Camlp4OCamlPrinter is the original syntax printer (the implementation is in Camlp4.Printers.OCaml). This printer is abbreviated as -printer o.
  • Camlp4OCamlAstDumper dumps the OCaml AST as a marshaled value (this printer is abbreviated as -printer p).
  • Don't confuse the OCaml AST dumper with the Camlp4 AST Dumper (Camlp4AstDumper) also abbreviated as -printer d, that dumps the Camlp4 AST as a marshaled value.

Why pre-process?

Pre-processing is necessary when one wants to compile a file which is not written in "pure" original syntax. This is the case for:

  • code written in the revised syntax
  • code written in the original syntax, using macros
  • camlp4 syntax extensions
  • files using one or more syntax extensions

Please note that pre-processing files written in "pure" original syntax is not mandatory (since the Objective Caml compiler understands it natively), however it may be damn useful when dealing with the cryptic "Syntax error" message:

Consider the following code:

let a = (5 + )

And the error messages, without and with pre-processing:

$ ocamlc
File "", line 1, characters 13-14:
Syntax error
$ ocamlc -pp camlp4o.opt
File "", line 1, characters 9-10:
Parse error: [expr] expected after [infix operator (level 2) (start with '+', '-')] (in [expr])
Preprocessor error

How to pre-process?

Using the "-pp" option, as follows:

ocamlc -pp <camlp4 command> <implementation (.ml) or interface (.mli) file>

Note that you may force parsing of a file as an implementation (using -impl) or an interface (using -intf), regardless of the file extension.

Pre-processing a file written in regular syntax:

ocamlc -pp camlp4o.opt

Pre-processing a file written in revised syntax:

ocamlc -pp camlp4r.opt

Pre-processing a syntax extension written in original syntax:

ocamlc -I +camlp4 -pp camlp4of.opt

Pre-processing a syntax extension written in revised syntax:

ocamlc -I +camlp4 -pp camlp4rf.opt
Personal tools
Espace privé