rtLisp

Realtime Lisp
Reference Manual

Version 0.5
2019 Jul 4

Glenn Takanishi

These pages are a modification of the original documention from RefLisp-2.67 by Bill Birch

Introduction

The "rtLisp" interpreter is a small C-program for self study of realtime systems programming. rtLisp uses the Scheme dialect of Lisp described in the scheme standard guide R3RS.

Run the interpreter by entering:

```        > rtlisp
; rtlisp v-0.1
>
```

Lexical and Syntactic Conventions

The main routine for rtLisp runs the read-evaluation-and-print loop, RELP, to execute each lisp expression in a program. A program's expression is embedded with parenthesis. For example, the expression

```        (print "hello" "world")
```

is a list. This list is composed of atoms called symbols. The atom "print" is a function operator, and the elements "hello" "world" are atomic identifiers or symbols which are literally data elements which are not evaluated. These atoms are quoted expressions. A quoted expression can be turned from data to program operators whenever the programmer decides to perform a transformation or substitution of data atoms or quoted expressions into function operators.

The lisp reader may parse a lisp program a line at a time. Each line is composed of a list or lists embedded in parenthesis or a line maybe contain just an atom. The lisp reader then passes the list consisting of symbols to the lisp evaluator. The primary purpose of the lisp evaluator is to break down a lisp expression into a form it can compute . The list evaluator takes the first element of the lisp above to be a function operator "print". The first element by convention is call the "car" of the list. The rest of the list, the "cdr", are the data elements hello and world.

Finally, the result of the evaluation of an expression is printed.

Lisp Expressions and Lambda

John McCarthy separated a lisp expression into its form and its arguments. The expression form and expression arguments can exist independently of each other. For example, the lambda list for the function which increments an integer by one is "(n) (+ n 1)". The first element, (n), is the argument list and the second element, (+ n 1), is the form list. John McCarthy noted this often in his published works . He used the formalism of lambda calculus to explicitly separate the functional form from its arguments.

The lambda expression for the list (print "hello" "world") is

```     (args) (print args)  where args is the list ["hello" "world"].
```

Currently, rtlisp uses dynamic scoping. It is not lexically scoped like Scheme. Lisp scoping is determined by how the arguments in symbolic expressions are kept track of. This is an important part of building the rtlisp interpreter.

Lisp Syntax

The special characters recognised are:

```
( [		-- beginning of a list, or cons cell.
) ]		-- end of a list, or cons cell
.		-- separates the car and cdr halves of a cell.
'		-- quote character
`		-- backquote character
,		-- comma function
,@		-- comma-at function
#'		-- function character
#!		-- first user reader macro.
#?		-- second user reader macro.
"		-- start and end of strings
\		-- escape char for within strings (not Common Lisp)
;		-- starts a comment
\		-- escape for the next character in symbols.
-0123456789 	-- start an integer

```
```Whitespace characters are recognised as the separator between lexical
tokens.

A more formal description of the s-expression syntax might be:

An <s-exp> can be an <atom> or a <list>

<atom>s can be:

nil	; nil is an atom

positive or negative integers eg:

545, -23

floating point numbers eg:

13.4, -33.7, 12.4E8, 23.4e-2

unlimited length character strings delimited by "s
with special characters in strings:
"\n" = newline
"\e" = escape
"\t" = tab
"\r" = carriage return
"\f" = form feed
"\\" = \
"\"" = "
"\c" = c where c is any other charater.
symbols
- symbol names may include any character preceded
by the \ character.
eg. A\(strange\.symbol

- alphabetic characters are all converted to
lower case in the interpreter. Thus FOOBAR
and foobar are the same.

- constants

- special symbols whose value cannot be changed
with set, and which are never garbage collected.

<list>s can be either:
nil	; the null list
() 	; the null list which equals nil
( <s-exp> . <s-exp> ) ; a cons cell
( <s-exp> <s-exp> etc.... ) ; which is the same as
( <s-exp> . ( <s-exp> .
(  <s-exp> etc.. . nil ))))

An s-expression preceded by the ' single quote character
is expanded by (read) to be quoted:

'<s-exp>  ==>	(quote <s-exp>)

Other characters have this effect also:

