add documentation
This commit is contained in:
parent
cd252f5908
commit
601451e9a9
2
Makefile
2
Makefile
|
@ -12,8 +12,6 @@ keithlisp: $(OBJS)
|
|||
|
||||
$(OBJ_DIR)/%.o: %.c
|
||||
gcc -c -o $@ $^ $(CFLAGS)
|
||||
$(OBJ_DIR):
|
||||
mkdir $(OBJ_DIR)
|
||||
|
||||
.PHONY = clean
|
||||
clean:
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# The Keithlisp Programmer's Reference
|
||||
Keithlisp is a tiny, stripped-down version of Lisp written in C. It's
|
||||
vaguely reminiscent of Common Lisp; however, **Keithlisp does NOT fully
|
||||
adhere to the Common Lisp standard!** Many Common Lisp functions are not
|
||||
present or behave differently in Keithlisp.
|
||||
|
||||
## General Advice
|
||||
- Keithlisp assumes that you, the programmer, know what you are doing.
|
||||
**Many Keithlisp functions will segfault or otherwise misbehave if you
|
||||
do not provide them with the data they expect.**
|
||||
- Keithlisp doesn't properly parse tokens longer than 64 bytes. This
|
||||
includes string literals.
|
||||
- Strings in Keithlisp are sequences of *bytes*. A zero byte does not
|
||||
necessarily correspond to the end of a string.
|
||||
- You can comment out `#define LISP_USE_ATOMS_ALIST` in main.h to remove
|
||||
the atoms_alist. This significantly reduces Keithlisp's memory
|
||||
footprint, but makes it impossible to retrieve the name of an atom.
|
||||
- Keithlisp doesn't automatically garbage-collect return values at the
|
||||
moment, but this may change in the future. If you know whether a
|
||||
function will return a cons/string referenced elsewhere or not, you
|
||||
should insert a garbage collector annotation in your code.
|
||||
|
||||
## Contents
|
||||
- [The Keithlisp Standard Library](stdlib.md)
|
|
@ -0,0 +1,9 @@
|
|||
# The Keithlisp Standard Library
|
||||
Keithlisp's built-in functions are grouped into the following
|
||||
categories:
|
||||
|
||||
- [Special Forms](stdlib_forms.md)
|
||||
- [Arithmetic](stdlib_arithmetic.md)
|
||||
- [Boolean Logic](stdlib_boolean.md)
|
||||
- [Comparison](stdlib_comparison.md)
|
||||
- [Miscellaneous Functions](stdlib_misc.md)
|
|
@ -0,0 +1,41 @@
|
|||
# Arithmetic
|
||||
|
||||
## `+`
|
||||
```
|
||||
(+ &rest numbers)
|
||||
```
|
||||
`+` returns the sum of its arguments, skipping any inputs that are not
|
||||
ints or floats. If no arguments are given, it returns 0.
|
||||
|
||||
## `-`
|
||||
```
|
||||
(- number)
|
||||
(- number &rest more-numbers)
|
||||
```
|
||||
If called with one argument, `-` returns the negation of that argument.
|
||||
If called with more than one argument, `-` subtracts `more-numbers` from
|
||||
`number`, skipping any inputs that are not ints or floats.
|
||||
If `number` is not an int or float, `-` returns nil.
|
||||
|
||||
## `*`
|
||||
```
|
||||
(* &rest numbers)
|
||||
```
|
||||
`*` returns the product of its arguments, skipping any inputs that are
|
||||
not ints or floats. If no arguments are given, it returns 1.
|
||||
|
||||
## `/`
|
||||
```
|
||||
(/ number &rest more-numbers)
|
||||
```
|
||||
`/` divides `number` by `more-numbers`, skipping any inputs that are not
|
||||
ints or floats. It always returns a float.
|
||||
If `number` is not an int or float, `/` returns nil.
|
||||
|
||||
## `int/`
|
||||
```
|
||||
(int/ number &rest more-numbers)
|
||||
```
|
||||
`int/` performs integer division, dividing `number` by `more-numbers`,
|
||||
skipping any inputs that are not ints or floats, and returning an int.
|
||||
If `number` is not an int or float, `int/`returns nil.
|
|
@ -0,0 +1,22 @@
|
|||
# Boolean Logic
|
||||
|
||||
## `not`
|
||||
```
|
||||
(not value)
|
||||
```
|
||||
`not` returns nil if `value` is non-nil, otherwise, it returns `t`.
|
||||
|
||||
## `or`
|
||||
```
|
||||
(or &rest values)
|
||||
```
|
||||
|
||||
`or` returns its first non-nil argument, or nil if all arguments are
|
||||
nil.
|
||||
|
||||
## `and`
|
||||
```
|
||||
(and &rest values)
|
||||
```
|
||||
`and` returns its last argument if all arguments are non-nil, or nil if
|
||||
it encounters a nil argument.
|
|
@ -0,0 +1,55 @@
|
|||
# Comparison
|
||||
|
||||
## `eq`
|
||||
```
|
||||
(eq value &rest values)
|
||||
```
|
||||
`eq` returns t if all `values` are equal to `value`, or nil if any are
|
||||
not.
|
||||
|
||||
For two values to be equal according to `eq`, they must have the same
|
||||
type. In all cases **except strings**, `eq` compares the immediate value
|
||||
as returned by [`addr-of`](stdlib_misc.md#addr-of). However, `eq` will
|
||||
return t for strings with identical contents, **regardless of their
|
||||
addresses**. To check if two strings reference the same location in
|
||||
memory, compare their `addr-of`.
|
||||
|
||||
## `=`
|
||||
```
|
||||
(= value &rest values)
|
||||
```
|
||||
`=` compares its arguments numerically. If they are all equal, it
|
||||
returns `value`, otherwise it returns nil. If any argument is not an int
|
||||
or float, `=` returns nil.
|
||||
|
||||
## `<`
|
||||
```
|
||||
(< value &rest values)
|
||||
```
|
||||
`<` compares its arguments numerically. If the sequence is monotonically
|
||||
increasing, it returns the last argument, otherwise it returns nil. If
|
||||
any argument is not an int or float, `<` returns nil.
|
||||
|
||||
## `>`
|
||||
```
|
||||
(> value &rest values)
|
||||
```
|
||||
`>` compares its arguments numerically. If the sequence is monotonically
|
||||
decreasing, it returns the last argument, otherwise it returns nil. If
|
||||
any argument is not an int or float, `>` returns nil.
|
||||
|
||||
## `<=`
|
||||
```
|
||||
(<= value &rest values)
|
||||
```
|
||||
`<=` compares its arguments numerically. If the sequence is
|
||||
monotonically nondecreasing, it returns the last argument, otherwise it
|
||||
returns nil. If any argument is not an int or float, `<=` returns nil.
|
||||
|
||||
## `>=`
|
||||
```
|
||||
(>= value &rest values)
|
||||
```
|
||||
`>=` compares its arguments numerically. If the sequence is
|
||||
monotonically nonincreasing, it returns the last argument, otherwise it
|
||||
returns nil. If any argument is not an int or float, `>=` returns nil.
|
|
@ -0,0 +1,22 @@
|
|||
# Special Forms
|
||||
Special forms are constructs that Keithlisp evaluates differently from
|
||||
other S-expressions.
|
||||
|
||||
## `quote`
|
||||
```
|
||||
quote form
|
||||
```
|
||||
`quote` returns `form` as-is, without performing any evaluation on it.
|
||||
|
||||
## `cond`
|
||||
```
|
||||
cond {(test {body-form}*)}*
|
||||
```
|
||||
`cond` is Keithlisp's basic conditional operator. It consists of zero or
|
||||
more clauses (a `test`, followed by zero or more `body-form`s).
|
||||
|
||||
`cond` evaluates the `test` of each clause in order. If the result is
|
||||
non-nil, `cond` skips all remaining clauses, evaluates each `body-form`,
|
||||
and returns the result of the last one (or the result of `test` if the
|
||||
clause has no `body-form`s). Otherwise, if all `test`s evaluate to nil,
|
||||
or no clauses were given, `cond` returns nil.
|
|
@ -0,0 +1,31 @@
|
|||
# Miscellaneous Functions
|
||||
|
||||
## `type-of`
|
||||
```
|
||||
(type-of value)
|
||||
```
|
||||
`type-of` returns an atom indicating the type of `value`, or nil if
|
||||
`value` is nil.
|
||||
|
||||
## `addr-of`
|
||||
```
|
||||
(addr-of value)
|
||||
```
|
||||
`addr-of` returns the raw immediate value of its argument as an int. For
|
||||
conses, strings, and funptrs, this is their memory address (hence the
|
||||
name). For ints, floats, and atoms, this returns their raw bytes
|
||||
interpreted as a signed 2's-complement integer.
|
||||
|
||||
## `set`
|
||||
```
|
||||
(set atom value)
|
||||
```
|
||||
`set` changes the value associated with `atom` in syms-alist, or creates
|
||||
the association if it does not already exist. It returns `value`.
|
||||
|
||||
## `fun`
|
||||
```
|
||||
(fun atom)
|
||||
```
|
||||
`fun` returns the function associated with `atom` in funs-alist, or nil
|
||||
if no such function exists.
|
29
main.c
29
main.c
|
@ -235,7 +235,7 @@ void lisp_evaluate(lisp_cons* cons, lisp_value* value) {
|
|||
return;
|
||||
}
|
||||
if (cons->car.value.atom == atom_cond) {
|
||||
lisp_macro_cond(cons->cdr.value.cons, value);
|
||||
lisp_sform_cond(cons->cdr.value.cons, value);
|
||||
return;
|
||||
}
|
||||
lisp_cons* fun_cons = lisp_alist_get(funs_alist, cons->car);
|
||||
|
@ -279,7 +279,7 @@ void lisp_evaluate(lisp_cons* cons, lisp_value* value) {
|
|||
}
|
||||
}
|
||||
lisp_atom atom_cond;
|
||||
void lisp_macro_cond(lisp_cons* cons, lisp_value* value) {
|
||||
void lisp_sform_cond(lisp_cons* cons, lisp_value* value) {
|
||||
while (cons != NULL) {
|
||||
lisp_cons* fork = cons->car.value.cons;
|
||||
lisp_evaluate_value(fork->car, value);
|
||||
|
@ -298,15 +298,32 @@ void lisp_macro_cond(lisp_cons* cons, lisp_value* value) {
|
|||
}
|
||||
|
||||
void lisp_set(lisp_cons* cons, lisp_value* value) {
|
||||
lisp_value key = cons->car;
|
||||
*value = cons->cdr.value.cons->car;
|
||||
lisp_cons** pairptr = lisp_alist_getptr(syms_alist, key);
|
||||
if (pairptr != NULL) {
|
||||
(*pairptr)->cdr = *value;
|
||||
return;
|
||||
}
|
||||
lisp_cons* new_alist = dbg_malloc(sizeof(lisp_cons));
|
||||
lisp_cons* pair = dbg_malloc(sizeof(lisp_cons));
|
||||
pair->car = cons->car;
|
||||
pair->cdr = cons->cdr.value.cons->car;
|
||||
lisp_alist_put(&syms_alist, pair);
|
||||
*value = pair->cdr;
|
||||
pair->car = key;
|
||||
pair->cdr = *value;
|
||||
new_alist->car.type = LISP_T_CONS;
|
||||
new_alist->car.value.cons = pair;
|
||||
new_alist->cdr.type = LISP_T_CONS;
|
||||
new_alist->cdr.value.cons = syms_alist;
|
||||
syms_alist = new_alist;
|
||||
return;
|
||||
}
|
||||
|
||||
void lisp_fun(lisp_cons* cons, lisp_value* value) {
|
||||
lisp_cons* pair = lisp_alist_get(funs_alist, cons->car);
|
||||
if (pair == NULL) {
|
||||
value->type = LISP_T_CONS;
|
||||
value->value.cons = NULL;
|
||||
return;
|
||||
}
|
||||
*value = pair->cdr;
|
||||
}
|
||||
|
||||
|
|
2
main.h
2
main.h
|
@ -58,6 +58,6 @@ lisp_atom lisp_defun_native(lisp_string* lstr, lisp_native_fun funptr);
|
|||
void lisp_evaluate_value(lisp_value input, lisp_value* result);
|
||||
void lisp_evaluate(lisp_cons* cons, lisp_value* value);
|
||||
extern lisp_atom atom_cond;
|
||||
void lisp_macro_cond(lisp_cons* cons, lisp_value* value);
|
||||
void lisp_sform_cond(lisp_cons* cons, lisp_value* value);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -202,7 +202,8 @@ void lisp_eq(lisp_cons* cons, lisp_value* value) {
|
|||
}
|
||||
cons = cons->cdr.value.cons;
|
||||
}
|
||||
*value = cmp_value;
|
||||
value->type = LISP_T_ATOM;
|
||||
value->value.atom = atom_t;
|
||||
}
|
||||
void lisp_num_eq(lisp_cons* cons, lisp_value* value) {
|
||||
lisp_value cmp_value = cons->car;
|
||||
|
|
Loading…
Reference in New Issue