diff --git a/femtolisp/.gitignore b/femtolisp/.gitignore new file mode 100644 index 0000000..5ae7457 --- /dev/null +++ b/femtolisp/.gitignore @@ -0,0 +1,4 @@ +/*.o +/*.do +/*.a +/flisp diff --git a/femtolisp/Makefile b/femtolisp/Makefile index 98af21a..06ba51e 100644 --- a/femtolisp/Makefile +++ b/femtolisp/Makefile @@ -22,7 +22,7 @@ SHIPFLAGS = -O2 -DNDEBUG $(FLAGS) default: release test test: - ./flisp unittest.lsp + cd tests && ../flisp unittest.lsp %.o: %.c $(CC) $(SHIPFLAGS) -c $< -o $@ diff --git a/femtolisp/bq.scm b/femtolisp/examples/bq.scm similarity index 100% rename from femtolisp/bq.scm rename to femtolisp/examples/bq.scm diff --git a/femtolisp/cps.lsp b/femtolisp/examples/cps.lsp similarity index 100% rename from femtolisp/cps.lsp rename to femtolisp/examples/cps.lsp diff --git a/femtolisp/rule30.lsp b/femtolisp/examples/rule30.lsp similarity index 100% rename from femtolisp/rule30.lsp rename to femtolisp/examples/rule30.lsp diff --git a/femtolisp/site/doc b/femtolisp/site/doc deleted file mode 100644 index cabbeb0..0000000 --- a/femtolisp/site/doc +++ /dev/null @@ -1,62 +0,0 @@ -1. Syntax - -symbols -numbers -conses and vectors -comments -special prefix tokens: ' ` , ,@ ,. -other read macros: #. #' #\ #< #n= #n# #: #ctor -builtins - -2. Data and execution models - -3. Primitive functions - -eq atom not set prog1 progn -symbolp numberp builtinp consp vectorp boundp -+ - * / < -apply eval - -4. Special forms - -quote if lambda macro while label cond and or - -5. Data structures - -cons car cdr rplaca rplacd list -alloc vector aref aset length - -6. Other functions - -read, print, princ, load, exit -equal, compare -gensym - -7. Exceptions - -trycatch raise - -8. Cvalues - -introduction -type representations -constructors -access -memory management concerns -ccall - - -If deliberate 50% heap utilization seems wasteful, consider: - -- malloc has per-object overhead. for small allocations you might use - much more space than you think. -- any non-moving memory manager (whether malloc or a collector) can - waste arbitrary amounts of memory through fragmentation. - -With a copying collector, you agree to give up 50% of your memory -up front, in exchange for significant benefits: - -- really fast allocation -- heap compaction, improving locality and possibly speeding up computation -- collector performance O(1) in number of dead objects, essential for - maximal performance on generational workloads diff --git a/femtolisp/site/doc.html b/femtolisp/site/doc.html deleted file mode 100644 index 855df6c..0000000 --- a/femtolisp/site/doc.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - -femtoLisp - - - - - -
- -

0. Argument

-This Lisp has the following characteristics and goals: - - - -

1. Syntax

-

1.1. Symbols

-Any character string can be a symbol name, including the empty string. In -general, text between whitespace is read as a symbol except in the following -cases: - -In these cases the symbol can be written by surrounding it with | | -characters, or by escaping individual characters within the symbol using -backslash \. Note that | and \ must always be -preceded with a backslash when writing a symbol name. - -

1.2. Numbers

- -A number consists of an optional + or - sign followed by one of the following -sequences: - -femtoLisp provides 30-bit integers, and it is an error to write a constant -less than -229 or greater than 229-1. - -

1.3. Conses and vectors

- -The text (a b c) parses to the structure -(cons a (cons b (cons c nil))) where a, b, and c are arbitrary -expressions. -

-The text (a . b) parses to the structure -(cons a b) where a and b are arbitrary expressions. -

-The text () reads as the symbol nil. -

-The text [a b c] parses to a vector of expressions a, b, and c. -The syntax #(a b c) has the same meaning. - - -

1.4. Comments

- -Text between a semicolon ; and the next end-of-line is skipped. -Text between #| and |# is also skipped. - -

1.5. Prefix tokens

- -There are five special prefix tokens which parse as follows:

-'a is equivalent to (quote a).
-`a is equivalent to (backquote a).
-,a is equivalent to (*comma* a).
-,@a is equivalent to (*comma-at* a).
-,.a is equivalent to (*comma-dot* a). - - -

1.6. Other read macros

- -femtoLisp provides a few "read macros" that let you accomplish interesting -tricks for textually representing data structures. - - - - - - - - - - - - - -
sequencemeaning -
#.eevaluate expression e and behave as if e's - value had been written in place of e -
#\cc is a character; read as its Unicode value -
#n=eread e and label it as n, where n - is a decimal number -
#n#read as the identically-same value previously labeled - n -
#:gNNN or #:NNNread a gensym. NNN is a hexadecimal - constant. future occurrences of the same #: sequence will read to - the identically-same gensym -
#sym(...)reads to the result of evaluating - (apply sym '(...)) -
#<triggers an error -
#'ignored; provided for compatibility -
#!single-line comment, for script execution support -
"str"UTF-8 character string; may contain newlines. - \ is the escape character. All C escape sequences are supported, plus - \u and \U for unicode values. -
-When a read macro involves persistent state (e.g. label assignments), that -state is valid only within the closest enclosing call to read. - - -

1.7. Builtins

- -Builtin functions are represented as opaque constants. Every builtin -function is the value of some constant symbol, so the builtin eq, -for example, can be written as #.eq ("the value of symbol eq"). -Note that eq itself is still an ordinary symbol, except that its -value cannot be changed. -

- - -
- - -

2. Data and execution models

- - - - - -
- - -

3. Primitive functions

- - -eq atom not set prog1 progn -symbolp numberp builtinp consp vectorp boundp -+ - * / < -apply eval - - - -
- -

4. Special forms

- -quote if lambda macro while label cond and or - - - -
- -

5. Data structures

- -cons car cdr rplaca rplacd list -alloc vector aref aset length - - - -
- -

6. Other functions

- -read print princ load exit -equal compare -gensym - - - -
- -

7. Exceptions

- -trycatch raise - - - -
- -

8. Cvalues

- -

8.1. Introduction

- -femtoLisp allows you to use the full range of C data types on -dynamically-typed Lisp values. The motivation for this feature is that -useful -interpreters must provide a large library of routines in C for dealing -with "real world" data like text and packed numeric arrays, and I would -rather not write yet another such library. Instead, all the -required data representations and primitives are provided so that such -features could be implemented in, or at least described in, Lisp. -

-The cvalues capability makes it easier to call C from Lisp by providing -ways to construct whatever arguments your C routines might require, and ways -to decipher whatever values your C routines might return. Here are some -things you can do with cvalues: -

-

-femtoLisp's "cvalues" is inspired in part by Python's "ctypes" package. -Lisp doesn't really have first-class types the way Python does, but it does -have values, hence my version is called "cvalues". - -

8.2. Type representations

- -The core of cvalues is a language for describing C data types as -symbolic expressions: - - - -A cvalue can be constructed using (c-value TYPE arg), where -arg is some Lisp value. The system will try to convert the Lisp -value to the specified type. In many cases this will work better if some -components of the provided Lisp value are themselves cvalues. - -

-Note the function type is called "c-function" to avoid confusion, since -functions are such a prevalent concept in Lisp. - -

-The function sizeof returns the size (in bytes) of a cvalue or a -c type. Every cvalue has a size, but incomplete types will cause -sizeof to raise an error. The function typeof returns -the type of a cvalue. - -

-You are probably wondering how 32- and 64-bit integers are constructed from -femtoLisp's 30-bit integers. The answer is that larger integers are -constructed from multiple Lisp numbers 16 bits at a time, in big-endian -fashion. In fact, the larger numeric types are the only cvalues -types whose constructors accept multiple arguments. Examples: -

-As you can see, missing zeros are padded in from the left. - - -

8.3. Constructors

- -For convenience, a specialized constructor is provided for each -class of C type (primitives, pointer, array, struct, union, enum, -and c-function). -For example: - - -These forms can be slightly less efficient than (c-value ...) -because in many cases they will allocate a new type for the new value. -For example, the fourth expression must create the type -(array int8 6). - -

-Notice that calls to these constructors strongly resemble -the types of the values they create. This relationship can be expressed -formally as follows: - -

-(define (c-allocate type)
-  (if (atom type)
-      (apply (eval type) ())
-      (apply (eval (car type)) (cdr type))))
-
- -This function produces an instance of the given type by -invoking the appropriate constructor. Primitive types (whose representations -are symbols) can be constructed with zero arguments. For other types, -the only required arguments are those present in the type representation. -Any arguments after those are initializers. Using -(cdr type) as the argument list provides only required arguments, -so the value you get will not be initialized. - -

-The builtin c-value function is similar to this one, except that it -lets you pass initializers. - -

-Cvalue constructors are generally permissive; they do the best they -can with whatever you pass in. For example: - -

- -

-ccopy, c2lisp - -

8.4. Pointers, arrays, and strings

- -Pointer types are provided for completeness and C interoperability, but -they should not generally be used from Lisp. femtoLisp doesn't know -anything about a pointer except the raw address and the (alleged) type of the -value it points to. Arrays are much more useful. They behave like references -as in C, but femtoLisp tracks their sizes and performs bounds checking. - -

-Arrays are used to allocate strings. All strings share -the incomplete array type (array char): - -

-> (c-value '(array char) [#\h #\e #\l #\l #\o])
-"hello"
-
-> (sizeof that)
-5
-
- -sizeof reveals that the size is known even though it is not -reflected in the type (as is always the case with incomplete array types). - -

-Since femtoLisp tracks the sizes of all values, there is no need for NUL -terminators. Strings are just arrays of bytes, and may contain zero bytes -throughout. However, C functions require zero-terminated strings. To -solve this problem, femtoLisp allocates magic strings that actually have -space for one more byte than they appear to. The hidden extra byte is -always zero. This guarantees that a C function operating on the string -will never overrun its allocated space. - -

-Such magic strings are produced by double-quoted string literals, and by -any explicit string-constructing function (such as string). - -

-Unfortunately you still need to be careful, because it is possible to -allocate a non-magic character array with no terminator. The "hello" -string above is an example of this, since it was constructed from an -explicit vector of characters. -Such an array would cause problems if passed to a function expecting a -C string. - -

-deref - -

8.5. Access

- -cref,cset,byteref,byteset,ccopy - -

8.6. Memory management concerns

- -autorelease - - -

8.7. Guest functions

- -Functions written in C but designed to operate on Lisp values are -known here as "guest functions". Although they are foreign, they live in -Lisp's house and so live by its rules. Guest functions are what you -use to write interpreter extensions, for example to implement a function -like assoc in C for performance. - -

-Guest functions must have a particular signature: -

-value_t func(value_t *args, uint32_t nargs);
-
-Guest functions must also be aware of the femtoLisp API and garbage -collector. - - -

8.8. Native functions

- - - diff --git a/femtolisp/site/flbanner.jpg b/femtolisp/site/flbanner.jpg deleted file mode 100644 index 4a0ffd5..0000000 Binary files a/femtolisp/site/flbanner.jpg and /dev/null differ diff --git a/femtolisp/site/flbanner.xcf b/femtolisp/site/flbanner.xcf deleted file mode 100644 index 5a609b5..0000000 Binary files a/femtolisp/site/flbanner.xcf and /dev/null differ diff --git a/femtolisp/site/flbanner2.jpg b/femtolisp/site/flbanner2.jpg deleted file mode 100644 index 20c0358..0000000 Binary files a/femtolisp/site/flbanner2.jpg and /dev/null differ diff --git a/femtolisp/site/index.html b/femtolisp/site/index.html deleted file mode 100644 index 9afbeb9..0000000 --- a/femtolisp/site/index.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - -femtoLisp - - -

femtoLisp

-
-femtoLisp is an elegant Lisp implementation. Its goal is to be a -reasonably efficient and capable interpreter with the shortest, simplest -code possible. As its name implies, it is small (10-15). -Right now it is just 1000 lines of C (give or take). It would make a great -teaching example, or a useful system anywhere a very small Lisp is wanted. -It is also a useful basis for developing other interpreters or related -languages. - - -

The language implemented

- -femtoLisp tries to be a generic, simple Lisp dialect, influenced by McCarthy's -original. - - -Builtin special forms:
-quote, cond, if, and, or, lambda, macro, label, while, progn, prog1 -

-Builtin functions:
-eq, atom, not, symbolp, numberp, boundp, cons, car, cdr, - read, eval, print, load, set, - +, -, *, /, <, apply, rplaca, rplacd -

-Included library functions and macros:
- -setq, setf, defmacro, defun, define, let, let*, labels, dotimes, -macroexpand-1, macroexpand, backquote, - -null, consp, builtinp, self-evaluating-p, listp, eql, equal, every, any, -when, unless, - -=, !=, >, <=, >=, compare, mod, abs, identity, - -list, list*, length, last, nthcdr, lastcdr, list-ref, reverse, nreverse, -assoc, member, append, nconc, copy-list, copy-tree, revappend, nreconc, - -mapcar, filter, reduce, map-int, - -symbol-plist, set-symbol-plist, put, get - -

-system.lsp - - -

The implementation

- - -

-lisp.c - - -

femtoLisp2

- -This version includes robust reading and printing capabilities for -circular structures and escaped symbol names. It adds read and print support -for the Common Lisp read-macros #., #n#, and #n=. -This allows builtins to be printed in a readable fashion as e.g. -"#.eq". -

-The net result is that the interpreter achieves a highly satisfying property -of closure under I/O. In other words, every representable Lisp value can be -read and printed. -

-The traditional builtin label provides a purely-functional, -non-circular way -to write an anonymous recursive function. In femtoLisp2 you can -achieve the same effect "manually" using nothing more than the reader: -
-#0=(lambda (x) (if (<= x 0) 1 (* x (#0# (- x 1))))) -

-femtoLisp2 has the following extra features and optimizations: -

-Those two optimizations are a Big Deal. -

-lisp2.c (uses flutils.c) - - -

Performance

- -femtoLisp's performance is surprising. It is faster than most -interpreters, and it is usually within a factor of 2-5 of compiled CLISP. - - - - - - - - - - - - - - - - - -
solve 5 queens problem 100x
interpretedcompiled -
CLISP 4.02 sec 0.68 sec -
femtoLisp22.62 sec 2.03 sec** -
femtoLisp 6.02 sec 5.64 sec** -
recursive fib(34)
interpretedcompiled -
CLISP 23.12 sec 4.04 sec -
femtoLisp24.71 sec n/a -
femtoLisp 7.25 sec n/a -
-** femtoLisp is not a compiler; in this context "compiled" means macros -were pre-expanded. - - -

"Installation"

- -Here is a Makefile. Type make to build -femtoLisp, make NAME=lisp2 to build femtoLisp2. - - -

Tail recursion

-The femtoLisp evaluator is tail-recursive, following the idea in - -Lambda: The Ultimate Declarative (should be required reading -for all schoolchildren). -

-The femtoLisp source provides a simple concrete example showing why a function -call is best viewed as a "renaming plus goto" rather than as a set of stack -operations. -

-Here is the non-tail-recursive evaluator code to evaluate the body of a -lambda (function), from lisp-nontail.c: -

-        PUSH(*lenv);    // preserve environment on stack
-        lenv = &Stack[SP-1];
-        v = eval(*body, lenv);
-        POP();
-        return v;
-
-(Note that because of the copying garbage collector, values are referenced -through relocatable handles.) -

-Superficially, the call to eval is not a tail call, because work -remains after it returns—namely, popping the environment off the stack. -In other words, the control stack must be saved and restored to allow us to -eventually restore the environment stack. However, restoring the environment -stack is the only work to be done. Yet after this point the old -environment is not used! So restoring the environment stack isn't -necessary, therefore restoring the control stack isn't either. -

-This perspective makes proper tail recursion seem like more than an -alternate design or optimization. It seems more correct. -

-Here is the corrected, tail-recursive version of the code: -

-        SP = saveSP;    // restore stack completely
-        e = *body;      // reassign arguments
-        *penv = *lenv;
-        goto eval_top;
-
-penv is a pointer to the old environment, which we overwrite. -(Notice that the variable penv does not even appear in the first code -example.) -So where is the environment saved and restored, if not here? The answer -is that the burden is shifted to the caller; a caller to eval must -expect that its environment might be overwritten, and take steps to save it -if it will be needed further after the call. In practice, this means -the environment is saved and restored around the evaluation of -arguments, rather than around function applications. Hence (f x) -might be a tail call to f, but (+ y (f x)) is not. - - - diff --git a/femtolisp/100x100.lsp b/femtolisp/tests/100x100.lsp similarity index 100% rename from femtolisp/100x100.lsp rename to femtolisp/tests/100x100.lsp diff --git a/femtolisp/color.lsp b/femtolisp/tests/color.lsp similarity index 100% rename from femtolisp/color.lsp rename to femtolisp/tests/color.lsp diff --git a/femtolisp/perf.lsp b/femtolisp/tests/perf.lsp similarity index 100% rename from femtolisp/perf.lsp rename to femtolisp/tests/perf.lsp diff --git a/femtolisp/tcolor.lsp b/femtolisp/tests/tcolor.lsp similarity index 100% rename from femtolisp/tcolor.lsp rename to femtolisp/tests/tcolor.lsp diff --git a/femtolisp/test.lsp b/femtolisp/tests/test.lsp similarity index 100% rename from femtolisp/test.lsp rename to femtolisp/tests/test.lsp diff --git a/femtolisp/torture.scm b/femtolisp/tests/torture.scm similarity index 100% rename from femtolisp/torture.scm rename to femtolisp/tests/torture.scm diff --git a/femtolisp/torus.lsp b/femtolisp/tests/torus.lsp similarity index 100% rename from femtolisp/torus.lsp rename to femtolisp/tests/torus.lsp diff --git a/femtolisp/unittest.lsp b/femtolisp/tests/unittest.lsp similarity index 100% rename from femtolisp/unittest.lsp rename to femtolisp/tests/unittest.lsp diff --git a/femtolisp/tiny/lisp b/femtolisp/tiny/lisp deleted file mode 100755 index 4446ca2..0000000 Binary files a/femtolisp/tiny/lisp and /dev/null differ diff --git a/femtolisp/tiny/lisp2 b/femtolisp/tiny/lisp2 deleted file mode 100755 index db01062..0000000 Binary files a/femtolisp/tiny/lisp2 and /dev/null differ diff --git a/femtolisp/tiny/lispf b/femtolisp/tiny/lispf deleted file mode 100755 index dc65ee6..0000000 Binary files a/femtolisp/tiny/lispf and /dev/null differ