Back to index

LispMe syntax

Syntactic elements

Identifiers

Identifiers (atoms) are similar to identifiers in other programming languages, but they may consist of a larger set of characters. Allowed characters are: A symbol can consist of upto 256 characters from the above set with the exception that tokens starting with a digit or + or - followed by a digit are interpreted as numbers.

Using the option Case-sensitive symbols you can determine, if symbols are case-insensitive or not. Case-insensitive symbols are generally converted to lower case. Unfortunately this doesn't apply to accented/national characters, as the Pilot ROM routines don't convert these characters.

Numbers

LispMe supports integer, real and complex numbers. Any number entered which is too large to represented as a 15 bit signed integer (-16384 to 16383), is automatically converted to floating point.

LispMe supports inputting decimal numbers only. It accepts real numbers according to this grammar:

real     ::= [sign] ureal.
ureal    ::= mantissa [exponent].
sign     ::= '+' | '-'.
mantissa ::= digit+ ['.' digit*]
           | '.' digit+.
exponent ::= ('e' | 'E') ['+' | '-'] digit+.
Real numbers are represented in IEEE-754 64 bit double precision format, which means about 15 decimal digits accuracy.

Complex numbers can be written according to this grammar:

complex  ::= real
           | real sign ureal 'i'
           | real 'i'
           | sign 'i'
           | real '@' real.
The @-syntax denotes complex numbers in polar form, left to the @ is the magnitude, right is the angle.

LispMe does not support the exactness property required by R4RS, nor does it support big integers or rationals.

Characters

Character objects are denoted by prefixing the character with #\. LispMe doesn't know special character names like #\space and #\newline, but you can create those values with the integer->char function or use the hex syntax, which is an extension to R4RS: Two hash chars ## followed by two hexadecimal digits (0-9, a-f) denote a character whose code is the value of the two hex digits given.

Examples

#\ü denotes the lower case german character ü (u umlaut)
##0a denotes the carriage return/linefeed char on the pilot

Strings

Strings are sequences of characters enclosed within double quotation marks ". Any character from the Pilot char set can be written in a string with three exceptions: These characters in a string must be preceeded by a backslash \. The # syntax is a LispMe extension, which allows an arbitrary character to be included in a string. After the # exactly two hexadecimal digits (0-9, a-f) are expected, which denote the character to be included.

In contrast to C or C++, you can have #00 bytes in a string.

Example

"a\\#0aa\#" denotes a string consisting of letter a, backslash, linefeed (hex 0a), letter a, hash sign.

Other literals

There're 3 special literals all beginning with a hash sign #

Pairs and lists

A pair (or dotted pair) is a data structure consisting of two components, called the car and the cdr. A pair consisting of the car component a and the cdr component b is written (a . b). If one of the components is a number, you should write a space character between the number and the dot to avoid confusion with a decimal point. LispMe's scanner munches as much input as possible when recognizing tokens, so be picky with spaces, especially with dotted pairs/floating point numbers. Notice the difference:

(a.1) is read as (a 0.1) (list)

(a. 1) is read as (a . 1) (dotted pair)

A list is either a special value () called the empty list, or a pair, whose cdr component is a list, for example (1 . (2 . (3 . ()))) There's also a shorter syntax for lists which omits both the dot and the parentheses around the cdr component, so this example can also be written (1 2 3). Lists of these form (the last cdr is the empty list) are called proper lists. Improper lists don't have the empty list as their last cdr, like (1 . (2 . (3 . 4))), which can be written as (1 2 3 . 4), too. It's an error to write more than one dot in a list.

Vectors

Vectors are sequences of arbitrary objects, which can be accessed by an integer index in constant time. Vector constants are written like lists, but they start with #( and are terminated by ). In contrast to lists, there are no "dotted" vectors. In contrast to R4RS, vector constants need not to be quoted in LispMe.

Comments

A semicolon ; starts a comment. All characters following it upto the end of the current line are ignored. Note that there must be a hard line feed (Graffiti stroke downward slash), word wrapping to the next line is not considered a line feed.

The LispMe Reader

Anything after a complete expression is ignored by the reader and any incomplete expression is automatically completed with closing parentheses. So

(+ 3 (* 7 4)) (foo bar) quux

and

(+ 3 (* 7 4

both read as (+ 3 (* 7 4)) and evaluate to 31.

When loading memos, (begin is stuffed into the read buffer before the actual memo contents is read, so a source memo must be a sequence of define expressions not enclosed in parentheses. Instead, the outermost list is automatically completed by the loading mechanism.

Valid LispMe expressions

LispMe expressions (programs, see here) are in fact nested lists and may be viewed as data, too, but not all nested lists are valid programs. LispMe programs must follow this grammar:
expression   ::= literal
               | identifier
               | special_form
               | application
               | (quasiquote qq-template)
               | `qq-template

literal      ::= number
               | character
               | string
               | #f | #t | #n | '()
               | #( object* )
               | (quote object)
               | 'object

special_form ::= (keyword component*)

application  ::= (expression+)

qq-template  ::= object including unquote and
                        unquote-splicing special forms
object means the written representation of any LispMe object and component is a syntactic component different for (and described at) each keyword in the LispMe catalog. This grammar is ambiguous due to special forms, but this ambiguity is resolved by reserving names used as keywords in special forms. A qq-template may be any LispMe object but is most commonly a list or vector, which may contain unquote and unquote-splicing special forms.

Printing of objects

Symbols

Symbols are printed in lower-case. There's no escape mechanism for funny characters in symbols, as these cannot be input or generated.

Numbers

Numbers are printed in decimal without leading zeros. If floating point numbers don't have decimal places, the decimal point is omitted, too. At most 15 decimal places are printed where the last decimal digit may not be rounded correctly. Exponential notation is used for numbers larger than 1015 or smaller than 10-4. (similar to the C format string "%.15g")

Complex numbers always print in rectangular form, where the real and imaginary part are both printed as described for real numbers.

The special real values infinity, -infinity and not-a-number print as [inf], [-inf] and [nan]. A complex number having an infinite component prints as [cinf] (complex infinity).

Characters

display and write print characters differently. write prefixes a character with #\ or uses ## for characters with ASCII codes <32 and display just prints the character itself.

Strings

display and write print strings differently. display just prints the contents of the string without any escape chars and without double quotes. write encloses the string in double quotes and escapes the characters ", \ and # with a backslash \ and writes all characters with ASCII codes <32 in hex notation.

Pairs and lists

The dot notation is avoided whenever possible. To avoid stack overflow in the printer, deeply nested lists (the limit in configurable in the preferences dialog) print as [deep]. Expressions which are to long for the output are abbreviated with ... and a warning is given.

By selecting the option Print quotes, you can make LispMe print quote-expressions in the abbreviated form.

Vectors

Vectors are printed using the standard syntax #( ... ). The depth limit (like with lists) applies to vectors, too.

Closures

Closures print as [clos n], where n indicates the number of arguments See lambda for more info.

Continuations

Continuations (see call/cc) print as [cont].

Promises

Promises (see delay) print as [prom].

Ports

Output ports print as [outport] and input ports as [inport n], where n is the current read position from the beginning of the memo. The special end-of-file object (returned by read, for example) prints as [eof].

Macros

Macros (see here) print as [macro].

Summary of specially printed objects

[-inf]negative infinity
[cinf]complex infinity
[clos n]closure
[cont]continuation
[deep]deeply nested list or vector
[eof]end-of-file object
[inf]positive infinity
[inport n]input port
[macro]macros
[nan]not a number
[outport]output port
[prom]promise
#na symbol created by gensym