tags:

views:

68

answers:

3

I've taken the following code from http://www.ocaml-tutorial.org/data_types_and_matching

I've been trying to write a C stub for following, to invoke from our PHP codebase. I can't quite understand how (and if) I'm supposed to create a typedef for the following Ocaml type expr, and how I can access the function multiply_out from the C stub?

I'm a newbie to Ocaml and we're evaluating it to see if it'll be useful to us in creating a small grammar for our math web app.

type expr = Plus of expr * expr        (* means a + b *)
          | Minus of expr * expr       (* means a - b *)
          | Times of expr * expr       (* means a * b *)
          | Divide of expr * expr      (* means a / b *)
          | Value of string            (* "x", "y", "n", etc. *)
          ;;

let rec multiply_out e =
  match e with
    Times (e1, Plus (e2, e3)) ->
      Plus (Times (multiply_out e1, multiply_out e2),
            Times (multiply_out e1, multiply_out e3))
  | Times (Plus (e1, e2), e3) ->
      Plus (Times (multiply_out e1, multiply_out e3),
            Times (multiply_out e2, multiply_out e3))
  | Plus (left, right) -> Plus (multiply_out left, multiply_out right)
  | Minus (left, right) -> Minus (multiply_out left, multiply_out right)
  | Times (left, right) -> Times (multiply_out left, multiply_out right)
  | Divide (left, right) -> Divide (multiply_out left, multiply_out right)
  | Value v -> Value v
  ;;

Any suggestions will be a big help! Thanks!

A: 

A list of links:

Interfacing C with OCaml

Stub code generator.

SWIG can connect almost anything to anything.

Modules and the C interface.

Amigable Clark Kant
Thanks Clark, for replying. Couple follow up Qs. I've gone thru the 1st link (and http://www.mega-nerd.com/erikd/Blog/CodeHacking/Ocaml/calling_ocaml.html), to see how Ocaml can be invoked from C. Works for simple types. Can't get documentation for a type like "expr". Will camlidl work for us? We want to invoke Ocaml from C on a UNIX platform. I'm assuming SWIG will come in later, PHP invoking C, rather than in helping C invoke Ocaml, is that right?
Sid
@Sid, I have no idea really, I don't know Ocaml. Maybe you can fire up Ocaml in a separate process and talk through sockets or pipes? Not an answer but an idea...
Amigable Clark Kant
The following link is a great resource on all types of situations for interfacing C and Ocaml; http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php
nlucaroni
@nlucaroni - Thank you for the link, I hadn't seen this one, it truly is helpful. I'm still slightly stuck, reverse engineering Niki's reply below, to carve and send a "Minus (e1, e2)" in C and send to Ocaml, can't figure out what's the substitute for Val_tag, if there is a Tag_val, I was assuming they'd be a Val_tag. Thanks!
Sid
A: 

Can't get documentation for a type like "expr".

Manual states this clearly and provides an example :

Non-constant constructors declared with a n-tuple as argument are represented by a block of size n, tagged with the constructor number; the n fields contain the components of its tuple argument.

E.g. Minus (e1,e2) will be represented as block of size 2 with tag 1.

ygrek
Thank you! Would you suggest creating a string for "Minus (e1, e2)" in C and using Ocamllex/Ocamlyacc to pattern match for "expr" type in Ocaml? Is there a better way to proceed?
Sid
+3  A: 

The manual is a bit terse but this is covered in the manual. The O'Reilly book is a little better: Representation of structured values. Here is a stub for your type:

int tag = Tag_val(v);
const char *lookup[4] = {"plus", "minus", "times", "divide"};
if(tag == 5) // Value
{
  char *val = String_val(Field(v, 0));
}
else
{
  value expr1 = Field(v, 0);
  value expr2 = Field(v, 1);
  const char *operation = lookup[tag-1];
}

To build an OCaml value in C check out Creating and Modifying OCaml values. Here's an example:

#define MINUS 2
#define VALUE 5
value two, five, minus;
CAMLlocal3(two, five, minus);
five = alloc(1, VALUE);
two = alloc(1, VALUE);
Store_field(copy_string("5"), 0, five);
Store_field(copy_string("2"), 0, two);
minus = alloc(2, MINUS); // allocate a block that contains two "words", tagged 2 (MINUX)
Store_field(minus, 0, five); // store five in the zeroith field of minus
Store_field(minus, 1, two); // store two in the first field of minus
CAMLreturn(minus);
Niki Yoshiuchi
I thoroughly appreciate your effort Niki. Where I'm stuck is I still can't understand how I'm supposed to write say "Minus (e1, e2)" in C and send it to Ocaml for processing. I understand I can use the above code, you've written, to read the response, but I'm stuck figuring out how to carve the C -> Ocaml input.
Sid
@Sid - check my edit. Basically you use a combination of `alloc` and `Store_field`.
Niki Yoshiuchi
+1 for coming back and editing.
Amigable Clark Kant
@Niki Thank you for the new response. It makes sense. I'm struggling with a seg fault now, but your answers have cleared my initial doubts. Thank you again.
Sid
@Sid - check my new edit. I forgot about dealing with the garbage collector. You need to tell OCaml that you are allocating memory with the `CAMLlocal#` and then use `CAMLreturn`. That is probably what is causing your segfault.
Niki Yoshiuchi
Aren't OCaml tag values allocated from 0? So `MINUS` should be 1, and `VALUE` 4. http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc138
Michael E
Looks like you are right, I thought tag 0 was reserved for tuples.
Niki Yoshiuchi
Wow! @Niki @Michael, thanks for taking the trouble, it would've taken me a long time to figure this myself. Thank you.
Sid