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 @@ - - -
- --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. - - -
-'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).
-
-
-
sequence | meaning - |
#.e | evaluate expression e and behave as if e's - value had been written in place of e - |
#\c | c is a character; read as its Unicode value - |
#n=e | read e and label it as n, where n - is a decimal number - |
#n# | read as the identically-same value previously labeled - n - |
#:gNNN or #:NNN | read 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. - |
- -
-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". - -
-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: -
-(c-value 'int32 0xdead 0xbeef) ; make 0xdeadbeef -(c-value 'uint64 0x1001 0x8000 0xffff) ; make 0x000010018000ffff -- -As you can see, missing zeros are padded in from the left. - - -
-(uint32 0xcafe 0xd00d) -(int32 -4) -(char #\w) -(array 'int8 [1 1 2 3 5 8]) -- - -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: - -
-(c-value '(array int8 1)) ; ok, full type provided -(c-value '(array int8)) ; error, no size information -(c-value '(array int8) [0 1]) ; ok, size implied by initializer -- - -
-ccopy, c2lisp - -
-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 - -
-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. - - -
-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 - - -
-lisp.c - - -
-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: -
-lisp2.c (uses flutils.c) - - -
interpreted | compiled - | |
CLISP | 4.02 sec | 0.68 sec - |
femtoLisp2 | 2.62 sec | 2.03 sec** - |
femtoLisp | 6.02 sec | 5.64 sec** - |
interpreted | compiled - | |
CLISP | 23.12 sec | 4.04 sec - |
femtoLisp2 | 4.71 sec | n/a - |
femtoLisp | 7.25 sec | n/a - |
-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