Accueil     À propos     Téléchargement     Ressources     Contactez-nous

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Re: ocamlyacc/lex reentrancy
• Markus Mottl
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
 Date: 2000-01-03 (16:47) From: Markus Mottl Subject: Re: ocamlyacc/lex reentrancy
```> > And, when invoking a lexer function or entry point,  you need to pass the
> > additionnal argument, a in
> >   somerule lexbuf lexdata

There is another way to get a similar behaviour with some syntactic sugar.
Use the following implementation of a "flow" (hm, just invented this name),
which is actually just a queue with some additional operators:

---------------------------------------------------------------------------
type 'a flow = Nil | Cons of 'a * 'a flow ref

type 'a t = { mutable head: 'a flow; mutable tail: 'a flow }

let create () = { head = Nil; tail = Nil }

let add fl x = match fl.tail with
| Nil -> let c = Cons (x, ref Nil) in fl.head <- c; fl.tail <- c
| Cons (_, last_ref) -> let c = Cons (x, ref Nil) in
last_ref := c; fl.tail <- c

let append fl1 fl2 = match fl1.tail with
| Cons (_, last_ref) -> last_ref := fl2.head; fl1.tail <- fl2.tail

let rec iter_aux f = function Nil -> () | Cons (x, t) -> f x; iter_aux f !t
let iter f q = iter_aux f q.head

let (%) fl el = add fl el; fl
let (!%) el = create () % el
let (%@) fl1 fl2 = append fl1 fl2; fl1
---------------------------------------------------------------------------

I use this in ocamlyacc files as follows:

---------------------------------------------------------------------------
%{ open Semantics.Impl
open Flow
%}

... some tokens ...

%start main
%type <Semantics.Impl.cmd Flow.t> main

%%

actions_or_paths
: action_or_path                          { \$1 }
| actions_or_paths useless action_or_path { \$1 %@ \$3 }

action_or_path : path { \$1 } | action { !% \$1 }

action
: POP_PATH         { pop_dir }
| EMPTY_PATH_STACK { clear_dir_stack }
| AT ID            { dir_stack_at \$2 }

path : op_rel_path { \$1 % push_dir } | cl_rel_path { \$1 % top_dir }

op_rel_path
: cl_rel_path SLASH       { \$1 }
| op_el                   { !% (cd \$1) }
| cl_rel_path SLASH op_el { \$1 % (cd \$3) }

cl_rel_path
: cl_el                    { !% (cd \$1) }
| set_el                   { !% (dir_set \$1) }
| cl_rel_path SLASH cl_el  { \$1 % (cd \$3) }
| cl_rel_path SLASH set_el { \$1 % (dir_set \$3) }

---------------------------------------------------------------------------

This should lead to very compact and readable specifications. The result of
parsing is a "flow" (queue) of commands (functions) that transform state.
See below for an interface of Semantics.Impl:

---------------------------------------------------------------------------
...
type state
type cmd = state -> state

val fresh : state
val cd : Dir.Spec.el -> cmd
val cd_root : cmd
val cd_up : cmd
val apply_flow : cmd Flow.t -> cmd
...
---------------------------------------------------------------------------

"apply_flow parse_result fresh" will apply all the state transformations of
the "flow" to a "fresh" state. Here the implementation of this function:

let apply_stream strm s =
let s' = ref s in Flow.iter (fun f -> s' := f !s') strm; !s'

Maybe someone else will also find it useful.

Regards,
Markus Mottl

--
Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl

```