10.4 Functions for Reading
10.4.1 Reading S-Expressions
(channelread CHAN:io-channel): any expr
Reads and returns the next S-expression from input channel CHAN.
Valid input forms are: vector-notation, dot-notation, list-notation, numbers,
strings, and identifiers. Identifiers are interned (see the intern function in
Chapter 4), unless the fluid variable *compressing is non-nil. Channelread
returns the value of the global variable $eof$ when the end of the currently
selected input channel is reached.
(de channelread (ch)
(let ((currentscantable⋆ lispscantable⋆)
(currentreadmacroindicator⋆ 'lispreadmacro))
(channelreadtokenwithhooks ch)))
Channelread uses the function channelreadtokenwithhooks. Tokens are scanned within the
context of the scan table bound to lispscantable*. The scan table is used to recognize special
character types, for example, delimiters like (, ), and space. The read macro mechanism is used
to parse s-expressions (see section 12.4.5 for more information on read macros). PSL uses a
number of read macros which are described below.
( | S-expressions are gathered into a list until the matching right
parenthesis is read. Both list and dot notation are recognized. A pair or
list is returned. |
) | If a right parenthesis is read and a matching left parenthesis had not
been previously read then it will be ignored. |
[ | S-expressions are gathered into a vector until a matching right bracket
is read. A vector is returned. |
’ | The next s-expression read is quoted, the result is of the form (QUOTE
S-EXPRESSION). |
(char eof) | If an end of file character is read while a list or vector is being
constructed then the following error will occur. ***** Unexpected EOF
while reading on channel. |
‘N’ | Otherwise the value of eof is returned. |
|
The following read macros are defined in the useful module.
# | this is like the quote mark ’ but it is used for function instead of
quote. For example #’name reads as (FUNCTION NAME). |
#/ | this returns the numeric form of the following character read
without raising it. For example #/a is 97 while #/A is 65. |
#\ | This is a read macro for char (see Chapter 6 for more information).
Note that the argument will be raised if *raise is non-nil. For
example, #\a = #\A = 65. |
#. | This causes the following expression to be evaluated at read time.
For example, ‘(1 2 #.(plus 1 2) 4) reads as (1 2 3 4). |
#+ | The next two expressions are read. If the first is a system name
which is the current system then the second expression is returned.
Otherwise another expression is read and it becomes the value
returned. |
#- | The next two expressions are read. If the first is a system name
which is not the current system then the second expression is
returned. Otherwise another expression is read and it becomes the
value returned. |
|
10.4.2 Reading Single Characters
(readchar): character expr
(channelreadchar CHANNEL:io-channel): character expr
Reads one character (an integer) from CHANNEL. All input is defined
in terms of this function. If CHANNEL is not open or is open for writing
only, an error is generated. If there is a non-zero value in the backup buffer
associated with CHANNEL, the buffer is emptied (set to zero) and the value
returned. Otherwise, the reading function associated with CHANNEL is
called with CHANNEL as argument, and the value it returns is returned by
channelreadchar.
⋆⋆⋆⋆⋆ Channel not open
⋆⋆⋆⋆⋆ Channel open for write only
(channelreadch CHAN:io-channel): id expr
Like channelreadchar, but returns the id for the character rather than its
ASCII code.
(unreadchar CH:character): Undefined expr
(channelunreadchar CHAN:io-channel CH:character): Undefined expr
The input backup function. Ch is deposited in the backup buffer associated
with Chan. This function should be only called after channelreadchar is
called, and before any intervening input operations, since it is used by the
token scanner. The unread buffer only holds one character, so it is generally
useless to unread more than one character.
10.4.3 Reading Tokens
The functions described here pertain to the token scanner and reader. Globals and switches used
by these functions are defined at the end of this section.
(channelreadtoken CHANNEL:io-channel): {id, number, string} expr
This is the basic PSL token scanner. The value returned is an item
corresponding to the next token from the input stream. An id will be interned
unless the switch
*compressing is non-nil. If *compressing is t then the
print name of the id is passed to newid, otherwise it is passed to intern.
The global variable toktype* is set as follows.
0 | if the token is an ordinary id, |
1 | if the token is a string, |
2 | if the token is a number, or |
3 | if the token is an unescaped delimiter such as |
| ”(”, but not ”!(” In this last case, the value |
| returned is the id whose print name is the |
| same as the delimiter. |
|
The precise behavior of this function depends on two fluid variables:
Currentscantable* is bound to a vector known as a scan table. Described below.
Currentreadmacroindicator* is bound to an id known as a read macro indicator. Described
below.
(ratom): {id, number, string} expr
Reads a token from the current input channel.
(channelreadtokenwithhooks CHANNEL:io-channel):any expr
This function reads a token and performs any action specified if the
token is marked as a read macro under the current indicator. Read
uses this function internally. Uses the variable currentreadmacroindicator*
urrentreadmacroindicator* to determine the current indicator.
10.4.4 Reading Entire Lines
(readline): string expr
Same as (channelreadline in*)
(channelreadline CHANNEL:io-channel): string expr
A string is returned which contains each character from the current position
of the scanner to the next end-of-line or end-of-file character.
10.4.5 Read Macros
At the top level of PSL, an expression is read, it is evaluated, and then the result is printed.
Normally a macro is expanded during evaluation. The read macro is a different type of macro,
it is expanded during the reading phase. When the reader encounters a read macro
character, the the macro is executed and the result is inserted in place of the read macro
character.
A read macro must be a function of two arguments, the first should represent a IO channel, the
second a character. A character which represents a read macro must be set to one of two types in
the scan table. It may be either a delimiter or a diphthong. Diphthong corresponds to double
character read macros, delimiter to single character read macros. In addition, the id which
corresponds to the character must have a reference to the name of the function on its property
list. For a diphthong the indicator must be lispdiphthong, for a delimiter it must be
lispreadmacro.
The quote macro may be defined as follows. Note that we cannot use ’form in place of (quote
form) until we have defined the read macro.
(de doquote (channel ch)
(list (quote quote) (channelread channel)))
(put (quote !') (quote lispreadmacro)(function doquote))
(putv lispscantable⋆ (char !') delimiter)
This says that when a single quote is read, PSL should replace it with a list consisting of quote
and the next expression in the input (obtained by an explicit call to channelread). Since defining
a character as a read macro makes it difficult to use the character in a normal way, read macros
should not be letters or digits.
10.4.6 Terminal Interaction
(yesp MESSAGE:string): boolean expr
If the user responds y or yes, yesp returns a non-nil value. A response of n or
no results in a value of nil. It is possible to enter a break loop by responding
with b. After quitting the break loop, one must still respond y, yes, n, or no.
10.4.7 Input Status and Mode
promptstring* = [Initially: ”x lisp
>”]
global
Displayed as a prompt when any input is taken from TTY. Prompts should
therefore not be directly printed. Instead the value should be bound to
promptstring*.
*eolinstringok = [Initially: nil]
switch
If *eolinstringok is non-nil, the warning message
⋆⋆⋆ String continued over end-of-line
is suppressed.
*raise = [Initially: t]
switch
If *raise is non-nil, all characters input for ids through PSL input functions
are raised to upper case. If *raise is nil, characters are input as is. A string
is unaffected by *raise.
*compressing = [Initially: nil]
switch
If *compressing is non-nil, channelreadtoken and other functions that call it
do not intern ids.
currentscantable* = [Initially: NIL]
global
This variable is set to lispscantable* by the function read
currentreadmacroindicator* = [Initially: NIL ]
global
The function read binds this variable to the value LISPREADMACRO.
Its value determines the property list indicator used in looking up read
macros. The user may define a set of read macros using some new indicator
and rebind this variable. Ordinary read macros may be added by putting
properties on ids under the LISPREADMACRO indicator.