From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: weis Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id RAA12129 for caml-redistribution; Mon, 3 Jan 2000 17:47:44 +0100 (MET) Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id KAA24332 for ; Mon, 3 Jan 2000 10:46:57 +0100 (MET) Received: from miss.wu-wien.ac.at (miss.wu-wien.ac.at [137.208.107.17]) by nez-perce.inria.fr (8.8.7/8.8.7) with ESMTP id KAA17979 for ; Mon, 3 Jan 2000 10:46:56 +0100 (MET) Received: (from mottl@localhost) by miss.wu-wien.ac.at (8.9.0/8.9.0) id KAA03180; Mon, 3 Jan 2000 10:46:34 +0100 (MET) From: Markus Mottl Message-Id: <200001030946.KAA03180@miss.wu-wien.ac.at> Subject: Re: ocamlyacc/lex reentrancy To: skaller@maxtal.com.au (skaller) Date: Mon, 3 Jan 2000 10:46:34 +0100 (MET) Cc: caml-list@inria.fr (OCAML) In-Reply-To: <386BADF3.80F07395@maxtal.com.au> from "skaller" at Dec 31, 99 06:09:39 am X-Mailer: ELM [version 2.4 PL21] MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Sender: weis > > 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 | Nil -> fl1.head <- fl2.head; fl1.tail <- fl2.tail | 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 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