camlp5-6.14/0000775000175000017500000000000012556457261011672 5ustar rogloroglocamlp5-6.14/doc/0000775000175000017500000000000012556457206012436 5ustar rogloroglocamlp5-6.14/doc/.gitignore0000664000175000017500000000004412556457206014424 0ustar rogloroglo*.aux *.bbl *.blg *.dvi *.log *.toc camlp5-6.14/doc/htmlp/0000775000175000017500000000000012556457206013562 5ustar rogloroglocamlp5-6.14/doc/htmlp/printers.html0000664000175000017500000002476712556457206016336 0ustar rogloroglo extensible printers

Extensible printers

This chapter describes the syntax and semantics of the extensible printers of Camlp5.

Similar to the extensible grammars, the extensible printers allow to define and extend printers of data or programs. A specific statement "EXTEND_PRINTER" allow to define these extensions.

Getting started

A printer is a value of type "Eprinter.t a" where "a" is the type of the item to be printed. When applied, a printer returns a string, representing the printed item.

To create a printer, one must use the function "Eprinter.make" with, as parameter, the name of the printer, (used in error messages). A printer is created empty, i.e. it fails if it is applied.

As with grammar entries, printers may have several levels. When the function "Eprinter.apply" is applied to a printer, the first level is called. The function "Eprinter.apply_level" allows to call a printer at some specific level possibly different from the first one. When a level does not match any value of the printed item, the next level is tested. If there is no more levels, the printer fails.

In semantic actions of printers, functions are provided to recursively call the current level and the next level. Moreover, a printing context variable is also given, giving the current indentation, what should be printed before in the same line and what should be printed after in the same line (it is not mandatory to use them).

The extension of printers can be done with the "EXTEND_PRINTER" statement added by the parsing kit "pa_extprint.cmo".

