Chicken » Embedding

## Embedding

Compiled Scheme files can be linked with C code, provided the Scheme code was compiled in embedded mode by passing `-DC_EMBEDDED` to the C compiler (this will disable generation of a `main()` function). `csc` will do this, when given the `-embedded` option.

The following C API is available:

### CHICKEN_parse_command_line

    [C function] void CHICKEN_parse_command_line (int argc, char *argv[], int *heap, int *stack int *symbols)

Parse the programs command-line contained in `argc` and `argv` and return the heap-, stack- and symbol table limits given by runtime options of the form `-:...`, or choose default limits. The library procedure `argv` can access the command-line only if this function has been called by the containing application.

### CHICKEN_initialize

    [C function] int CHICKEN_initialize (int heap, int stack, int symbols, void *toplevel)

Initializes the Scheme execution context and memory. `heap` holds the number of bytes that are to be allocated for the secondary heap. `stack` holds the number of bytes for the primary heap. `symbols` contains the size of the symbol table. The keyword table will be 1/4th the symbol table size. Passing `0` to one or more of these parameters will select a default size.

`toplevel` should be a pointer to the toplevel entry point procedure. You should pass `C_toplevel` here. In any subsequent call to `CHICKEN_run` you can simply pass `NULL`. Calling this function more than once has no effect. If enough memory is available and initialization was successful, then `1` is returned, otherwise this function returns `0`.

It is essential to run `CHICKEN_initialize` and subsequent calls to `CHICKEN_run` in the same native thread. The former computes a stack limit address which will not be valid if the runtime system is re-entered in a execution context where the stack is located at a different address.

### CHICKEN_run

    [C function] C_word CHICKEN_run (void *toplevel)

Starts the Scheme program. Call this function once to execute all toplevel expressions in your compiled Scheme program. If the runtime system was not initialized before, then `CHICKEN_initialize` is called with default sizes. `toplevel` is the toplevel entry-point procedure, you usually pass `C_toplevel` here. The result value is the continuation that can be used to re-invoke the Scheme code from the point after it called `return-to-host`.

If you just need a Scheme interpreter, you can also pass `CHICKEN_default_toplevel` as the toplevel procedure, which just uses the default library units.

Once `CHICKEN_run` has been called, Scheme code is executing until all toplevel expressions have been evaluated or until `return-to-host` is called inside the Scheme program.

### CHICKEN_eval

    [C macro] int CHICKEN_eval (C_word exp, C_word *result)

Evaluates the Scheme object passed in `exp`, writing the result value to `result`. The return value is 1 if the operation succeeded, or 0 if an error occurred. Call `CHICKEN_get_error_message` to obtain a description of the error.

### CHICKEN_eval_string

    [C macro] int CHICKEN_eval_string (char *str, C_word *result)

Evaluates the Scheme expression passed in the string `str`, writing the result value to `result`.

### CHICKEN_eval_to_string

    [C macro] int CHICKEN_eval_to_string (C_word exp, char *result, int size)

Evaluates the Scheme expression passed in `exp`, writing a textual representation of the result into `result`. `size` should specify the maximal size of the result string.

### CHICKEN_eval_string_to_string

    [C macro] int CHICKEN_eval_string_to_string (char *str, char *result, int size)

Evaluates the Scheme expression passed in the string `str`, writing a textual representation of the result into `result`. `size` should specify the maximal size of the result string.

### CHICKEN_apply

    [C macro] int CHICKEN_apply (C_word func, C_word args, C_word *result)

Applies the procedure passed in `func` to the list of arguments `args`, writing the result value to `result`.

### CHICKEN_apply_to_string

    [C macro] int CHICKEN_apply_to_string (C_word func, C_word args, char *result, int size)

Applies the procedure passed in `func` to the list of arguments `args`, writing a textual representation of the result into `result`.

### CHICKEN_read

    [C macro] int CHICKEN_read (char *str, C_word *result)

Reads a Scheme object from the string `str`, writing the result value to `result`.

### CHICKEN_load

    [C macro] int CHICKEN_load (char *filename)

Loads the Scheme file `filename` (either in source form or compiled).

### CHICKEN_get_error_message

    [C macro] void CHICKEN_get_error_message (char *result, int size)

Returns a textual description of the most recent error that occurred in executing embedded Scheme code.

### CHICKEN_yield

    [C macro] int CHICKEN_yield (int *status)

If threads have been spawned during earlier invocations of embedded Scheme code, then this function will run the next scheduled thread for one complete time-slice. This is useful, for example, inside an idle handler in a GUI application with background Scheme threads.