`<s-exp> ==>	(backquote <s-exp>)
,<s-exp> ==>	(comma <s-exp>)
,@<s-exp> ==>	(comma-at <s-exp>)
#'<s-exp> ==>	(function <s-exp>)

[The notation "==>" means "evaluates to".]

These functions are defined in the initialisation file and are
intended to provide compatibility with Common Lisp.

#!<s-exp> ==>	(quser1 <s-exp>)
#?<s-exp> ==>	(quser2 <s-exp>)

These quote characters intended to be user-definable.

The Top Level (Read/Eval/Print, REPL, Loop)

Installing rtLisp

Set up the environment variable LISPINIT to point to the initialisation
file.  For example use:

export LISPINIT=/usr/local/share/rtlisp/init.l

To run the demonstrations, change into the rtlisp directory and type
the following after the prompt:

rtlisp demo.s

Starting rtLisp

On your operating system, there will be a command or mouse-clicking
operation which will get the program started.

rtlisp [arg ...]

Once started, the program accumulates the command line parameters in a
list in symbol "command-line". The program then reads and executes the
initialisation file file. This filename is taken from the environment
variable "LISPINIT". If the environment variable is missing rtlisp
attempts to read "init.l" in the current directory. You should set up

export LISPINIT=/usr/local/share/rtlisp/init.l

The shipped initialisation file then processes the command line
parameters. Each is taken to be the name of a file to be read and
executed. It processes each file in turn, skipping files it cannot
open. You may prefer to use the command line arguments in a different
way, if so you must alter your LISPINIT file.

rtLisp Execution

This section describes what happens after you invoke rtlisp. After the
initialisation messages you will be presented with a > prompt:

> rtlisp
; rtlisp v-0.1
>

To halt execution type (exit). Also the interpreter returns control to
the operating system when it sees end-of-file (or the *eof* symbol).
The character used to signify this varies from one system to  another,
on Unix systems it is Control-D.

The operation of the interpreter is a read-eval-print loop.  Its
operation is the same as (eval <s-exp>) and is as follows:

Atoms which are not symbols such as: integer, float, string, primitive,
special, stream. evaluate to themselves. eg

> 12
12

Symbols are tested to see if they have  a value, in which case that is
returned. e.g.

> (set a 1)
1
> a
1

If a symbol has no value, it is unbounded.  An error is reported and
processing stops.  Some symbols are constant and should not be changed.
They evaluate to themselves.  Important constants are:	nil, #t, unbound,
*eof*.

Following an Expression through the REPL

The lisp interpreter processes a symbolic lisp expression by running
it through three basic phases: read, evaluation and print.

The lisp interpreter first reads the symbolic expression from the
command line or input file a line at a time.  For example, you can type
"(cons 2 3)" on the command line.  This lisp expression is parsed in the
read phase.  The first element of the list is parsed into an operator
token "cons" which constructs a list pair.  The parser continues processing
the list for more items until the last one.  After the parser classifies
each item or token, this list of items is passed on to the next phase
called the evaluation phase.

In the evaluation phase, for example, the cons procedure evaluates the
arguments 2 and 3 forming a cons cell (2 . 3).  Inside the internals of
the interpreter this expression is passed to the "PRIMITIVE" section of code

(cons 2 3) ==> (<PRIMITIVE:2783823> 2 3) ==> (2 . 3)

If the expression being evaluated was "(cons 'a 'b)", the arguments
would not be evaluated.  For example,

(cons 'a 'b) ==> (<SPECIAL:989977> (quote a) (quote b))
==> (a . b)

"a" and "b" are symbols with no specifically assigned values.

For our interpreter, inside the rtlisp internals, the evaluation of the
arguments for the lisp expression falls into three categories: PRIMITIVE,
SPECIAL and MACRO.  The corresponding lisp function operation is classified
into "lambda", "lambda*" or "macro".  The application of the evalution, or
the "apply" process breaks down into these three types.

Finally, the results of the evaluation are passed to the print function.

Examples of Lambda Evaluation

If "lambda" is found, the actual arguments are evaluated (PRIMITIVE). The
function's argument symbols are then set to these values.

> ((lambda (x) (car x)) (list 1 2 3 ))
1

If "lambda*" is found, the actual arguments are not evaluated.

> ((lambda* (x) (car x)) (list 1 2 3 4))
list

>  (set f `(lambda (n) (eval (+ n 1))))
(lambda (n) (eval (+ n 1)))
> (f 1)
2

>  (set g (lambda (n) (+ n 1)))
(lambda (n) (eval (+ n 1)))
> (g 2)
3

>  ((lambda (x) (car x)) (list 1 2 3 ))
1

If "macro" is found, the actual arguments are not evaluated, like
lambda*, however the result of the "apply" is evaluated again. e.g.

