Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ lisp
*.stackdump
temp/
printer
sample


# Xcode
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ CFLAGS = -Wall -pedantic -Wstrict-prototypes -O3
LDLIBS = -lm
CC=cc

all: lisp printer
all: lisp printer sample

lisp: repl.c lisp.h
${CC} repl.c -o $@ ${CFLAGS} ${LDLIBS}

printer: printer.c lisp.h
${CC} printer.c -o $@ ${CFLAGS} ${LDLIBS}

sample: sample.c lisp.h
${CC} sample.c -o $@ ${CFLAGS} ${LDLIBS}
83 changes: 38 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,34 +50,28 @@ I created this while reading [SICP](https://github.com/justinmeiners/sicp-excerc

### Interactive programming with Read, eval, print loop.
```bash
$ ./lisp_i
$ ./lisp
> (define (sqr x) (* x x)))
> (define length 40)
> (define area 0)
> (set! area (sqr length))
1600
```

### Embedding in a program
### Quickstart

```c
LispContext ctx = lisp_init();
lisp_load_lib(ctx);

// load lisp program (add 1 and 2)
LispError error;
Lisp program = lisp_read("(+ 1 2)", &error, ctx);

// execute program using global environment
Lisp result = lisp_eval(program, &error, ctx);

// prints 3
lisp_print(result);
if (error != LISP_ERROR_NONE)
lisp_print(result); ; => 3

// you are responsible for garbage collection
lisp_collect(ctx, env);
// ...
// shutdown also garbage collects
lisp_shutdown(ctx, env);
lisp_shutdown(ctx);
```

### Loading Data
Expand All @@ -103,12 +97,11 @@ Lisp
Loading the structure in C.

```c
// setup lisp without any library
LispContext ctx = lisp_init_empty();
LispContext ctx = lisp_init();
// load lisp structure
Lisp data = lisp_read_file(file, ctx);
// get value for age
Lisp age = lisp_vector_for_key(data, lisp_make_symbol("AGE", ctx), ctx);
Lisp age = lisp_list_assoc(data, lisp_make_symbol("AGE", ctx), ctx);
// ...
lisp_shutdown(ctx);
```
Expand All @@ -118,51 +111,49 @@ lisp_shutdown(ctx);
C functions can be used to extend the interpreter, or call into C code.

```c
Lisp sum_of_squares(Lisp args, LispError* e, LispContext ctx)
Lisp integer_range(Lisp args, LispError* e, LispContext ctx)
{
// first argument
Lisp accum = lisp_car(args);
// remaining arguments
Lisp rest = lisp_cdr(args);
LispInt start = lisp_int(lisp_car(args));
args = lisp_cdr(args);
// second argument
LispInt end = lisp_int(lisp_car(args));

// iterate over the rest of the arguments
while (!lisp_is_null(rest))
if (end < start)
{
Lisp val = lisp_car(rest);

// make this work for integers and floats
if (lisp_type(accum) == LISP_INT)
{
accum.int_val += lisp_int(val) * lisp_int(val);
}
else if (lisp_type(accum) == LISP_FLOAT)
{
accum.float_val += lisp_float(val) * lisp_float(val);
}

rest = lisp_cdr(rest);
*e = LISP_ERROR_OUT_OF_BOUNDS;
return lisp_make_null();
}

return accum;
LispInt n = end - start;
Lisp numbers = lisp_make_vector(n, ctx);

for (LispInt i = 0; i < n; ++i)
lisp_vector_set(numbers, i, lisp_make_int(start + i));

return numbers;
}

// ...

// wrap in Lisp object
Lisp func = lisp_make_func(sum_of_squares);
Lisp func = lisp_make_func(integers_in_range);

// add to enviornment with symbol SUM-OF-SQUARES
lisp_env_set(env, lisp_make_symbol("SUM-OF-SQAURES", ctx), func, ctx);
// add to enviornment with symbol INTEGER-RANGE
Lisp env = lisp_env_global(ctx);
lisp_env_define(env, lisp_make_symbol("INTEGER-RANGE", ctx), func, ctx);
```

In Lisp
```scheme
(sum-of-squares 1 2 3)
; returns 1 + 4 + 9 = 14
(INTEGER-RANGE 5 15)
; => #(5 6 7 8 9 10 11 12 13 14)
```
Constants can also be stored in the environment in a similar fashion.

```c
Lisp pi = lisp_make_real(3.1415);
lisp_env_set(env, lisp_make_symbol("PI", ctx), pi, ctx);
Lisp pi = lisp_make_real(3.141592);
lisp_env_define(env, lisp_make_symbol("PI", ctx), pi, ctx);
```
## Macros

Expand All @@ -173,7 +164,8 @@ Common Lisp style (`defmacro`) is available with the name `define-macro`.

## Garbage Collection

Unlike most languages, the garbage collector is not called automatically. You must call it yourself in C:
Garbage is only collected if it is explicitly told to.
You can invoke the garbage collector in C:

lisp_collect(ctx);

Expand All @@ -185,8 +177,9 @@ Note that whenever a collect is issued
ANY `Lisp` value which is not accessible
through the global environment may become invalid.
Be careful what variables you hold onto in C.
Most C functions which are callable from Lisp
don't have a problem as `eval` cannot be called within them.

Don't call `eval` in a custom defined C function unless
you know what you are doing.

See [internals](INTERNALS.md) for more details.

Expand Down
Loading