t3x.org / sketchy / sk07.html
SketchyLISP
Reference
  Copyright (C) 2007
Nils M Holm

7 Interpreter API

7.1 Embedding the Interpreter

The SketchyLISP interpreter consists of two parts: the sketchy.h header file and the library. The header contains

The library contains the interpreter itself. To compile a C program that interfaces SketchyLISP, use the following invocation:

cc program.c -lsketchy

You might have to add -Iincdir and -Llibdir options, if the header or library are located in non-standard places.

A minimal program embedding the SketchyLISP interpreter follows. The program implements a complete interpreter shell. The only differences to the `real' SketchyLISP shell are that this simple application does not implement meta commands, batch mode, signal handling, or command line options.

#include <stdio.h>
#include <sketchy.h>

void main(void) {
    int n;

    if (sk_init(SK_DFL_NODES, SK_DFL_VCELLS)) {
        fprintf(stderr, "sk_init failed\n");
        exit(1);
    }
    if (sk_loadImage(SK_DFL_IMAGE)) {
        fprintf(stderr, "sk_loadImage failed\n");
        exit(1);
    }
    while (1) {
        SK_errFlag = 0;
        n = sk_read();
        if (n == sk_eof()) break;
        n = sk_eval(n);
        if (SK_errFlag) {
            sk_printError();
        }
        else {
            sk_pr("=> ");
            sk_print(n);
            sk_nl();
        }
    }
    sk_bye();
}

The functions, variables, and constants used in this program will be explained in detail in the following sections.

7.2 Initialization and Shutdown Functions

7.2.1 sk_bye

void sk_bye(void);

Shut down SketchyLISP and terminate the calling program using exit(0).

7.2.2 sk_fini

void sk_fini(void);

Release the memory pools allocated by sk_init().

7.2.3 sk_init

int sk_init(int nodes, int vcells);

Initialize the interpreter and allocate the memory pools. Return a value indicating success (0) or failure (<0). The arguments nodes and vcells indicate the numbers of nodes and vector cells to allocate. To allocate a default number of resources, use

sk_init(SK_DFL_NODES, SK_DFL_VCELLS);

Neither the number of nodes nor the number of vcells may be less than SK_MIN_SIZE.

The release date of the interpreter can be found in the constant SK_RELEASE and the major version number in SK_MAJOR. The release date has the format "yyyy-mm-dd", the version number is an integer.

7.3 Evaluation Functions

7.3.1 sk_eval

int sk_eval(int n);

Evaluate the SketchyLISP node n and return a node representing the normal form of n. This function sets SK_errFlag in case of an error. In this case, the return value of sk_eval() is undefined.

Sk_eval() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_eval() is unprotected.

7.4 Error Handling Functions

7.4.1 sk_gotError

void sk_gotError(void);

Signal the interpreter that the most recent error has been handled. Either this routine or sk_printError must be called after detecting an error condition. Otherwise the interpreter will not evaluate any further expressions.

7.4.2 sk_printCallTrace

void sk_printCallTrace(int frame);

Print a trace of those 10 functions that were most recently called.

7.4.3 sk_printError

void sk_printError(void);

Print an error message and reset the error condition by calling sk_gotError(). If the error flag (SK_errFlag) is clear upon entry, sk_printError() does not print any message. If it does print a message, it has the following form:

* file: line: function: message: expr
* additional information

File is the file containing the source of the error. It is taken from the variable SK_errFile. If this variable is NULL, the file part is omitted.

Line is the line number of the expression that has caused the error. It is equal to the value of SK_errLine.

Function is the name of the function in which the error occured. It is taken from the node SK_errFun. If this node is NIL, sk_printError() prints REPL instead.

Message is the error message itself (SK_errMsg).

Expr is the expression that caused the error. It is taken from the node SK_errExpr. If SK_errExpr is equal to the constant SK_NOEXPR, the error was not caused by any specific expression.

The additional information part is equal to the SK_errArg variable. It prints only, if this variable is not NULL.

If the SK_errFrame variable is not NIL, sk_printError() also prints a call trace using sk_printCallTrace().

7.4.4 sk_stop

void sk_stop(void);

Stop the interpreter by issuing an error. The error message delivered to the interpreter is "interrupted". After stopping the interpreter using sk_stop(), the error condition must be reset by issuing sk_printError() or sk_gotError().

sk_stop() is typically called by a signal handler. The following code fragment would handle keyboard interrupts (SIGINT) under Unix:

#include <signal.h>

void catchIntr(int sig) {
	sk_stop();
}

void main(void) {
	signal(SIGINT, catchIntr);
	/*
	 * Place your SketchyLISP interface here.
	 */
}

7.5 Access Functions

7.5.1 sk_car

int sk_car(int n);

Extract the car part of the node n.

7.5.2 sk_cdr

int sk_cdr(int n);

Extract the cdr part of the node n.

7.5.3 sk_eof

int sk_eof(void);

Return the EOF object. Comparing a node with the EOF object resembles the eof-object? primitive:

int eof_object(int n) { return n == sk_eof(); }

7.5.4 sk_false

int sk_false(void);

Return the node representing logical falsity (aka #f).

7.5.6 sk_int

long sk_int(int n, int *ep);

Return the value of the big integer node n. If n is not the root of an integer node or the value of the node is too big to fit in a long int, return 0 and set ep[0] to a non-zero value.

The caller must set ep[0] to zero before calling sk_int().

7.5.7 sk_nil

const int sk_nil(void);

Return the node representing the empty list (aka NIL).

7.5.8 sk_string

const char *sk_string(int n);

Return the value of the string node n. If n is not the root of an string node, return NULL.

7.5.9 sk_true

int sk_true(void);

Return the node representing logical truth (aka #t).

7.5.10 sk_undefined

int sk_undefined(void);

Return the node representing an undefined value. A variable that is bound to sk_undefined() is indeed undefined. Reducing such a variable will yield bottom.

7.5.11 sk_vector

const int *sk_vector(int n);

Return a pointer to an array of int. Each member of that array represents one member of the vector n. Use sk_vector_len() to find the size of the returned array.

7.5.12 sk_vector_len

int sk_vector_len(int n);

Return the number of members of the vector n.

7.5.13 sk_void

int sk_void(void);

Return the node representing an unspecific value (aka #<void>).

7.5.14 sk_writeToString

int sk_writeToString(int n);

Write the external representation of the node n to a string object and return it. Use the sk_string() function to access the text of the string returned by sk_writeToString().

Sk_writeToString() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_writeToString() is unprotected.

7.6 Input/Output Functions

7.6.1 sk_display

void sk_display(int n);

Display the SketchyLISP node n using the display primitive.

7.6.2 sk_load

int sk_load(char *p);

Load a source file by temporarily redirecting the input stream to the file p. Return a value indicating success (0) or failure (<0). Failure occurs, if the source file could not be opened or contains an erroneous expression. In the latter case, some definitions contained in the file may have loaded sucessfully.

Sk_load() can trigger a garbage collection. See sk_protect() for details.

7.6.3 sk_nl

void sk_nl(void);

Write a newline sequence to the output stream.

7.6.4 sk_pr

void sk_pr(char *s);

Write the string s to the output stream.

7.6.5 sk_print

void sk_print(int n);

Write the external representation of the SketchyLISP node n to the output stream.

7.6.6 sk_prnum

void sk_prnum(int n, int w);

Print the number n. If n has less than w digits, pad the output to w characters using blanks. W may not be larger than 7.

7.6.7 sk_rdch

int sk_rdch(void);

Read a single raw character from the input stream of the interpreter and return it. When the input stream is exhausted, return SK_EOT.

The character may be put back to the input stream using sk_reject().

7.6.8 sk_read

int sk_read(void);

Read a Scheme datum from the input stream and convert it to internal representation. Return a SketchyLISP node representing the internal form. This function resembles the read primitive.

Sk_read() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_read() is unprotected.

7.6.9 sk_reject

int sk_reject(int c);

Put the character c back to the input stream. The next character read by the interpreter (or by sk_rdch()) will be exactly this character.

Only one single character may be rejected. Rejecting multiple characters before reading them will result in the loss of all but the most recently rejected character.

7.6.10 sk_require

void sk_require(char *p);

Load the content of the file p using sk_load, but only if the basename of p is not bound in the interpreter. The basename of a path is the element between the last slash (if any) and the first dot (if any):

/this/is/some/path/basename.scm

Sk_require() can trigger a garbage collection. See sk_protect() for details.

7.7 Metric Functions

7.7.1 sk_count

void sk_count(struct sk_counter *c, int k);

Increment the counter c by some small amount k (k may not be larger than 1000). If the counter overflows, an error condition occurs. The counter structure is defined as follows:

struct sk_counter {
    int n,      /* ones */
        n1k,    /* thousands */
        n1m,    /* millions */
        n1g;    /* billions */
};

7.7.2 sk_printCounter

void sk_printCounter(struct sk_counter *c);

Write the value of a counter to the output stream. For a definition of the sk_counter structure, see sk_count(). The counter value is printed in groups of three digits separated by commas, like this:

1,234,567

7.7.3 sk_printStats

void sk_printStats(void);

Print some statistics of the form

nr reduction steps
nn nodes allocated
ng garbage collections

where nr = SK_reductions,
nn = SK_allocations,
and ng = SK_collections.

All the statistics variables are of the type sk_counter. For its definition, see sk_count(). Individual values are printed using sk_printCounter().

7.7.4 sk_resetCounter

int sk_resetCounter(struct sk_counter *c);

Reset the counter c to zero. For a definition of the sk_counter structure, see sk_count().

7.8 User Procedure Functions

7.8.1 sk_addUserPrim

int sk_addUserPrim(char *name, int (*handler)(int n));

Register a handler for a user procedure. Name names the procedure and handler is the function handling calls to that procedure.

The following foo() handler implements a user procedure that divides an integer by two:

int foo(int n) {
	int	m;
	int	e;
	long	v;

	if (sk_args(n) != 1)
		return sk_error("foo: wrong number of args", n);
	m = sk_nthArg(n, 0);
	if (sk_typeof(m) != SK_TYPE_INTEGER)
		return sk_error("foo: not an integer", m);
	e = 0;
	v = sk_int(m, &e);
	if (e) return sk_error("foo: value too big", m);
	return sk_mkInteger(v/2);
}

The following call to sk_addUserPrim registers the procedure:

sk_addUserPrim("foo", foo);

After registering the procedure, it can be called by SketchyLISP programs in the same way as primitive functions and lambda functions:

(foo 123) => 61

Sk_addUserPrim() can trigger a garbage collection. See sk_protect() for details.

7.8.2 sk_args

int sk_args(int n);

Return the number of actual arguments passed to a user procedure.

N is the node received by the function implementing the procedure.

7.8.3 sk_error

int sk_error(char *msg, int n);

Report an error that occurred in a user procedure. Msg is the error message and n is the expression or part of the the expression that caused the error.

7.8.4 sk_nthArg

int sk_nthArg(int n, int i);

Return a node representing the i'th actual argument passed to a user procedure.

N is the node received by the function implementing the procedure.

7.8.5 sk_protect

void sk_protect(int n);

Protect the node n during garbage collections. Protected nodes will never be reclaimed.

Protected nodes must be released using sk_unprotect() before returning from a user procedure.

7.8.6 sk_typeof

int sk_typeof(int n);

Return the type of the node n.

Types are encoded using the following constants:

SK_TYPE_BOOLEAN
SK_TYPE_CHAR
SK_TYPE_EOF
SK_TYPE_INTEGER
SK_TYPE_PAIR
SK_TYPE_PROCEDURE
SK_TYPE_STRING
SK_TYPE_SYMBOL
SK_TYPE_SYNTAX
SK_TYPE_VOID

7.8.7 sk_unprotect

void sk_unprotect(int k);

Unprotect the most recently protected nodes. K is the number of nodes to unprotect.

7.9 Construction Functions

7.9.1 sk_cons

int sk_cons(int car, int cdr);

Create a fresh node with car=car and cdr=cdr. Car and cdr are nodes.

Sk_cons() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_cons() is unprotected.

7.9.2 sk_listToVector

int sk_listToVector(int n);

Convert the list n to a vector and return its node.

Sk_listToVector() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_listToVector() is unprotected.

7.9.3 sk_mkChar

int sk_mkChar(int c);

Create a fresh char node representing the character c.

Sk_mkChar() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_mkChar() is unprotected.

7.9.4 sk_mkInteger

int sk_mkInteger(long v);

Create a fresh integer node representing the value v.

Sk_mkInteger() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_mkInteger() is unprotected.

7.9.5 sk_mkString

int sk_mkString(char *s, int k);

Create a fresh string node representing the value s. K must specify the number of characters in the string s (excluding the delimiting NUL).

Sk_mkString() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_mkString() is unprotected.

7.9.6 sk_readFromString

int sk_readFromString(char *s);

Read the string s in the same way as the read-from-string primitive and return a node pointing to the internal representation of a singleton list containing the form read.

In case s does not contain a well-formed expression, return sk_false().

Sk_readFromString() can trigger a garbage collection. See sk_protect() for details.

The node returned by sk_readFromString() is unprotected.

7.9.7 sk_setCar

int sk_setCar(int n, int new);

Set the car part of the node n to new. N must be a pair node, new may be a node of any type.

7.9.8 sk_setCdr

int sk_setCdr(int n, int new);

Set the cdr part of the node n to new. N must be a pair node, new may be a node of any type.

7.10 Miscellaneous Functions

7.10.1 sk_dumpImage

void sk_dumpImage(char *p);

Dump the workspace of the interpreter to the file p. This function sets SK_errFlag in case of an error.

7.10.2 sk_dumpSymbols

void sk_dumpSymbols(char *p);

Write a list of packages and the symbols of the package p to the output stream.

7.10.3 sk_findSource

void sk_findSource(char *p, char *buf);

Attempt to locate the file p in "." and in all directories specified in the SKETCHYSRC emvironment variable. If the file has no suffix try both the file name and the file name with ".scm" appended. Return the full path of the file upon success and NULL in case the file could not be located.

The buf array must be at least SK_MAXPATHL characters long.

sk_findSource() is used by require to locate source files.

7.10.4 sk_gc

void sk_gc(struct sk_gcStats *stats);

Perform a garbage collection and fill the stats data structure with some statistics. stats is defined as follows:

struct sk_gcStats {
    int nodes_used,
        vcells_used,
        nodes_max,
        vcells_max;
};

The _used fields are filled with the numbers of nodes and vcells currently used, and the _max fields are filled with peak load of the memory pools since the last call to sk_gc.

sk_gc also resets the peak load indicators.

Sk_gc() will trigger a garbage collection. See sk_protect() for details.

7.10.5 sk_license

char **sk_license(void);

Return a pointer to the conditions of use as an array of strings. Each string contains one line of the license. The last line contains NULL.

7.10.6 sk_loadImage

int sk_loadImage(char *p);

Load a workspace image from the file p. Return a value indicating success (0) or failure (<0). Possible causes for failure are:

Note: After a failed attempt to load an image, the interpreter must be shut down by calling sk_fini() and then re-initialized using sk_init().

7.11 Variables

7.11.1 SK_allocations

extern struct sk_counter SK_allocations;

Allocation counter. See sk_count().

7.11.2 SK_arrowMode

extern int SK_arrowMode;

Set arrow mode. See :arrow-mode meta command.

7.11.3 SK_closureForm

extern int SK_closureForm;

External representation of procedures (0,1,2). See :closure-form meta command.

7.11.4 SK_collections

extern struct sk_counter SK_collections;

Garbage collection counter. See sk_count().

7.11.5 SK_errArg

extern char SK_errArg[SK_TEXTLEN];

Additional error information. See sk_printError().

7.11.6 SK_errExpr

extern int SK_errExpr;

Expression causing last error. See sk_printError().

7.11.7 SK_errFile

extern char SK_errFile[SK_MAXPATHL];

File of last error. See sk_printError().

7.11.8 SK_errFlag

Error flag. See sk_eval(), sk_printError(), and sk_gotError().

extern int SK_errFlag;

7.11.9 SK_errFrame

extern int SK_errFrame;

Call frame of last error. See sk_printError() and sk_printCallTrace().

7.11.10 SK_errFun

extern int SK_errFun;

Function of last error. See sk_printError().

7.11.11 SK_errLine

extern int SK_errLine;

Line number of last error. See sk_printError().

7.11.12 SK_errMsg

extern char *SK_errMsg;

Most recent error message. See sk_printError().

7.11.13 SK_metaChar

extern int SK_metaChar;

Meta command character. Prefix for meta commands. Default: ':'.

7.11.14 SK_reductions

extern struct sk_counter SK_reductions;

Reduction counter. See sk_count().

7.11.15 SK_statFlag

extern int SK_statFlag;

Statistics flag. Start gathering statistics. See sk_printStats() function and :statistics meta command.

7.11.16 SK_strictApply

extern int SK_strictApply;

Strict (R5RS) apply flag. See :r5rs-apply meta command.

7.11.17 SK_trace

extern int SK_trace;

Function being traced. See :trace meta command.

7.11.18 SK_traceHandler

extern int (*SK_traceHandler)(int n);

Pointer to used-defined trace handler. Set to NULL to use the internal trace handler. For now, see the source code (sketchy.c)for further details.

7.12 Constants

7.12.1 SK_DFL_IMAGE

#define SK_DFL_IMAGE "/usr/local/share/sketchy/sketchy.image"

The full path name of the default image.

7.12.2 SK_DFL_NODES

#define SK_DFL_NODES 131072

The default size of the node pool.

7.12.3 SK_DFL_VCELLS

#define SK_DFL_NODES SK_DFL_NODES

The default size of the vector cell pool.

7.12.4 SK_EOT

#define SK_EOT -1

The end of input indicator of the sk_rdch() function. To test for the end of interpreter input, compare against sk_eof().

7.12.5 SK_MAJOR

#define SK_MAJOR 99

The major version number of the current release (probably not 99). Used to identify image files.

7.12.6 SK_MAXPATHL

#define SK_MAXPATHL 256

The maximum length of a path name.

7.12.7 SK_MAX_USER_PRIMITIVES

#define SK_MAX_USER_PRIMITIVES 64

The maximum number of user procedures.

7.12.8 SK_MIN_SIZE

#define SK_MIN_SIZE 12288

The minimum size of the node pool and vector pool.

7.12.9 SK_NOEXPR

#define SK_NOEXPR -1

Pass this constant to sk_error() to indicate that an error is not related to a specific expression.

7.12.10 SK_RELEASE

#define SK_RELEASE "2006-09-23"

The date of the current release.

7.12.11 SK_TEXTLEN

#define SK_TEXTLEN 1024

The maximum size of textual objects like string literals, numeric literals, symbols, etc.