> ((macro (x) `(car ,x)) '(1 2 3 4))
1

If a formal argument is the special symbol #:rest, then all remaining
actual arguments are set to the formal argument following the #:rest.

> ((lambda (a #:rest b) (list a b)) 1 2 3 4 5 6)
(1 (2 3 4 5 6))

If a formal argument is the symbol #:optional, then any missing actual
arguments are set to NIL.

> ((lambda (a #:optional b) (list a b)) 99)
(99 nil)

If an optional argument is expressed as a list of the form (<symbol>
<initform>) then the <initform> is evaluated and used when no actual
argument is supplied.

> ((lambda (a #:optional (b 27)) (list a b)) 99)
(99 27)

The symbols #:rest and #:optional may be used in combination.

> ((lambda (a #:optional b #:rest c) (list a b c)) 99)
(99 nil nil)

> (set F (lambda (a #:optional b #:rest c) (list a b c)))
(lambda (a #:optional b #:rest c) (list a b c))
> (F 99)
(99 nil nil)

In all cases the body of the function is then evaluated with the new
bindings. The value of this evaluation is then returned. After
execution of the function, the previous  values of the symbols used as
arguments are restored.

Scope and Extent

rtLisp is a "shallow" binding interpreter.   It has no environments.
The function arguments therefore have dynamic extent and global scope.
This means that the formal arguments of a lambda-list
are the same symbols available at the top level, and are effectively
globals. It also means that when a function is applied, the formal
arguments are shadowed, and are removed when the function finishes.

In it's basic form then, the interpreter suffers from the "funarg"
problem.  The #' reader macro is provided to allow (function) to be
defined in rtLisp.

Lexical scope may be added to programs by re-defining DEF with a
version that re-writes the formal arguments of defined functions.

Adding both lexical scope and indefinite extent can be achieved  by
deferring the re-writing of functions until evaluation time.
Programs will run significantly slower if they use indefinite extent.
Some Common Lisp functions require indefinite extent scope to run
correctly, usually those that implement objects with local state.

List Processing Functions

The following sections describe the inbuilt functions provided in the
interpreter.

(car <expr>)
Returns the first element of the list <expr>, or more
strictly, the A side of the cons cell.

(car '(1 2 3 4)) ==> 1
(car '()) ==> nil

(cdr <expr>)
Returns everything except the first element of <expr>

(cdr '(1 2 3 4)) ==> (2 3 4)
(cdr '()) ==> nil

Returns the second element of <expr>

(cadr '(1 2 3 4)) ==> 2

Returns the third element of <expr>

(caddr '(1 2 3 4)) ==> 3

(nth <integer> <expr>)
Returns the nth element of <expr>, numbering from zero.
It returns NIL if <integer> is greater than the length of the
list.

(nth 3 '(0 1 2 3 4)) ==> 3

(cons <expr1> <expr2>)
Returns a new cons cell with <expr1> and <expr2>
as its car and cdr.

(cons 1 2)   ==> (1 . 2)
(cons 1 nil) ==> (1) ==> (1 . nil)
(cons 1 '(8 9)) ==> (1 8 9)

(length <expr>)
Returns the number of elements in the list, or the number of
characters in a string or symbol name.

(length nil) ==> 0
(length '(1 2 3 4)) ==> 4
(length "foobar") ==> 6
(length (symbol-name 'fred)) ==> 4

(member <expr> <list>)
Returns a sublist if <expr> is a member of the list, nil
otherwise. (equal) is used to compare the elements.

Definition:

(def member (expr list)
(cond
((null list) nil)
((equal? expr (car list)) list)
(t (member expr (cdr list)))))

(member '23 '(a s d f)) ==> nil
(member '23 '(a b c 23 d)) ==> (23 d)

(append <a> #:rest <b>)
Appends one or more lists together.

(append '(1 3) '(3 4) ==> (1 2 3 4)
(append '(1 2) '(3 4) '(5 6) ==> (1 2 3 4 5 6)

(reverse <x>)
Reverses the top level of a list.

(reverse '(1 2 3 4)) ==> (4 3 2 1)

(move <to-cell> <from-cell>)

This function destructively modifies the to-cell by copying the
contents of from-cell into it. It attempts to discard the cells
pointed to by to-cell before the operation if it was a cons
cell. It checks to see if a circular structure would result
from the operation. For now, it is an error to create circular
structures, because the reference counting garbage collector
cannot handle them.

> (def set-car! (to from)		; define SET-CAR!
(move to (cons from (cdr to)))
> (set A '(1 . 2))		; initialise a cell
> (set B A)
> (set-car! A 99)			; overwrite it
> B
(99 . 2)

Symbol Functions

The value of a symbol is *unbound* if none of these functions below
have given it a value. If you (set\$) or (set!) a symbol to *unbound*,
the cells used in the previous value are reclaimed if possible.

(set\$ <symbol> <value>)
Assigns the free <symbol> the <value> specified.
Returns the value. <symbol> must be an identifier.

(set\$ 'x 21) ==> 21
x ==> 21

(symbol-value <symbol>)
Returns the current value of the symbol. An error occurs if
the symbol has no value.

(set\$ 'foobar 21)
(symbol-value 'foobar) ==> 21

(set! <symbol> <value>)
Performs the same as (set) however <symbol>
is not evaluated. This the usual assignment function
in rtlisp.

(set! x 89) ==> 89
x ==> 89

(constant <symbol> <value)
The same as set!, however the type of the <symbol> is changed
into a constant, ie., the symbol is unchangeable.

(intern <string>)
Creates a new symbol, with a printname of <string>. The
symbol is added to the symbol table, and can be found by
function is equivalent to (set-symbol).

> (set\$ (intern "foobar") 23)
23
foobar
23

(gensym)
Creates a unique new symbol, with a printname of G<n>, where
<n> is a unique number. The symbol is NOT added to the
symbol table, it is inaccessible to (read). eg:

>(gensym)
G123

(output-symbol <s-exp> #:optional <proforma>) This creates and interns
a symbol with a print name of <s-exp> even if a symbol with
that name is already present. The optional <proforma> is used
to derive the number of the hash bucket where the symbol is
stored. If <proforma> is absent, <s-exp> is used which is the
default. The symbol is returned. Note: rtlisp is different
from Common Lisp which only allows symbols to have string print
names.

(set-symbol <s-exp> #:optional <proforma>)

This looks for a symbol with a name equal to <s-exp>, using
is  used to derive the number of the hash bucket where the
symbol  is looked for and stored. If <proforma> is absent,
<s-exp> is  used which is the default. (read) uses (set-symbol)
with no proforma. The symbol is	returned. If this operation

This looks for a symbol with a name equal to <s-exp>, if none
is found it returns nil.  The optional <proforma> is  used to
derive the number of the hash bucket which is searched. If
<proforma> is absent, <s-exp> is  used by default. In addition,
if the proforma contains the wildcard * symbol, then (read-symbol)
matches on the symbol name. The symbol found is returned,
otherwise nil.

Definition of the matching used:
(else  (cond ((and (consp mask) (consp y))
(and (match (car mask) (car y))
(else nil)))))

> (or
> (set person '(name * age *))		; create a proforma
(output-symbol '(name (john doe) age 23) person) 	; and an instance
(read-symbol * person))				; look for any person
(name (john doe) age 23) 			; found John Doe!

This function can be used in conjunction with one of the
user defined quote charaters to achieve a usable syntax:

> (def quser2 (name) (eval (read-symbol name)))
quser2
(set w 2)
2
> w	; (read-symbol "w") ==> 'w
2

;; make a new symbol
(set\$ (set-symbol '(matrix 12 34)) 123.3)
123.3
> (matrix 12 34)	; access it
123.3

;; or if (quser1) is defined like (backquote):
#!(matrix ,x-cood ,y-coord ) ; x-coord is a symbol

(input-symbol <s-exp> #:optional <proforma>)
This looks for a symbol using (read-symbol), if one is found,
it is removed from the symbol table, and an attempt is made
to garbage collect it. If a symbol is found, its print
name is returned.

(def <function> <arglist> <expr>  .... )

This macro is equivalent to:
(set! <function> '(lambda <arglist> <expr> .....))
and is used to declare new functions. Functions
declared with (def) will have all their arguments
evaluated prior to being executed. (def) is a macro.

<arglist> can be either an atomic symbol or a
list of symbols. In the first case all arguments
are passed as a list in the single argument,
otherwise the actual arguments are placed in the
corresponding symbol values using (set). The #:optional and
#:rest flags can also be used.

The <function> symbol is returned.

(def foo (#:rest args) (length args)) ==> foo
(foo 1 2 3 4) ==> 4

(def bar (arg1 arg2) (cons arg1 arg2))==>bar
(bar 'a 'b) ==> (a . b)

(df <function> <arglist> <expr>  .... )

This macro is equivalent to:
(set\$ <function> '(lambdaq <arglist> <expr> .....))
and is used to declare new functions. Functions
declared with (df) do not have their arguments
evaluated prior to being executed.(df) is a macro.

<arglist> can be either an atomic symbol or a
list of symbols. In the first case all arguments
are put into <arglist> with (set), otherwise the actual
arguments are placed in the corresponding symbol values
using (set).

The <function> symbol is returned.

(df foo (#:rest args)  args) ==> foo
(foo a b c d) ==> (a b c d)

(df if (c true false)
(cond ((eval c) true)
(else false))) ==> if

(if (zero? 9) (cons 1 2) (cons 3 4)) ==> (cons 3 4)

(def-macro <function> <arglist> <expr>  .... )

This macro is equivalent to:
(set! <function> '(macro <arglist> <expr> .....))
and is used to declare macros. Functions
declared with (def-macro) do not have their arguments
evaluated prior to being executed. A macro
is evaluated like a (df) function, with the result

The <function> symbol is returned.

(def-macro if (c true false)
(cond ((eval c) true)
(else false))) ==> if

(if (zero? 9) (cons 1 2) (cons 3 4)) ==> (3 . 4)

(def-macro amacro (#:rest args) args)
(amacro cons 1 2 ) ==> (1 . 2)

(oblist)
Returns a list of all the symbols in the symbol table, in hashed
order, whether bound or not.

Control Functions

(cond (<predicate> <expr> .....)
(<predicate> <expr> .....)
....)

This is the main conditional control structure in rtlisp.
The predicates are evaluated in turn until one is
found that returns a non-nil value. Then each of the
expressions <expr> following are evaluated in turn.
The value returned from the (cond) is the value of
the final expression. If no <predicate> evaluates
to non-nil then the value of the (cond) is nil.
Likewise a null <expr> list renders nil.

(while <condition> <expr> .....)
The <condition> is evaluated, if it is not nil,
the <expr> list is evaluated, each in turn. This process
is repeated until the <condition> becomes nil.
The last <expr> evaluated is returned, or nil.

(until (<condition> <result> ... <lastresult>) <expr> .....)
The <condition> is evaluated, if it is nil,
the <expr> list is evaluated, each in turn. This process
is repeated until the <condition> becomes non-nil.
Then the <result> forms are evaluated, the value of the <lastresult>
is returned. If no <results> are present NIL is returned.

(def test1 (n)
(do-until ((equal n 0) "finished")
(print n)
(set! n (- n 1))))

(begin <expr> <expr> .......)
This function evaluates each of the expressions in its
arguments. The value of the last argument is returned.

(error <expr>)						[function]
The expression is printed, and the interpreter jumps
to the top level. This function can be used to jump out of
a user program if a severe error is detected. Note that
cells will be permanently lost from the free pool in the
process.

(catch <tag-symbol> <expr> ..... <expr-n>)
First half of no-local goto. The <tag-symbol> is (set) to the current
stack frame. The expressions following are executed and
the value of the last expression is returned.

(catch) is equivalent to:

(set\$ <tag-symbol> current stack frame)
(begin <expr> ..... <expr-n)

The special tag 'error-tag is used by the interpreter. If it
finds an error it calls (throw 'error-tag <>). You can therfore
catch errors by enclosing functions in (catch 'error-tag ...).

(throw <tag-symbol> <return-expr>)
Second half of a non-local goto. The <tag-symbol> is evaluated,
and must result in a stack-frame object set up by a previous,
current (throw). The <return-exp> is evaluated, and execution then
jumps to the last (throw) with the <tag-symbol>. The (throw)
returns with <return-exp>. (throw 'error-tag <>) is a way of
signalling a user error.

Implementation note: catch and throw are implemented with the C
setjmp() and longjmp() functions.  References to cells on the
stack cannot be garbage-collected, and (throw) will "leak" memory.
Use (catch) and (throw) to catch user errors or for circumstances
that are infrequent.

; function to calculate Square-root safely.
(def my-sqrt (x)
(cond ((< x 0) (throw 'math-error "whoops!"))
(t (exp (/ (log x) 2)))))

(catch 'math-error
(print 1)
(my-sqrt -22)
(print 2))

; When executed this prints:
1 "whoops!"

Evaluation Functions

(eval <expr>)
The <expr> is evaluated, given that <expr> may have
been evaluated before (eval) was called, this would
make the second evaluation of <expr>. Since shallow binding
is used in the interpreter, the current bindings are used.

(eval '(cons 1 2)) ==> (1 . 2)
(eval ''x) ==> x
(set ex '(* 2 3))
(eval ex) ==> 6

(apply <func> <actuals>)
The <func> is applied to the argument list <actuals>.
<func> must be a PRIMITIVE or SPECIAL or a lambda expression,
and <actuals> must be a list of arguments as required by
the <func> being invoked.

(apply 'cons '(1 2)) ==> (1 . 2)
(apply '(lambda x (cons x x) '(3)) ==> ((3) 3)

(quote <expr>)
The <expr> is returned un-evaluated. (quote) could be written
as: (df quote (x) x)
The parser in (read) turns '<expr> into (quote <expr>) when

(quote w) ==> w
'w	==> w

(backquote <expr>)
The back-quote function
provides an easy way to write macros. The (comma) and (comma-at)
markers are also supported. The description of the backquote
mechanism is rather complex, suffice it to say that it behaves
like (quote) with the addition that any expressions enclosed by
the (comma) are evaluated, and those enclosed by (comma-at)
are evaluated and spliced into the result. Note that (read)
expands ` , and ,@ to (backquote) (comma) and (comma-at).

`(foo ,(* 2 3)) 	; evaluates to (foo 6)
`(bar ,@(list 3 4))	; ==> (bar 3 4)

;; example of backquote used to define a macro:
;;
(def-macro if (condition true-exp false-exp)
`(cond (,condition ,true-exp)
(#t ,false-exp)))
(if (equal 1 2) 'equal 'not-equal)  ; ==> 'not-equal

;; And used to define a macro with variable arguments.
(def-macro toto (#:rest x)
`(cons ,@x))
(toto 1 2) ; ==> (1 . 2)

Predicate Functions

(atom? <expr>)
Returns #f if <expr> is a list, else #t.

(cons? <expr>)
Returns #t if <expr> is a list, else #f.

(null? <expr>)
Returns #t if <expr> is nil, else it returns #f.

(symbol? <expr>)
Returns #t if <expr> is an symbol, else Ef.

(symbol? 'car) ==> #t
(symbol? car) ==> nil ; car evaluates to a PRIMITVEP

(string? <expr>)
Returns #t if <expr> is a string, else #f.

(string? "car") ==> #t
(string? 'car) ==> #f

(equal? <expr1> <expr2>)
Returns #t if the two expressions point to the same
object in memory.

(equal? 'foo 'foo) ==> #t
(equal? "foo" "foo") ==> #t
(equal? 1 1) ==> #t
(equal? '(1) '(1)) => #t

(eq? <expr1> <expr2>)
Returns #t if the two expressions are equivalent,
irrespective of their location in memory. This is
safer than (equal?).

(eq? 'foo 'foo) ==> #t
(eq? "foo" "foo") ==> #t
(eq? 1 1) ==> #t
(eq? '(1) '(1)) => #t

(bound? <expr>)
Returns #f if <expr> is an symbol with no
assigned value. Useful for testing a symbol's
value without provoking an error.

(bound? x) ==> #f
(set! x 1)
(bound? x) ==> #t

(integer? <expr>)
Returns #t if <expr> is an integer, else #f.

(fix? 32) ==> #t
(fix? 32.8) ==> #f

(real? <expr>)
Returns #t if <expr> is a floating point number , else #f.

(float? 32.3) ==> #t
(float? 2) ==> #f

(number? <expr>)
Returns #t if <expr> is a number (float or integer), else #f.

(number? 32) ==> #t
(number? 3.2) ==> #t
(number? "32") ==> #f

Mathematical Functions

Mathematical functions may convert their arguments from integer types
to floats before evaluation.

(+ <num1> <num2> ..... <numN>)
Returns the sum of a list of integer arguments. Non-
integer arguments provoke an error message.

(- <num1> #:optional <num2>)
Returns <num1> - <num2>. If <num2> is absent it returns
-1 * <num1>.  Non-numeric arguments provoke an error message.

(* <num1> ..... )
Returns the product of a list of numeric arguments. May float
if necesary. Non-integer arguments provoke an error message.

(/ <num1> #:optional <num2>)
Returns <num1> divided by <num2>. If <num2> is absent it
returns 1/<num1>.  Non-numeric arguments provoke an error
message. A float will be returned if <num1> is not divisible
by <num2>.

(rem <num1> <num2>)
Returns the remainder when <num1> is divided by
<num2>. Non-integer arguments provoke an error
message.

(floor <number>)
Converts its argument by truncating towards negative infinity.
i.e. the result is is the largest integer that is not larger
than the <number>. A integer data type is always returned.

(abs <num>)
Returns the absolute value of <num>.

(random <range>)
Returns a pseudo-random number between 0 and <range>.

(seed <num>)
Sets the starting point of the random number
generator sequence. The (rand) called directly after
(seed) will always generate the same sequence for
the same seed. (Not Common Lisp).

(hash <sexp>)
Computes an hash index on the <sexp> input,
returning an integer. This is used by (set-symbol) etc
to calculate the hash bucket to use for symbols.
[The function may change from one version to the next.]

(float <integer>)
Returns float equivalent of its argument.

(log <num>)
Returns natural logarithm of argument.

(log10 <num>)
Returns log to base 10 of argument.

(exp <num>)
Returns e raised to the power of argument.

(sin <num>)
Returns trigonometric sine of <num> which

(cos <num>)
Returns trigonometric cosine of <num> which

(arc-sin <num>)
Returns trigonometric inverse sine of <num> which
is between 0 and 1, returns radians.

(arc-cos <num>)
Returns trigonometric inverse cosine of <num> which
is between 0 and 1, returns radians.

Relational Functions

(and <expr1> <expr2> .... <exprN>)		[Macro]
Evaluates each expression in turn until one is found
that has a value of nil, in which case nil is
returned. The remaining expressions are not evaluated.
If none are #f then #t is returned.

(or <expr1> <expr2> .... <exprN>)
Evaluates each expression in turn until one is found
that has a value of t, in which case t is
returned. The remainder are not evaluated.
If none are t then nil is returned.

(> <num1> <num2>)
Returns t if <num1> is greater than <num2>, else nil
is returned. Numeric arguments only.

(< <num1> <num2>)
Returns t if <num1> is less than <num2>, else nil is
returned. Numeric arguments only.

(string< <left> <right>)
Returns t if <left> is lexically less than <right>,
else nil is returned. A mixture of symbol and string
arguments is accepted.

(string< 'a 'b) ==> #t
(string< "b" 'a) == #f

Property Lists

Each symbol, with or without a value has a property list. The
properties are stored as an "alist". ie  ((<prop1> . <value1>) (<prop2>
. <valu2>) .........) All symbols have a property which is the text
used when the symbol is printed, PNAME.

(put <symbol> <property> <value>)
Sets the symbol's property to the value given.
Returns the <value>.

(put 'mary 'age 21) ==> 21
(put 'foobar 'what "first")

(get <symbol> <property> <value>)
Returns the value of the property attached to the
symbol. If this property is not attached nil is
returned.

(get 'john 'age) ==> 21

(remprop U IND)
Removes the property with indicator IND from the
property list of U.  Returns the removed property
or NIL if there was no such indicator.

(symbol-name <symbol>)
Returns a expression (string) containing the name of the symbol.

(symbol-name 'fred) ==> "fred"

(symbol-plist <symbol>)
Returns the entire property list of the symbol.

> (symbol-plist 'john)
(PNAME  john age  21)
> (symbol-plist (set-symbol '(plan 9))
(PNAME (plan 9))

Input/Output Functions

File I/O

(open <filename> &key :direction <direction>)
Opens the file specified, using the mode specified.
<filename> can be an symbol or string.
<direction> is has the following meanings:

:output  truncate or create for writing

If no mode is specified, :input is assumed.

(open) returns a stream, otherwise NIL.

(open "C:\\BILL\\LISP\\TEST.LSP" :direction :input) ==> <file:9823891>
(set! fd (open 'data :direction :output)) ==> <file:2829849>
(open "test.lsp")

(close <fd>)
Closes a file opened by (open). <fd> must be a stream.

(set! fd (open 'data 'input) ==> <file:2829849>
(close fd)

(force-output <fd>)
Forces all buffered data to be output on the file
specified.  <fd> must be a file descriptor returned
by (open).

(set! fd (open 'data 'output) ==> <file:2829849>
(flush fd)

Read parse the next s-expression from the file
specified. <fd> must have been returned from (open).
If <fd> is absent, then the standard
input is read. *eof* is returned at the end of file.

(read (open 'file 'input)) ==> eof

This function opens, reads, parses and evaluates the  input
file specified, <infilename> can be a symbol, string or
bigstring. If :verbose is t (default), then a comment is
printed to standard output. If :print is true, then the results
of evaluations are printed to standard output. :print nil is
the default.

(load "demos.s" :verbose t :print nil) ; The default
(load "/usr/mcarthy/eliza" :print t) ; print results.

(display <expr>)
Prints the <expr> on the standard output. Strings
are not quoted, nor are special characters. Returns
<expr>.

(princ "string") string
(princ ''foo)  (quote foo)

(write <expr> #:optional <fd>)
Prints the <expr> on the standard output. Strings
are quoted, and some quote forms are reduced. Returns
<expr>. This function is designed to output in a form

(prin1 "string") "string"
(prin1 weird\\symbol) weird\\symbol
(prin1 ''foo)  'foo
(prin1 ',@bar) ,@bar

(write* <fd> <expr> .....)
Prints the expressions to the file specified,
using (princ). If the first argument is not an <fd>
returned from (open) an error is reported.

Reads the next character from the file specified.
The value is returned as an integer less than 256.
<fd> must have been returned from (open), if absent
the standard input is read. *eof* is returned at the
end of file.

(write-char <char> <fd> )
Outputs one character from the file specified.
<char> is an integer which will be output.<fd> must
have been returned from (open), if absent the
standard output is used.

(string->integer <string>)
ASCII to integer transformation. Returns an integer
corresponding to the value of the numeric string.

(string->integer "143") ==> 143

(integer->string <number>)
Integer to ASCII convertion. Returns a string
with the ASCII representation of the integer.

(integer->string 678) ==> "678"

(real->string <number> <width> <precision> <leading 0s>)
Float to ASCII convertion. Returns a string
with the ASCII representation of the float.

<width> is the number of characters in the output string
<precision> if the number of decimal places.
if <leading 0s> is eq to t then the number

> (real->string 50.0 3 0 #t)
050
> (string? (real->string 678))
#t

(system <program> <arg> <arg> ....)
This function allows you to call another program
from within rtlisp. The result depends upon the base
operating system. In general it calls execv().

(system "emacs" "/usr/bill/lisp/man.txt")

(getenv <string>)
This function returns the value of the environment variable
named by <string>, or NIL if it is absent.

(get-decoded-time)
This routine reads the computer's clock and returns
the time and date. The return value is a list of
integers in the following format:

(second		; 0-59
minute 		; 0-59
hour 		; 0-23
date 		; 1-31
month		; 1-12
year 		; two digits
day-of-week	; 0-6 where 0 = Monday
daylight-saving ;
)

NB
The ATARI-ST clock only ticks every 2 seconds!

(get-decoded-time) ==> (11 20 21 1 7 92 3)

(get-universal-time)
This routine gets the number of seconds since the epoch (Jan 1
00:00:00 GMT 1970). It returns a float because integers are too
small to contain the value. Therefore the value doesn't change
very often!

(command-line)

Get the command line.  The global variable *argv* also lists
the command line.

Debugging Functions

(room)
the version number and memory usage. Memory is
allocated from a fixed-size pool, when that becomes
full, memory is acquired from the operating system
heap via malloc(). The behaviour of the operating
system determines what happens when the heap is
all used up. ATARI-TOS aborts the program!
The program uses a lot of stack (16,384 bytes on the
ST, 64K on MS-DOS).

(trace <arg>)
(trace 1) instructs the interpreter to print every
argument to the main evaluation functions. The
return values are not printed. (The return values
from most executions of "eval" and "apply" will
usually appear as arguments to subsequent calls
to these functions.)

(trace 0) switches tracing off.

(trace <symbol-function>)
This is defined in init.l, and prints the call and return of
lambda functions. See init.l for details.

> (trace our-function)

(untrace <symbol-function>)
Removes the effects of (trace). init.l for details.

Extensions to rtLisp

(extensions <boolean>)
This function switches on Bill Birch's extensions to rtlisp if <boolean>
is T, and switches them off if NIL. The extensions activated are:

(apply): Before apply attempts to apply its functional argument to
the actual argument list, it checks to see if there exists a symbol
whose PNAME is of the form (<func> <actuals). If there is,
(apply)
evaluates the symbol instead of normal application. The symbol
value is returned. This extension permits memoisation of functions,
and allows a more functional programming style. for example:

(extensions #t)			; activate extensions
; handy function to create symbols which look like
; function applications
(def assert (form result)
(set (set-symbol form) result))

; Fibonnacci Series
(def fib (n)
; Note total lack of COND statements !!
(+ (fib (- n 1)) (fib (- n 2))) )

; Declare the terminating conditions of fibonacci series.
; These are found by APPLY in preference to an application.
(assert `(,fib 1) 1)
(assert `(,fib 0) 1)

;; Here is a memoised version of the fibonnacci series
;; which is very much faster than (fib)
(def fib-fast (n)
; The assert statement saves the result for
; future executions of APPLY
(assert (list fib-fast n)
(+ (fib-fast (- n 1)) (fib-fast (- n 2))) ))

(assert `(,fib-fast 1) 1)
(assert `(,fib-fast 0) 1)

History & Design Notes

This interpreter started out conforming to Standard Lisp.  The family
of lisp dialects can be viewed to be close since the fundamental lisp
functions can be formulated in list processing functions using car, cdr
and cons.  So rtlisp is moving to use the Scheme dialect of lisp.

The fundamental design rules in force during the development of this
interpreter has been the use of reference counting instead of mark and
sweep garbage collection.  The future version of this interpreter will
use a concurrent for of incremental mark and sweep garbage collection.
Reference counting will be replaced.

Here is a list of the design goals:

1	The cell manipulation code, see the lisp.h code, is made
as simple and efficient as possible for self-study.

2	In the spirit of lisp, only one data type is permitted, the Cell
structure.  All data is stored in the subfields of the "cons" cell.
This prevents list manipulation code from being repeated for
different data types.

3	The 'C' source code of rtlisp should function as much as possible
like lisp (in spirit) itself which primarily manipulates linked
list structures.

4	Garbage collection will be done using concurrent mark & sweep
to do real-time list processing.

Reference

  Symbol Manupulating Language--~Memo 4--Revlsions of the Language
by John McCarthy,
[http://www.softwarepreservation.org/projects/LISP/MIT/AIM-004.pdf]

     Timothy P. Hart and Thomas G. Evans, "Notes on Implementing Lisp
for the M-460 Computer", in "THE PROGRAMMING LANGUAGE Lisp: Its Operation
and Applications", Information International Inc. March 1964.

[http://www.softwarepreservation.org/projects/LISP/book/III_LispBook_Apr66.pdf]

The above reference, , is on page 191 of the LispBook_Apr66.

     Arthur Norman and Gillian Cattell, "Lisp on the BBC
Microcomputer", Acornsoft, 1983.

 was used in the development of eval and read. Examples are also taken
from .

Appendix

I'm studying this code to make it much more efficient.  Then maybe
implement an incremental concurrent mark and sweep garbage collector.

```
{"ft_lang_label":"__label__en","ft_lang_prob":0.7891805,"math_prob":0.9071942,"size":38376,"snap":"2023-40-2023-50","text_gpt3_token_len":10044,"char_repetition_ratio":0.15719795,"word_repetition_ratio":0.08369431,"special_character_ratio":0.28697625,"punctuation_ratio":0.1307568,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.98234177,"pos_list":[0,1,2],"im_url_duplicate_count":[null,1,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-09-27T14:48:48Z\",\"WARC-Record-ID\":\"<urn:uuid:72c33500-98d0-4d68-a1c0-9c7bf0bc5e38>\",\"Content-Length\":\"45739\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:2650e4c5-9bc3-4776-bf27-d59075ef6a83>\",\"WARC-Concurrent-To\":\"<urn:uuid:7fc0e727-29b1-486b-96d8-b4c23389f2de>\",\"WARC-IP-Address\":\"35.212.73.244\",\"WARC-Target-URI\":\"https://neuralmachines.com/software/rtlisp.html\",\"WARC-Payload-Digest\":\"sha1:ZB3XJ6DTJVGOJKIVMUIATUDXDUCY5IUL\",\"WARC-Block-Digest\":\"sha1:2HMTMRNLJRHT7RHZE2SEGM7WAAUU66F4\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-40/CC-MAIN-2023-40_segments_1695233510300.41_warc_CC-MAIN-20230927135227-20230927165227-00142.warc.gz\"}"}