Syntax of the EXTEND_PRINTER statement

        expression ::= extend-statement
  extend-statement ::= "EXTEND_PRINTER" extend-body "END"
       extend-body ::= extend-printers
   extend-printers ::= extend-printer extend-printers
                     | <nothing>
    extend-printer ::= printer-name ":" position-opt "[" levels "]"
      position-opt ::= "FIRST"
                     | "LAST"
                     | "BEFORE" label
                     | "AFTER" label
                     | "LEVEL" label
                     | <nothing>
            levels ::= level "|" levels
                     | level
             level ::= label-opt "[" rules "]"
         label-opt ::= label
                     | <nothing>
             rules ::= rule "|" rules
                     | rule
              rule ::= pattern "->" expression
                     | pattern "when" expression "->" expression
      printer-name ::= qualid
            qualid ::= qualid "." qualid
                     | uident
                     | lident
            uident ::= 'A'-'Z' ident
            lident ::= ('a'-'z' | '_' | misc-byte) ident
             ident ::= ident-char*
        ident-char ::= ('a'-'a' | 'A'-'Z' | '0'-'9' | '_' | ''' | misc-byte)
         misc-byte ::= '\128'-'\255'

Semantics of EXTEND_PRINTER

Printers definition list

All printers are extended according to their corresponding definitions which start with an optional "position" and follow with the "levels" definition.

Optional position

After the colon, it is possible to specify where to insert the defined levels:

Levels

After the optional "position", the level list follow. The levels are separated by vertical bars, the whole list being between brackets.

A level starts with an optional label, which corresponds to its name. This label is useful to specify this level in case of future extensions, using the position (see previous section) or for possible direct calls to this specific level.

Rules

A level is a list of rules separated by vertical bars, the whole list being between brackets.

A rule is an usual pattern association (in a function or in the "match" statement), i.e. a pattern, an arrow and an expression. The expression is the semantic action which must be of type "string".

Rules insertion

The rules are sorted by their patterns, according to the rules of the extensible functions.

Semantic action

The semantic action, i.e. the expression following the right arrow in rules, contains in its environment the variables bound by the pattern and three more variables:

The variables "curr" and "next" are of type:

  pr_context -> t -> string

where "t" is the type of the printer (i.e. the type of its patterns).

The variable "curr", "next" and "pc" have predefined names and can hide the possible identifiers having the same names in the pattern or in the environment of the "EXTEND_PRINTER" statement.

The Eprinter module

See its section in the chapter "Library".

Examples

Parser and Printer of expressions

This example illustrates the symmetry between parsers and printers. A simple type of expressions is defined. A parser converts a string to a value of this type, and a printer converts a value of this type to a string.

In the printer, there is no use of the "pc" parameter and no use of the "Pretty" module. The strings are printed on a single line.

Here is the source (file "foo.ml"):

  #load "pa_extend.cmo";
  #load "pa_extprint.cmo";

  open Printf;

  type expr =
    [ Op of string and expr and expr
    | Int of int
    | Var of string ]
  ;

  value g = Grammar.gcreate (Plexer.gmake ());
  value pa_e = Grammar.Entry.create g "expr";
  value pr_e = Eprinter.make "expr";

  EXTEND
    pa_e:
      [ [ x = SELF; "+"; y = SELF -> Op "+" x y
        | x = SELF; "-"; y = SELF -> Op "-" x y ]
      | [ x = SELF; "*"; y = SELF -> Op "*" x y
        | x = SELF; "/"; y = SELF -> Op "/" x y ]
      | [ x = INT -> Int (int_of_string x)
        | x = LIDENT -> Var x
        | "("; x = SELF; ")" -> x ] ]
    ;
  END;

  EXTEND_PRINTER
    pr_e:
      [ [ Op "+" x y -> sprintf "%s + %s" (curr pc x) (next pc y)
        | Op "-" x y -> sprintf "%s - %s" (curr pc x) (next pc y) ]
      | [ Op "*" x y -> sprintf "%s * %s" (curr pc x) (next pc y)
        | Op "/" x y -> sprintf "%s / %s" (curr pc x) (next pc y) ]
      | [ Int x -> string_of_int x
        | Var x -> x
        | x -> sprintf "(%s)" (Eprinter.apply pr_e pc x) ] ]
    ;
  END;

  value parse s = Grammar.Entry.parse pa_e (Stream.of_string s);
  value print e = Eprinter.apply pr_e Pprintf.empty_pc e;

  if Sys.interactive.val then ()
  else print_endline (print (parse Sys.argv.(1)));

Remark on the use of "curr" and "next" while printing operators: due to left associativity, the first operand uses "curr" and the second operand uses "next". For right associativity operators, they should be inverted. For no associativity, both should use "next".

The last line of the file allows use in either the OCaml toplevel or as standalone program, taking the string to be printed as parameter. It can be compiled this way:

  ocamlc -pp camlp5r -I +camlp5 gramlib.cma foo.ml

Examples of use (notice the redundant parentheses automatically removed by the printing algorithm):

  $ ./a.out "(3 * x) + (2 / y)"
  3 * x + 2 / y
  $ ./a.out "(x+y)*(x-y)"
  (x + y) * (x - y)
  $ ./a.out "x + y - z"
  x + y - z
  $ ./a.out "(x + y) - z"
  x + y - z
  $ ./a.out "x + (y - z)"
  x + (y - z)

Printing OCaml programs

Complete examples of usage of extensible printers are the printers in syntaxes and extended syntaxes provided by Camlp5 in the pretty printing kits:

See the chapter entitled "Printing programs".

camlp5-6.14/doc/htmlp/ast_transi.html0000664000175000017500000013456512556457206016635 0ustar rogloroglo AST - transitional

Syntax tree - transitional mode

This chapter presents the Camlp5 syntax tree when Camlp5 is installed in transitional mode.

Introduction

This syntax tree is defined in the module "MLast" provided by Camlp5. Each node corresponds to a syntactic entity of the corresponding type.

For example, the syntax tree of the statement "if" can be written:

  MLast.ExIfe loc e1 e2 e3

where "loc" is the location in the source, and "e1", "e2" and "e3" are respectively the expression after the "if", the one after the "then" and the one after the "else".

If a program needs to manipulate syntax trees, it can use the nodes defined in the module "MLast". The programmer must know how the concrete syntax is transformed into this abstract syntax.

A simpler solution is to use one of the quotation kit "q_MLast.cmo". It proposes quotations which represent the abstract syntax (the nodes of the module "MLast") into concrete syntax with antiquotations to bind variables inside. The example above can be written:

  <:expr< if $e1$ then $e2$ else $e3$ >>

This representation is very interesting when one wants to manipulate complicated syntax trees. Here is an example taken from the Camlp5 sources themselves:

  <:expr<
    match try Some $f$ with [ Stream.Failure -> None ] with
    [ Some $p$ -> $e$
    | _ -> raise (Stream.Error $e2$) ]
  >>

This example was in a position of a pattern. In abstract syntax, it should have been written:

  MLast.ExMat _
    (MLast.ExTry _ (MLast.ExApp _ (MLast.ExUid _ "Some") f)
       [(MLast.PaAcc _ (MLast.PaUid _ "Stream") (MLast.PaUid _ "Failure"),
         None, MLast.ExUid _ "None")])
    [(MLast.PaApp _ (MLast.PaUid _ "Some") p, None, e);
     (MLast.PaAny _, None,
      MLast.ExApp _ (MLast.ExLid _ "raise")
        (MLast.ExApp _
           (MLast.ExAcc _ (MLast.ExUid _ "Stream") (MLast.ExUid _ "Error"))
           e2))]

Which is less readable and much more complicated to build and update.

Instead of thinking of "a syntax tree", the programmer can think of "a piece of program".

Location

In all syntax tree nodes, the first parameter is the source location of the node.

In expressions

When a quotation is in the context of an expression, the location parameter is "loc" in the node and in all its possible sub-nodes. Example: if we consider the quotation:

  <:sig_item< value foo : int -> bool >>

This quotation, in a context of an expression, is equivalent to:

  MLast.SgVal loc "foo"
    (MLast.TyArr loc (MLast.TyLid loc "int") (MLast.TyLid loc "bool"));

The name "loc" is predefined. However, it is possible to change it, using the argument "-loc" of the Camlp5 shell commands.

Consequently, if there is no variable "loc" defined in the context of the quotation, or if it is not of the correct type, a semantic error occur in the OCaml compiler ("Unbound value loc").

Note that in the extensible grammars, the variable "loc" is bound, in all semantic actions, to the location of the rule.

If the created node has no location, the programmer can define a variable named "loc" equal to "Ploc.dummy".

In patterns

When a quotation is in the context of a pattern, the location parameter of all nodes and possible sub-nodes is set to the wildcard ("_"). The same example above:

  <:sig_item< value foo : int -> bool >>

is equivalent, in a pattern, to:

  MLast.SgVal _ "foo"
    (MLast.TyArr _ (MLast.TyLid _ "int") (MLast.TyLid _ "bool"))

However, it is possible to generate a binding of the variable "loc" on the top node by writing a "colon" before the "less" in the quotation. The same example:

  <:sig_item:< value foo : int -> bool >>

is equivalent to:

  MLast.SgVal loc "foo"
    (MLast.TyArr _ (MLast.TyLid _ "int") (MLast.TyLid _ "bool"))

Antiquotations

The expressions or patterns between dollar ($) characters are called antiquotations. In opposition to quotations which has its own syntax rules, the antiquotation is an area in the syntax of the enclosing context (expression or pattern). See the chapter about quotations.

If a quotation is in the context of an expression, the antiquotation must be an expression. It can be any expression, including function calls. Examples:

  value f e el = <:expr< [$e$ :: $loop False el$] >>;
  value patt_list p pl = <:patt< ( $list:[p::pl]$) >>;

If a quotation is in the context of an pattern, the antiquotation is a pattern. Any pattern is possible, including the wildcard character ("_"). Examples:

   fun [ <:expr< $lid:op$ $_$ $_$ >> -> op ]
   match p with [ <:patt< $_$ | $_$ >> -> Some p ]

Nodes and Quotations

This section describes all nodes defined in the module "MLast" of Camlp5 and how to write them with quotations. Notice that, inside quotations, one is not restricted to these elementary cases, but any complex value can be used, resulting on possibly complex combined nodes.

Variables names give information of their types:

expr

Expressions of the language.

Node <:expr< ... >> Comment
ExAcc loc e1 e2 $e1$ . $e2$ access
ExAnt loc e $anti:e$ antiquotation (1)
ExApp loc e1 e2 $e1$ $e2$ application
ExAre loc e1 e2 $e1$ .( $e2$ ) array element
ExArr loc le [| $list:le$ |] array
ExAsr loc e assert $e$ assert
ExAss loc e1 e2 $e1$ := $e2$ assignment
ExBae loc e le $e$ .{ $list:le$ } big array element
ExChr loc s $chr:s$ character constant
ExCoe loc e None t2 ($e$ :> $t2$) coercion
ExCoe loc e (Some t1) t2 ($e$ : $t1$ :> $t2$) coercion
ExFlo loc s $flo:s$ float constant
ExFor loc s e1 e2 True le for $lid:s$ = $e1$ to $e2$ do { $list:le$ } for (increasing)
ExFor loc s e1 e2 False le for $lid:s$ = $e1$ downto $e2$ do { $list:le$ } for (decreasing)
ExFor loc s e1 e2 b le for $lid:s$ = $e1$ $to:b$ $e2$ do { $list:le$ } for
ExFun loc lpee fun [ $list:lpee$ ] function (2)
ExIfe loc e1 e2 e3 if $e1$ then $e2$ else $e3$ if
ExInt loc s1 "" $int:s1$ integer constant
ExInt loc s1 "l" $int32:s1$ integer 32 bits
ExInt loc s1 "L" $int64:s1$ integer 64 bits
ExInt loc s1 "n" $nativeint:s1$ native integer
ExLab loc p None ~{$p$} label
ExLab loc p (Some e) ~{$p$ = $e$} label
ExLab loc p oe ~{$p$ $opt:oe$} label
ExLaz loc e lazy $e$ lazy
ExLet loc True lpe e let rec $list:lpe$ in $e$ let rec
ExLet loc False lpe e let $list:lpe$ in $e$ let not rec
ExLet loc b lpe e let $flag:b$ $list:lpe$ in $e$ let
ExLid loc s $lid:s$ lowercase identifier
ExLmd loc s me e let module $uid:s$ = $me$ in $e$ let module
ExMat loc e lpee match $e$ with [ $list:lpee$ ] match (2)
ExNew loc ls new $list:ls$ new
ExObj loc None lcsi object $list:lcsi$ end object expression
ExObj loc (Some p) lcsi object ($p$) $list:lcsi$ end object expression
ExObj loc op lcsi object $opt:op$ $list:lcsi$ end object expression
ExOlb loc p None ?{$p$} option label
ExOlb loc p (Some e) ?{$p$ = $e$} option label
ExOlb loc p oe ?{$p$ $opt:oe$} option label
ExOvr loc lse {< $list:lse$ >} override
ExPck loc me None (module $me$) module packing
ExPck loc me (Some mt) (module $me$ : $mt$) module packing
ExRec loc lpe None {$list:lpe$} record
ExRec loc lpe (Some e) {($e$) with $list:lpe$} record
ExSeq loc le do { $list:le$ } sequence
ExSnd loc e s $e$ # $s$ method call
ExSte loc e1 e2 $e1$ .[ $e2$ ] string element
ExStr loc s $str:s$ string
ExTry loc e lpee try $e$ with [ $list:lpee$ ] try (2)
ExTup loc le ($list:le$) t-uple
ExTyc loc e t ($e$ : $t$) type constraint
ExUid loc s $uid:s$ uppercase identifier
ExVrn loc s ` $s$ variant
ExWhi loc e le while $e$ do { $list:le$ } while
(1)

Node used in the quotation expanders to tells at conversion to OCaml compiler syntax tree time, that all locations of the sub-tree is correcty located in the quotation. By default, in quotations, the locations of all generated nodes are the location of the whole quotation. This node allows to make an exception to this rule, since we know that the antiquotation belongs to the universe of the enclosing program. See the chapter about quotations and, in particular, its section about antiquotations.

(2)

The variable "lpee" found in "function", "match" and "try" statements correspond to a list of "(patt * option expr * expr)" where the "option expr" is the "when" optionally following the pattern:

  p -> e

is represented by:

  (p, None, e)

and

  p when e1 -> e

is represented by:

  (p, Some e1, e)

patt

Patterns of the language.

Node <:patt< ... >> Comment
PaAcc loc p1 p2 $p1$ . $p2$ access
PaAli loc p1 p2 ($p1$ as $p2$) alias
PaAnt loc p $anti:p$ antiquotation (1)
PaAny loc _ wildcard
PaApp loc p1 p2 $p1$ $p2$ application
PaArr loc lp [| $list:lp$ |] array
PaChr loc s $chr:s$ character
PaFlo loc s $flo:s$ float
PaInt loc s1 "" $int:s1$ integer constant
PaInt loc s1 "l" $int32:s1$ integer 32 bits
PaInt loc s1 "L" $int64:s1$ integer 64 bits
PaInt loc s1 "n" $nativeint:s1$ native integer
PaLab loc p1 None ~{$p1$} label
PaLab loc p1 (Some p2) ~{$p1$ = $p2$} label
PaLab loc p1 op2 ~{$p1$ $opt:op2$} label
PaLaz loc p lazy $p$ lazy
PaLid loc s $lid:s$ lowercase identifier
PaNty loc s (type $lid:s$) new type
PaOlb loc p None ?{$p$} option label
PaOlb loc p (Some e) ?{$p$ = $e$} option label
PaOlb loc p oe ?{$p$ $opt:oe$} option label
PaOrp loc p1 p2 $p1$ | $p2$ or
PaRec loc lpp { $list:lpp$ } record
PaRng loc p1 p2 $p1$ .. $p2$ range
PaStr loc s $str:s$ string
PaTup loc lp ($list:lp$) t-uple
PaTyc loc p t ($p$ : $t$) type constraint
PaTyp loc ls # $list:ls$ type pattern
PaUid loc s $uid:s$ uppercase identifier
PaUnp loc s None (module $uid:s$) module unpacking
PaUnp loc s (Some mt) (module $uid:s$ : $mt$) module unpacking
PaVrn loc s ` $s$ variant
(1) Node used to specify an antiquotation area, like for the equivalent node in expressions. See above.

ctyp

Type expressions of the language.

Node <:ctyp< ... >> Comment
TyAcc loc t1 t2 $t1$ . $t2$ access
TyAli loc t1 t2 $t1$ as $t2$ alias
TyAny loc _ wildcard
TyApp loc t1 t2 $t1$ $t2$ application
TyArr loc t1 t2 $t1$ -> $t2$ arrow
TyCls loc ls # $list:ls$ class
TyLab loc s t ~$s$: $t$ label
TyLid loc s $lid:s$ lowercase identifier
TyMan loc t1 True t2 $t1$ == private $t2$ manifest
TyMan loc t1 False t2 $t1$ == $t2$ manifest
TyMan loc t1 b t2 $t1$ == $priv:b$ $t2$ manifest
TyObj loc lst True < $list:lst$ .. > object
TyObj loc lst False < $list:lst$ > object
TyObj loc lst b < $list:lst$ $flag:b$ > object
TyOlb loc s t ?$s$: $t$ option label
TyPck loc mt (module $mt$) package
TyPol loc ls t ! $list:ls$ . $t$ polymorph
TyQuo loc s '$s$ variable
TyRec loc llsbt { $list:llsbt$ } record
TySum loc llslt [ $list:llslt$ ] sum
TyTup loc lt ( $list:lt$ ) t-uple
TyUid loc s $uid:s$ uppercase identifier
TyVrn loc lpv None [ = $list:lpv$ ] variant
TyVrn loc lpv (Some None) [ > $list:lpv$ ] variant
TyVrn loc lpv (Some (Some [])) [ < $list:lpv$ ] variant
TyVrn loc lpv (Some (Some ls)) [ < $list:lpv$ > $list:ls$ ] variant

modules...

str_item

Structure items, i.e. phrases in a ".ml" file or "struct" elements.

Node <:str_item< ... >> Comment
StCls loc lcice class $list:lcice$ class declaration
StClt loc lcict class type $list:lcict$ class type declaration
StDcl loc lsi declare $list:lsi$ end declare
StDir loc s None # $lid:s$ directive
StDir loc s (Some e) # $lid:s$ $e$ directive
StDir loc s oe # $lid:s$ $opt:oe$ directive
StExc loc s [] [] exception $uid:s$ exception
StExc loc s lt [] exception $uid:s$ of $list:lt$ exception
StExc loc s [] ls exception $uid:s$ = $list:ls$ exception
StExc loc s lt ls exception $uid:s$ of $list:lt$ = $list:ls$ exception
StExp loc e $exp:e$ expression
StExt loc s t ls external $s$ : $t$ = $list:ls$ external
StInc loc me include $me$ include
StMod loc True lsme module rec $list:lsme$ module rec
StMod loc False lsme module $list:lsme$ module non rec
StMod loc b lsme module $flag:b$ $list:lsme$ module
StMty loc s mt module type $s$ = $mt$ module type
StOpn loc ls open $list:ls$ open
StTyp loc ltd type $list:ltd$ type declaration
StUse loc s lsil # $str:s$ $list:lsil$ ... internal use ... (1)
StVal loc True lpe value rec $list:lpe$ value rec
StVal loc False lpe value $list:lpe$ value non rec
StVal loc b lpe value $flag:b$ $list:lpe$ value
(1)

Node internally used to specify a different file name applying to the whole subtree. This is generated by the directive "use" and used when converting to the OCaml syntax tree which needs the file name in its location type.

sig_item

Signature items, i.e. phrases in a ".mli" file or elements inside "sig ... end".

Node <:sig_item< ... >> Comment
SgCls loc lcict class $list:lcict$ class
SgClt loc lcict class type $list:lcict$ class type
SgDcl loc lsi declare $list:lsi$ end declare
SgDir loc s None # $lid:s$ directive
SgDir loc s (Some e) # $lid:s$ $e$ directive
SgDir loc s oe # $lid:s$ $opt:oe$ directive
SgExc loc s [] exception $s$ exception
SgExc loc s lt exception $s$ of $list:lt$ exception
SgExt loc s t ls external $s$ : $t$ = $list:ls$ external
SgInc loc mt include $mt$ include
SgMod loc True lsmt module rec $list:lsmt$ module rec
SgMod loc False lsmt module $list:lsmt$ module non rec
SgMod loc b lsmt module $flag:b$ $list:lsmt$ module
SgMty loc s mt module type $s$ = $mt$ module type
SgOpn loc ls open $list:ls$ open
SgTyp loc ltd type $list:ltd$ type declaration
SgUse loc s lsil # $str:s$ $list:lsil$ ... internal use ... (1)
SgVal loc s t value $s$ : $t$ value
(1)

Same remark as for "str_item" above.

module_expr

Node <:module_expr< ... >> Comment
MeAcc loc me1 me2 $me1$ . $me2$ access
MeApp loc me1 me2 $me1$ $me2$ application
MeFun loc s mt me functor ($s$ : $mt$) -> $me$ functor
MeStr loc lsi struct $list:lsi$ end struct
MeTyc loc me mt ($me$ : $mt$) module type constraint
MeUid loc s $uid:s$ uppercase identifier
MeUnp loc e None (value $e$) module unpacking
MeUnp loc e (Some mt) (value $e$ : $mt$) module unpacking

module_type

Node <:module_type< ... >> Comment
MtAcc loc mt1 mt2 $mt1$ . $mt2$ access
MtApp loc mt1 mt2 $mt1$ $mt2$ application
MtFun loc s mt1 mt2 functor ($s$ : $mt1$) -> $mt2$ functor
MtLid loc s $lid:s$ lowercase identifier
MtQuo loc s ' $s$ abstract
MtSig loc lsi sig $list:lsi$ end signature
MtTyo loc me module type of $me$ of module expression
MtUid loc s $uid:s$ uppercase identifier
MtWit loc mt lwc $mt$ with $list:lwc$ with construction

classes...

class_expr

Node <:class_expr< ... >> Comment
CeApp loc ce e $ce$ $e$ application
CeCon loc ls lt [ $list:lt$ ] $list:ls$ constructor
CeFun loc p ce fun $p$ -> $ce$ function
CeLet loc True lpe ce let rec $list:lpe$ in $ce$ let rec
CeLet loc False lpe ce let $list:lpe$ in $ce$ let non rec
CeLet loc b lpe ce let $flag:b$ $list:lpe$ in $ce$ let
CeStr loc None lcsi object $list:lcsi$ end object
CeStr loc (Some p) lcsi object ($p$) $list:lcsi$ end object
CeStr loc op lcsi object $opt:op$ $list:lcsi$ end object
CeTyc loc ce ct ($ce$ : $ct$) class type constraint

class_type

Node <:class_type< ... >> Comment
CtAcc loc ct1 ct2 $ct1$ . $ct2$ access
CtApp loc ct1 ct2 $ct1$ $ct2$ application
CtCon loc ct lt $ct$ [ $list:lt$ ] constructor
CtFun loc t ct [ $t$ ] -> $ct$ arrow
CtIde loc s $id:s$ identifier
CtSig loc None lcsi object $list:lcsi$ end object
CtSig loc (Some t) lcsi object ($t$) $list:lcsi$ end object
CtSig loc ot lcsi object $opt:ot$ $list:lcsi$ end object

class_str_item

Node <:class_str_item< ... >> Comment
CrCtr loc t1 t2 type $t1$ = $t2$ type constraint
CrDcl loc lcsi declare $list:lcsi$ end declaration list
CrInh loc ce None inherit $ce$ inheritance
CrInh loc ce (Some s) inherit $ce$ $opt:Some s$ inheritance
CrInh loc ce os inherit $ce$ $opt:os$ inheritance
CrIni loc e initializer $e$ initialization
CrMth loc True True s None e method! private $lid:s$ = $e$ method
CrMth loc True True s (Some t) e method! private $lid:s$ : $t$ = $e$ method
CrMth loc True True s ot e method! private $lid:s$ $opt:ot$ = $e$ method
CrMth loc True False s None e method! $lid:s$ = $e$ method
CrMth loc True False s (Some t) e method! $lid:s$ : $t$ = $e$ method
CrMth loc True False s ot e method! $lid:s$ $opt:ot$ = $e$ method
CrMth loc True b2 s None e method! $priv:b2$ $lid:s$ = $e$ method
CrMth loc True b2 s (Some t) e method! $priv:b2$ $lid:s$ : $t$ = $e$ method
CrMth loc True b2 s ot e method! $priv:b2$ $lid:s$ $opt:ot$ = $e$ method
CrMth loc False True s None e method private $lid:s$ = $e$ method
CrMth loc False True s (Some t) e method private $lid:s$ : $t$ = $e$ method
CrMth loc False True s ot e method private $lid:s$ $opt:ot$ = $e$ method
CrMth loc False False s None e method $lid:s$ = $e$ method
CrMth loc False False s (Some t) e method $lid:s$ : $t$ = $e$ method
CrMth loc False False s ot e method $lid:s$ $opt:ot$ = $e$ method
CrMth loc False b2 s None e method $priv:b2$ $lid:s$ = $e$ method
CrMth loc False b2 s (Some t) e method $priv:b2$ $lid:s$ : $t$ = $e$ method
CrMth loc False b2 s ot e method $priv:b2$ $lid:s$ $opt:ot$ = $e$ method
CrMth loc b1 True s None e method $!:b1$ private $lid:s$ = $e$ method
CrMth loc b1 True s (Some t) e method $!:b1$ private $lid:s$ : $t$ = $e$ method
CrMth loc b1 True s ot e method $!:b1$ private $lid:s$ $opt:ot$ = $e$ method
CrMth loc b1 False s None e method $!:b1$ $lid:s$ = $e$ method
CrMth loc b1 False s (Some t) e method $!:b1$ $lid:s$ : $t$ = $e$ method
CrMth loc b1 False s ot e method $!:b1$ $lid:s$ $opt:ot$ = $e$ method
CrMth loc b1 b2 s None e method $!:b1$ $priv:b2$ $lid:s$ = $e$ method
CrMth loc b1 b2 s (Some t) e method $!:b1$ $priv:b2$ $lid:s$ : $t$ = $e$ method
CrMth loc b1 b2 s ot e method $!:b1$ $priv:b2$ $lid:s$ $opt:ot$ = $e$ method
CrVal loc True True s e value! mutable $lid:s$ = $e$ value
CrVal loc True False s e value! $lid:s$ = $e$ value
CrVal loc True b2 s e value! $flag:b2$ $lid:s$ = $e$ value
CrVal loc False True s e value mutable $lid:s$ = $e$ value
CrVal loc False False s e value $lid:s$ = $e$ value
CrVal loc False b2 s e value $flag:b2$ $lid:s$ = $e$ value
CrVal loc b1 True s e value $!:b1$ mutable $lid:s$ = $e$ value
CrVal loc b1 False s e value $!:b1$ $lid:s$ = $e$ value
CrVal loc b1 b2 s e value $!:b1$ $flag:b2$ $lid:s$ = $e$ value
CrVav loc True s t value virtual mutable $lid:s$ : $t$ virtual value
CrVav loc False s t value virtual $lid:s$ : $t$ virtual value
CrVav loc b s t value virtual $flag:b$ $lid:s$ : $t$ virtual value
CrVir loc True s t method virtual private $lid:s$ : $t$ virtual method
CrVir loc False s t method virtual $lid:s$ : $t$ virtual method
CrVir loc b s t method virtual $flag:b$ $lid:s$ : $t$ virtual method

class_sig_item

Node <:class_sig_item< ... >> Comment
CgCtr loc t1 t2 type $t1$ = $t2$ type constraint
CgDcl loc lcsi declare $list:lcsi$ end declare
CgInh loc ct inherit $ct$ inheritance
CgMth loc True s t method private $lid:s$ : $t$ method
CgMth loc False s t method $lid:s$ : $t$ method
CgMth loc b s t method $flag:b$ $lid:s$ : $t$ method
CgVal loc True s t value mutable $lid:s$ : $t$ value
CgVal loc False s t value $lid:s$ : $t$ value
CgVal loc b s t value $flag:b$ $lid:s$ : $t$ value
CgVir loc True s t method virtual private $lid:s$ : $t$ virtual method
CgVir loc False s t method virtual $lid:s$ : $t$ virtual method
CgVir loc b s t method virtual $flag:b$ $lid:s$ : $t$ virtual method

other

type_decl

What is after 'type' or 'and' in a type declaration.

Node <:type_decl< ... >>
{tdNam=ls;tdPrm=ltv;tdPrv=True;tdDef=t;tdCon=ltt} $tp:ls$ $list:ltv$ = private $t$ $list:ltt$
{tdNam=ls;tdPrm=ltv;tdPrv=False;tdDef=t;tdCon=ltt} $tp:ls$ $list:ltv$ = $t$ $list:ltt$
{tdNam=ls;tdPrm=ltv;tdPrv=b;tdDef=t;tdCon=ltt} $tp:ls$ $list:ltv$ = $priv:b$ $t$ $list:ltt$

with_constr

"With" possibly following a module type.

Node <:with_constr< ... >> Comment
WcMod loc ls me module $list:ls$ = $me$ with module
WcMos loc ls me module $list:ls$ := $me$ with module substitution
WcTyp loc ls ltv True t type $list:ls$ $list:ltv$ = private $t$ with type
WcTyp loc ls ltv False t type $list:ls$ $list:ltv$ = $t$ with type
WcTyp loc ls ltv b t type $list:ls$ $list:ltv$ = $flag:b$ $t$ with type
WcTys loc ls ltv t type $list:ls$ $list:ltv$ := $t$ with type substitution

poly_variant

Polymorphic variants.

Node <:poly_variant< ... >> Comment
PvTag loc s True [] `$s$ constructor
PvTag loc s True lt `$s$ of & $list:lt$ constructor
PvTag loc s False lt `$s$ of $list:lt$ constructor
PvTag loc s b lt `$s$ of $flag:b$ $list:lt$ constructor
PvInh loc t $t$ type
camlp5-6.14/doc/htmlp/opretty.html0000664000175000017500000004405312556457206016164 0ustar rogloroglo Extensions of printing

Extensions of printing

Camlp5 provides extensions kits to pretty print programs in revised syntax and normal syntax. Some other extensions kits also allow to rebuild the parsers, or the EXTEND statements in their initial syntax. The pretty print system is itself extensible, by adding new rules. We present here how it works in the Camlp5 sources.

The pretty print system of Camlp5 uses the library modules Pretty, an original system to format output) and Extfun, another original system of extensible functions.

This chapter is designed for programmers that want to understand how the pretty printing of OCaml programs work in Camlp5, want to adapt, modify or debug it, or want to add their own pretty printing extensions.

Introduction

The files doing the pretty printings are located in Camlp5 sources in the directory "etc". Peruse them if you are interested in creating new ones. The main ones are:

We present here how this system works inside these files. First, the general principles. Second, more details of the implementation.

Principles

Using module Pretty

All functions in OCaml pretty printing take a parameter named "the printing context" (variable pc). It is a record holding :

A typical pretty printing function calls the function horiz_vertic of the library module Pretty. This function takes two functions as parameter:

Both functions catenate the strings by using the function sprintf of the library module Pretty which controls whether the printed data holds in the line or not. They generally call, recursively, other pretty printing functions with the same behaviour.

Let us see an example (fictitious) of printing an OCaml application. Let us suppose we have an application expression "e1 e2" to pretty print where e1 and e2 are sub-expressions. If both expressions and their application holds on one only line, we want to see:

  e1 e2

On the other hand, if they do not hold on one only line, we want to see e2 in another line with, say, an indendation of 2 spaces:

  e1
    e2

Here is a possible implementation. The function has been named expr_app and can call the function expr to print the sub-expressions e1 and e2:

  value expr_app pc e1 e2 =
    horiz_vertic
      (fun () ->
         let s1 = expr {(pc) with aft = ""} e1 in
         let s2 = expr {(pc) with bef = ""} e2 in
         sprintf "%s %s" s1 s2)
      (fun () ->
         let s1 = expr {(pc) with aft = ""} e1 in
         let s2 =
           expr
             {(pc) with
                ind = pc.ind + 2;
                bef = tab (pc.ind + 2)}
             e2
         in
         sprintf "%s\n%s" s1 s2)
  ;

The first function is the horizontal printing. It ends with a sprintf separating the printing of e1 and e2 by a space. The possible "before part" (pc.bef) and "after part" (pc.aft) are transmitted in the calls of the sub-functions.

The second function is the vertical printing. It ends with a sprintf separating the printing of e1 and e2 by a newline. The second line starts with an indendation, using the "before part" (pc.bef) of the second call to expr.

The pretty printing library function Pretty.horiz_vertic calls the first (horizontal) function, and if it fails (either because s1 or s2 are too long or hold newlines, or because the final string produced by sprintf is too long), calls the second (vertical) function.

Notice that the parameter pc contains a field pc.bef (what should be printed before in the same line), which in both cases is transmitted to the printing of e1 (since the syntax {(pc) with aft = ""} is a record with pc.bef kept). Same for the field pc.aft transmitted to the printing of e2.

Using EXTEND_PRINTER statement

This system is combined to the extensible printers to allow the extensibility of the pretty printing.

The code above actually looks like:

  EXTEND_PRINTER
    pr_expr:
      [ [ <:expr< $e1$ $e2$ >> ->
            horiz_vertic
              (fun () ->
                 let s1 = curr {(pc) with aft = ""} e1 in
                 let s2 = next {(pc) with bef = ""} e2 in
                 sprintf "%s %s" s1 s2)
              (fun () ->
                 let s1 = curr {(pc) with aft = ""} e1 in
                 let s2 =
                   next
                     {(pc) with
                        ind = pc.ind + 2;
                        bef = tab (pc.ind + 2)}
                     e2
                 in
                 sprintf "%s\n%s" s1 s2) ] ]
    ;
  END;

The variable "pc" is implicit in the semantic actions of the syntax "EXTEND_PRINTER", as well as two other variables: "curr" and "next".

These parameters, "curr" and "next", correspond to the pretty printing of, respectively, the current level and the next level. Since the application in OCaml is left associative, the first sub-expression is printed at the same (current) level and the second one is printed at the next level. We also see a call to next in the last (2nd) case of the function to treat the other cases in the next level.

Dangling else, bar, semicolon

In normal syntax, there are cases where it is necessary to enclose expressions between parentheses (or between begin and end, which is equivalent in that syntax). Three tokens may cause problems: the "else", the vertical bar "|" and the semicolon ";". Here are examples where the presence of these tokens constrains the previous expression to be parenthesized. In these three examples, removing the begin..end enclosers would change the meaning of the expression because the dangling token would be included in that expression:

Dangling else:

  if a then begin if b then c end else d

Dangling bar:

  function
    A ->
      begin match a with
        B -> c
      | D -> e
      end
  | F -> g

Dangling semicolon:

  if a then b
  else begin
    let c = d in
    e
  end;
  f

The information is transmitted by the value pc.dang. In the first example above, while displaying the "then" part of the outer "if", the sub-expression is called with the value pc.dang set to "else" to inform the last sub-sub-expression that it is going to be followed by that token. When a "if" expression should be displayed without "else" part, and that its "pc.dang" is "else", it should be enclosed with spaces.

This problem does not exist in revised syntax. While pretty printing in revised syntax, the parameter pc.dang is not necessary and remains the empty string.

By level

As explained in the chapter about the extensible printers (with the EXTEND_PRINTER statement), printers contain levels. The global printer variable of expressions is named "pr_expr" and contain all definitions for pretty printing expressions, organized by levels, just like the parsing of expressions. The definition of "pr_expr" actually looks like this:

  EXTEND_PRINTER
    pr_expr:
      [ "top"
        [ (* code for level "top" *) ]
      | "add"
        [ (* code for level "add" *) ]
      | "mul"
        [ (* code for level "mul" *) ]
      | "apply"
        [ (* code for level "apply" *) ]
      | "simple"
        [ (* code for level "add" *) ] ]
    ;
  END;

The Prtools module

The Prtools module is defined inside Camlp5 for pretty printing kits. It provides variables and functions to process comments, and meta-functions to process lists (horizontally, vertically, paragraphly).

Comments

value comm_bef : int -> MLast.loc -> string;
"comm_bef ind loc" get the comment from the source just before the given location "loc". This comment may be reindented using "ind". Returns the empty string if no comment found.
value source : ref string;
The initial source string, which must be set by the pretty printing kit. Used by [comm_bef] above.
value set_comm_min_pos : int -> unit;
Set the minimum position of the source where comments can be found, (to prevent possible duplication of comments).

Meta functions for lists

type pr_fun 'a = pr_context -> 'a -> string;
Type of printer functions.
value hlist : pr_fun 'a -> pr_fun (list 'a);
[hlist elem pc el] returns the horizontally pretty printed string of a list of elements; elements are separated with spaces.
The list is displayed in one only line. If this function is called in the context of the [horiz] function of the function [horiz_vertic] of the module Printing, and if the line overflows or contains newlines, the function internally fails (the exception is catched by [horiz_vertic] for a vertical pretty print).
value hlist2 : pr_fun 'a -> pr_fun 'a -> pr_fun (list 'a);
horizontal list with a different function from 2nd element on.
value hlistl : pr_fun 'a -> pr_fun 'a -> pr_fun (list 'a);
horizontal list with a different function for the last element.
value vlist : pr_fun 'a -> pr_fun (list 'a);
[vlist elem pc el] returns the vertically pretty printed string of a list of elements; elements are separated with newlines and indentations.
value vlist2 : pr_fun 'a -> pr_fun 'a -> pr_fun (list 'a);
vertical list with different function from 2nd element on.
value vlist3 : pr_fun ('a * bool) -> pr_fun ('a * bool) -> pr_fun (list 'a);
vertical list with different function from 2nd element on, the boolean value being True for the last element of the list.
value vlistl : pr_fun 'a -> pr_fun 'a -> pr_fun (list 'a);
vertical list with different function for the last element.
value plist : pr_fun 'a -> int -> pr_fun (list ('a * string));
[plist elem sh pc el] returns the pretty printed string of a list of elements with separators. The elements are printed horizontally as far as possible. When an element does not fit on the line, a newline is added and the element is displayed in the next line with an indentation of [sh]. [elem] is the function to print elements, [el] a list of pairs (element * separator) (the last separator being ignored).
value plistb : pr_fun 'a -> int -> pr_fun (list ('a * string));
[plist elem sh pc el] returns the pretty printed string of the list of elements, like with [plist] but the value of [pc.bef] corresponds to an element already printed, as it were on the list. Therefore, if the first element of [el] does not fit in the line, a newline and a tabulation is added after [pc.bef].
value plistl : pr_fun 'a -> pr_fun 'a -> int -> pr_fun (list ('a * string));
paragraph list with a different function for the last element.
value hvlistl : pr_fun 'a -> pr_fun 'a -> pr_fun (list 'a);
applies "hlistl" if the context is horizontal; else applies "vlistl".

Miscellaneous

value tab : int -> string;
[tab ind] is equivalent to [String.make ind ' ']
value flatten_sequence : MLast.expr -> option (list MLast.expr);
[flatten_sequence e]. If [e] is an expression representing a sequence, return the list of expressions of the sequence. If some of these expressions are already sequences, they are flattened in the list. If that list contains expressions of the form let..in sequence, this sub-sequence is also flattened with the let..in applying only to the first expression of the sequence. If [e] is a let..in sequence, it works the same way. If [e] is not a sequence nor a let..in sequence, return None.

Example : repeat..until

This pretty prints the example repeat..until statement programmed in the chapter Syntax extensions (first version generating a "while" statement).

The code

The pattern generated by the "repeat" statement is recognized (sequence ending with a "while" whose contents is the same than the beginning of the sequence) by the function "is_repeat" and the repeat statement is pretty printed in its initial form using the function "horiz_vertic" of the Pretty module. File "pr_repeat.ml":

  #load "pa_extprint.cmo";
  #load "q_MLast.cmo";

  open Pcaml;
  open Pretty;
  open Prtools;

  value eq_expr_list el1 el2 =
    if List.length el1 <> List.length el2 then False
    else List.for_all2 eq_expr el1 el2
  ;

  value is_repeat el =
    match List.rev el with
    [ [<:expr< while not $e$ do { $list:el2$ } >> :: rel1] ->
        eq_expr_list (List.rev rel1) el2
    | _ -> False ]
  ;

  value semi_after pr pc = pr {(pc) with aft = sprintf "%s;" pc.aft};

  EXTEND_PRINTER
    pr_expr:
      [ [ <:expr< do { $list:el$ } >> when is_repeat el ->
            match List.rev el with
            [ [<:expr< while not $e$ do { $list:el$ } >> :: _] ->
                horiz_vertic
                  (fun () ->
                     sprintf "%srepeat %s until %s%s" pc.bef
                       (hlistl (semi_after curr) curr
                          {(pc) with bef = ""; aft = ""} el)
                       (curr {(pc) with bef = ""; aft = ""} e)
                       pc.aft)
                  (fun () ->
                     let s1 = sprintf "%srepeat" (tab pc.ind) in
                     let s2 =
                       vlistl (semi_after curr) curr
                         {(pc) with
                          ind = pc.ind + 2;
                          bef = tab (pc.ind + 2);
                          aft = ""}
                         el
                     in
                     let s3 =
                       sprintf "%suntil %s" (tab pc.ind)
                         (curr {(pc) with bef = ""} e)
                     in
                     sprintf "%s\n%s\n%s" s1 s2 s3)
            | _ -> assert False ] ] ]
    ;
  END;

Compilation

  ocamlc -pp camlp5r -I +camlp5 -c pr_repeat.ml

Testing

Getting the same files "foo.ml" and "bar.ml" of the repeat syntax example:

  $ cat bar.ml
  #load "./foo.cmo";
  value x = ref 42;
  repeat
    print_int x.val;
    print_endline "";
    x.val := x.val + 3
  until x.val > 70;

  $ camlp

Without the pretty printing kit:

  $ camlp5r pr_r.cmo bar.ml
  #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
    }
  };

With the pretty printing kit:

  $ camlp5r pr_r.cmo ./pr_repeat.cmo bar.ml -l 75
  #load "./foo.cmo";
  value x = ref 42;
  repeat
    print_int x.val;
    print_endline "";
    x.val := x.val + 3
  until x.val > 70;
camlp5-6.14/doc/htmlp/revsynt.html0000664000175000017500000006550512556457206016175 0ustar rogloroglo revised syntax

The revised syntax

The revised syntax is an alternative syntax of OCaml. It is close to the normal syntax. We present here only the differences between the two syntaxes.

Notice that there is a simple way to know how the normal syntax is written in revised syntax: write the code in a file "foo.ml" in normal syntax and type, in a shell:

  camlp5o pr_r.cmo pr_rp.cmo foo.ml

And, conversely, how a file "bar.ml" written in revised syntax is displayed in normal syntax:

  camlp5r pr_o.cmo pr_op.cmo bar.ml

Even simpler, without creating a file:

  camlp5o pr_r.cmo pr_op.cmo -impl -
  ... type in normal syntax ...
  ... type control-D ...
  camlp5r pr_o.cmo pr_rp.cmo -impl -
  ... type in revised syntax ...
  ... type control-D ...

Lexing

Modules, Structure and Signature items

Expressions and Patterns

Imperative constructions

Tuples and Lists

Records

Irrefutable patterns

An irrefutable pattern is a pattern which is syntactically visible and never fails. They are used in some syntactic constructions. It is either:

Notice that this definition is only syntactic: a constructor belonging to a type having only one constructor is not considered as an irrefutable pattern (except "()").

Constructions with matching

Mutables and Assignment

Miscellaneous

Types and Constructors

Streams and Parsers

Classes and Objects

Labels and Variants

camlp5-6.14/doc/htmlp/index.html0000664000175000017500000001365712556457206015573 0ustar rogloroglo Camlp5

Introduction

Camlp5 is a preprocessor and pretty-printer for OCaml programs. It also provides parsing and printing tools.

As a preprocessor, it allows to:

As a pretty printer, it allows to:

Camlp5 also provides some parsing and pretty printing tools:

It works as a shell command and can also be used in the OCaml toplevel.

Shell usage

The main shell commands are:

These commands can be given as parameters of the option -pp of the OCaml compiler. Examples:

  ocamlc -pp camlp5o foo.ml
  ocamlc -pp camlp5r bar.ml

This way, the parsing is done by Camlp5. In case of syntax errors, the parsing fails with an error message and the compilation is aborted. Otherwise, the OCaml compiler continues with the syntax tree provided by Camlp5.

In the toplevel, it is possible to preprocess the input phrases by loading one of the files "camlp5o.cma" or "camlp5r.cma". The common usage is:

  ocaml -I +camlp5 camlp5o.cma
  ocaml -I +camlp5 camlp5r.cma

It is possible that, in your installation, the Camlp5 library is not in the OCaml directory. In this case, the commands must be:

  ocaml -I `camlp5 -where` camlp5o.cma
  ocaml -I `camlp5 -where` camlp5r.cma

In general, in this documentation, when a command requires:

  -I +camlp5

it can be replaced by:

  -I `camlp5 -where`

or, by:

  -I <directory>

where "directory" is the directory path where the Camlp5 library files are installed.

Parsing and Printing kits

Parsing and printing extensions are OCaml object files, i.e. files with the extension ".cmo" or ".cma". They are the result of the compilation of OCaml source files containing what is necessary to do the parsing or printing. These object files are named parsing and printing kits.

These files cannot be linked to produce executables because they generally call functions and use variables defined only in Camlp5 core, typically belonging to the module "Pcaml". The kits are designed to be loaded by the Camlp5 commands, either through their command arguments or through directives in the source files.

It is therefore important to compile the kits with the option "-c" of the OCaml compiler (i.e. just compilation, not producing an executable) and with the option "-I +camlp5" (or "-I `camlp5 -where`") to inform the compiler to find module interfaces in installed Camlp5 library.

In the OCaml toplevel, it is possible to use a kit by simply loading it with the directive "#load".

Extending syntax

A syntax extension is a Camlp5 parsing kit. There are two ways to use a syntax extension:

Several syntax extensions can be used for a single file. The way to create one's own syntax extensions is explained in this document.

Pretty printing

As for syntax extensions, the pretty printing is defined or extended through Camlp5 printing kits. Some pretty printing kits are provided by Camlp5, the main ones being:

Examples: if we have a file, foo.ml, written in normal syntax and and another one, bar.ml, written in revised syntax, here are the commands to pretty print them in their own syntax:

  camlp5o pr_o.cmo foo.ml
  camlp5r pr_r.cmo bar.ml

And how to convert them into the other syntax:

  camlp5o pr_r.cmo foo.ml
  camlp5r pr_o.cmo foo.ml

The way to create one's own pretty printing extensions is explained in this document.

Note: the revised syntax

The revised syntax is a specific syntax whose aim is to resolve some problems and inconsistencies of the normal OCaml syntax. A chapter will explain the differences between the normal and the revised syntax.

All examples of this documentation are written in that revised syntax. Even if you don't know it, it is not difficult to understand. The same examples can be written in normal syntax. In case of problems, refer to the chapter describing it.

camlp5-6.14/doc/htmlp/htmlp2html0000775000175000017500000000315312556457206015605 0ustar rogloroglo#!/bin/sh # htmlp2html,v FILE=$1 VERSION="$(grep "value version =" ../../main/pcaml.ml | sed -e 's/^[^"]*"\([^"]*\).*$/\1/')" ( echo '
' echo '
    ' grep '' $FILE | sed -e 's|^

    \(.*\)

    |b2\1e2|' | sed -e 's|^

    \(.*\)

    |b3\1e3|' | sed -e '{:b N; s/\n//; tb}' | sed -e 's/e2b3/\n
      \n
    • /g' | sed -e 's|e3b2|
    • \n
    \n \n
  1. |g' | sed -e 's|e2b2|
  2. \n
  3. |g' | sed -e 's|e2|
  4. |g' | sed -e 's/b2/
  5. /g' | sed -e 's|e3b3|
  6. \n
  7. |g' | sed -e 's|e3|
  8. \n \n |g' echo '
' echo '
' ) > toc.tmp cat $FILE | sed \ -e '/title="Normal"/a \ ' | sed \ -e '/