An example:

    % cat x.scm
    ;;; x.scm
    (import (chicken platform) (chicken foreign))

    (define (bar x) (gc) (* x x))

    (define-external (baz (int i)) double
      (sqrt i))
    (return-to-host)

    % cat y.c
    /* y.c */

    #include <chicken.h>
    #include <assert.h>

    extern double baz(int);

    int main() {
      char buffer[ 256 ];
      int status;
      C_word val = C_SCHEME_UNDEFINED;
      C_word *data[ 1 ];

      data[ 0 ] = &val;

      CHICKEN_run(C_toplevel);

      status = CHICKEN_read("(bar 99)", &val);
      assert(status);

      C_gc_protect(data, 1);

      printf("data: %08x\n", val);

      status = CHICKEN_eval_string_to_string("(bar)", buffer, 255);
      assert(!status);

      CHICKEN_get_error_message(buffer, 255);
      printf("ouch: %s\n", buffer);

      status = CHICKEN_eval_string_to_string("(bar 23)", buffer, 255);
      assert(status);

      printf("-> %s\n", buffer);
      printf("data: %08x\n", val);

      status = CHICKEN_eval_to_string(val, buffer, 255);
      assert(status);
      printf("-> %s\n", buffer);

      printf("->` %g\n", baz(22));

      return 0;
    }

    % csc x.scm y.c -embedded

It is also possible to re-enter the computation following the call to `return-to-host` by calling `CHICKEN_continue`:

### CHICKEN_continue

    [C function] C_word CHICKEN_continue (C_word k)

Re-enters Scheme execution. `k` is the continuation received from the previous invocation of `CHICKEN_run` or `CHICKEN_continue`. When `return-to-host` is called again, this function returns another continuation that can be used to restart again.

If you invoke callbacks prior to calling `CHICKEN_continue`, make sure that the continuation is not reclaimed by garbage collection. This can be avoided by using `C_gc_protect` or gc-roots.

Another example:

    % cat x.scm
    (import (chicken platform) srfi-18) ;; Needs the srfi-18 egg

    (define m (make-mutex))

    (define (t)
      (mutex-lock! m)
      (thread-sleep! 1)
      (print (thread-name (current-thread)))
      (mutex-unlock! m)
      (t) )

    (thread-start! (make-thread t 'PING!))
    (thread-start! (make-thread t 'PONG!))

    (let loop ()
      (return-to-host)
      (thread-yield!)
      (loop) )

    % cat y.c
    #include <chicken.h>

    int main()
    {
      C_word k = CHICKEN_run(C_toplevel);

      for(;;)
        k = CHICKEN_continue(k);

      return 0;
    }

    % csc x.scm y.c -embedded

It is advisable not to mix repeated uses of `CHICKEN_continue`/`return-to-host` (as in the example above) with callbacks. Once `return-to-host` is invoked, the runtime system and any Scheme code executed prior to the invocation is initialized and can be conveniently used via callbacks.

A simpler interface For handling GC-safe references to Scheme data are the so called gc-roots:

### CHICKEN_new_gc_root

    [C function] void* CHICKEN_new_gc_root ()

Returns a pointer to a GC root, which is an object that holds a reference to a Scheme value that will always be valid, even after a garbage collection. The content of the gc root is initialized to an unspecified value.

### CHICKEN_new_finalizable_gc_root

    [C function] void* CHICKEN_new_finalizable_gc_root ()

Similar to `CHICKEN_new_gc_root`, but allows the stored value to be finalized: if this gc root holds reference to an otherwise unreferenced data object that has a finalizer, the finalizer is still invoked.

### CHICKEN_delete_gc_root

    [C function] void CHICKEN_delete_gc_root (void *root)

Deletes the gc root.

### CHICKEN_gc_root_ref

    [C macro] C_word CHICKEN_gc_root_ref (void *root)

Returns the value stored in the gc root.

### CHICKEN_gc_root_set

    [C macro] void CHICKEN_gc_root_set (void *root, C_word value)

Sets the content of the GC root to a new value.

Sometimes it is handy to access global variables from C code:

### CHICKEN_global_lookup

    [C function] void* CHICKEN_global_lookup (char *name)

Returns a GC root that holds the global variable with the name `name`. If no such variable exists, `NULL` is returned.

### CHICKEN_global_ref

    [C function] C_word CHICKEN_global_ref (void *global)

Returns the value of the global variable referenced by the GC root `global`.

### CHICKEN_global_set

    [C function] void CHICKEN_global_set (void *global, C_word value)

Sets the value of the global variable referenced by the GC root `global` to `value`.

Previous: Foreign type specifiers

Next: C interface