Chapter 6
A SOOP window is created by executing
the file "launcher.s" in DrScheme.
In the MuLE interface window that appears, click on the "SOOP -
functional" button or select from the pull-down menu. This opens a SOOP window by binding a
variable to the result of a call to the procedure make-SOOP. Once in the
SOOP environment, existing SOOP program files can be opened and loaded into the
simple editing window of the SOOP interpreter by selecting the “open”
button. The opened file will appear in
the upper window and may be modified before executing with the SOOP
interpreter. Everything typed in the
lower window will be interpreted as an expression by SOOP.
The SOOP interface is a double paned
window. Both the upper definitions
window and the lower interface window can be used to enter in programs, though
it is recommended that the definitions window be used for this purpose. The interface window accepts one expression
at a time and executes it when the enter key is hit, whereas the definitions
window allows for several expressions on different lines to be entered at
once. They will only be executed when
the "execute" button is clicked.
All of the output will appear in the interface window. Besides this benefit, the definitions window
allows for the saving and retrieving of files, opposed to the interface window
which does not. If the user wishes to
alternate between the two, bear in mind the environment, or list, that has been
created is used by, and thus is changed by, either window.
At the command level, SOOP understands
three meta-commands: list, help and clear. Each command is executed in SOOP by entering
the command, without parentheses, at the SOOP prompt.
list A debugging
instruction that will list all of the environment (current variable) bindings.
clear Clears the
environment (current variable) bindings.
This is especially useful between program executions.
help Displays the
SOOP grammar, i.e. valid SOOP expressions.
There
are only two legal operations in the SOOP environment, binding a variable to an
instantiation of an object (via the assign
keyword) and sending a message to an object (via the send keyword). Examples are
the following:
(assign
x make-box)
(send x msg)
Where
msg is a legal
message for the class box.
Simplistic
comments are allowed in SOOP programs. If the first two characters on a line of a SOOP program are // then the line is ignored by the SOOP interpreter. There can be no white space or other
characters before the //, i.e. the // must be in columns one and two of the line.
6.3 Classes
There
are currently 7 classes recognized in SOOP:
·The class box (a variable)
·The class block (a set of messages)
·The class if (a form of if expression)
·The class loop (a form of while expression)
·The class stack (a stack)
·The class queue (a queue)
·The class array (an array)
Classes
may be instantiated but not created through the run-time environment. To create a new class in SOOP, a new class (really
a function that returns a function) must be added to the file “SOOPObj.s”, and
the class name must be added to the list MAKEWORD which is
defined as a local variable at the beginning of the SOOP function. All class names must begin with the word make-.
Thus the seven listed classes have the names: make-box, make-block, make-if, make-loop, make-stack, make-queue, and make-array.
6.4 Objects
Objects
are instantiated through the assign keyword. To create an instantiation one must assign a
name to the class name. To create two
instantiations of a box, for example, the following commands would be used:
(assign
x make-box)
(assign y make-box)
When
these commands are entered two different windows will appear on the screen, one
for x and one for y. They will both be
box objects.
Every
object is represented in SOOP by a text window. These windows may be written into, but the act of writing in a
box does NOT change the values stored in the object. To change the state of an object, one must send the object
messages (see below). The text windows
are only meant to provide a visual representation of the state of an object.
Multiple
messages can be cascaded, but parentheses are not allowed. Thus and a box object may be sent the
message (send x + send
y * 3)
which is interpreted as (send
x + (send y * 3)). However, the latter
message would result in an error because parentheses are not allowed.
Different
objects recognize different messages, but to send a message the keyword send must be used. The syntax for sending a message is:
(send
x msg)
where
x is a name
given to an instantiation of an object and msg is a legal
message for that object.
Every
SOOP object recognizes the following messages:
type returns
the class of the object as a string.
empty? Returns
true if the value (for boxes), test condition (for select/loop classes), block,
queue, stack, or array is empty.
print prints
the value of all values, expressions, or messages contained in the object.
6.4.1 The Box Object
Boxes
provide variables to the SOOP environment.
A box object stores a numerical value and accepts certain messages that
allow manipulation of their value. In
particular, a box understands the following messages:
type returns “box”.
empty? returns
true if there is no value stored in the box and false otherwise.
set-name<msg> sets the name
of the window to “msg”
get returns the value stored in the box.
set-val<expr> executes the expression <expr> and sets the value of the box to the result.
<arith_op> msg | obj performs one of + - * / > < on the result of the evaluating
message, msg or on getting the value from the object obj. Note that an object name can be used without
the formal message pattern of send obj get.
This is an exception to the requirement that all messages be sent with
an explicit send. A simple binary
operation can also be used here without the formal send syntax, i.e.
(send x + y)
is
a legal message and is interpreted as
(send x + send y get)
Messages
can be cascaded as mentioned above, though parentheses are not allowed.
Examples of
box commands include the following:
(assign x make-box)
(send x set-name var1)
(send x set-val 10)
(assign y make-box)
(send y set-name var2)
(send y set-val 5)
(assign z make-box)
(send z set-name var3)
(send z set-val send x + y)
(send z set-val send x + send y * z)
Note
in the penultimate expression, the box named z gets the value 15. In the last expression, the z box gets the
value 85.
6.4.2 The Block Object
Block
objects store a sequence of messages.
When the block is executed, each message is sent sequentially.
To create a
block object the assign syntax is used.
For example, the expression
(assign
blk1 make-block)
creates
an instance of the block object with the name blk1. There are, at this time, no messages in the block. These messages can be added by sending the add-expression message and
deleted by sending the delete-expression message as
described below.
The
legal messages for a block are as follows:
type returns
“block”.
empty? returns
true if there is nothing in the block.
set-name<msg> sets the name of the window to “msg”.
add–expression<msg> adds the expression “msg” to the end
of the end of the block of messages to be executed.
delete–expression<msg> deletes the last expression from the
block.
empty–all sets the block to empty.
execute executes
the messages in its block one at a time.
Examples
of legal messages for a block include the following:
(assign
blk1 make-block)
(send
blk1 set-name new-block)
(send
blk1 add-expression send x set-val 3)
(send
blk1 add-expression send y set-val 23)
(send
blk1 add-expression send z set-val send x + y)
(send
blk1 execute)
(send
blk1 delete-expression)
(send
blk1 execute)
6.4.3 The If
Object
If
objects contain a test message, a true message and a false message. The true and false messages may be
blocks. To create an if object
instantiation, the assign syntax is used with the make-if procedure. For example:
(assign
if1 make-if)
At
this point the name if1 is bound to
an instance of the if object. None of
the messages (test, true, false) has been initialized yet. Before the if object can be used, each of
these messages must be initialized (see below). Once the test message has been initialized, the if object can be
executed by passing the object the message execute. For example, the if1 object can be executed
by the syntax:
(send
if1 execute)
Both
true and false messages are optional.
The
legal messages for an “if” object are as follows.
type returns
“if”.
empty? returns
true if object’s test condition contains the symbol ‘empty.
set-name<msg> sets the name of the window to “msg”.
add-test <expr> adds the expression <expr> as
the test condition.
add-true <expr> adds the expression <expr> as
the true condition.
add-false<expr> adds the expression <expr> as
the false condition.
empty-all sets
all conditions and expressions to empty.
execute executes
the test condition by sending the appropriate message. If the
result is “true”, the true message is
sent, otherwise the false message is
sent.
Examples
of legal “If” object syntax include the following:
(assign
if1 make-if)
(send
if1 set-name new-if)
(send
if1 add-test send x < 3)
(send
if1 add-true send y set-val 23)
(send
if1 add-false send z set-val send x + y)
(send
if1 execute)
(assign
blk1 make-block)
(send
if1 add-true blk1)
Note
that the penultimate statement above creates a block object. The final statement sets the true condition
of the “if“object to be the block.
6.4.4 The Loop
Object
Loop
objects contain a test message and a body message (which may be a block). When a loop object receives the message execute, the test message (which must be
a message that begins with a send) is sent and,
if the result is “true”, the message(s) in the body are sent. The test message is then sent again and, if
the result is again “true”, the body message(s) are again sent. This continues until the test message
returns “false”.
Loop
objects are created using the assign syntax.
To create a loop named lp1 the following expression could be entered in
SOOP:
(assign
lp1 make-loop)
At
this point the loop is uninitialized.
To initialize the loop, the message add-test and add-body can be used as described
below. The body is optional. To execute the loop, the loop object must be
sent the message execute:
(send
lp1 execute)
Valid
loop messages are as follows.
type returns
“loop”.
empty? returns
true if the test condition contains the symbol ‘empty.
set-name<msg> sets the name of the window to “msg”.
add-test
<expr> adds the expression <expr> as
the test
condition.
add-body
<expr> adds the expression <expr> as
the
body.
add-false<expr> adds the expression <expr> as
the false condition.
emtpy-all sets
all conditions and expressions to empty.
execute executes
the test condition by sending the appropriate message. If the
result is “true”, the body message is sent, otherwise execution halts.
Examples
of syntax:
(assign
loop1 make-loop)
(send
loop1 set-name new-loop)
(send
loop1 set-name new-loop)
(send
loop1 set-body send x set-val send x – 1)
(send
loop1 execute)
6.4.5 The
Queue Object
A
queue object is a list in which elements are entered one at a time through one
end and removed in the same order they were entered. In other words, the first element entered in the queue will be
the first element that can be removed from the queue.
To
create a queue object instantiation, the assign syntax is used with the make-queue
procedure. For example:
(assign
myqueue make-queue)
At
this point the name myqueue is bound to an instance of the queue object. The queue is completely empty at this
point. The queue object executes
multiple messages. It accepts the
following messages:
type returns
“queue”.
empty? returns
“true” if the queue is empty.
set-name<msg> sets the name of the window to “msg”.
enqueue<msg> adds the message "msg" to
the end of the end of the list of messages to be executed.
dequeue deletes
the first expression from the queue.
atfront gets the
first expression from the queue.
emtpy-all sets
queue to empty.
Examples
of syntax:
(assign
myqueue make-queue)
(send
myqueue enqueue 'a)
(send
myqueue enqueue 3)
(send
myqueue dequeue)
(send
myqueue atfront)
(send
myqueue dequeue)
6.4.6 The
Stack Object
A
stack object is a list in which elements are entered one at a time through one
end and removed in the opposite order they were entered. In other words, the last element entered in
the stack will be the first element that can be removed from the stack.
To
create a stack object instantiation, the assign syntax is used with the make-stack
procedure. For example:
(assign
stk1 make-stack)
At
this point the name stk1 is bound to an instance of the stack object. The stack is completely empty at this
point. The stack object executes
multiple messages. It accepts the
following messages:
type returns
“stack”.
empty? returns
“true” if the stack is empty.
set-name<msg> sets the name of the window to “msg”.
push <msg> puts the message "msg" to
the end of the end of the list of messages to be executed.
pop deletes
the last expression from the stack.
top gets the last expression in the
stack.
empty-all sets
the stack to empty.
Examples
of syntax
(assign
stk1 make-stack)
(send
stk1 push 'a)
(send
stk1 push 3)
(send
stk1 pop)
(send
stk1 top)
(send
stk1 pop)
6.4.7 The
Array Object
An
array object is a static list of elements that can be accessed using an index
number. To create an array object
instantiation, the assign syntax is used with the make-array
procedure. For example:
(assign
array1 make-array)
At
this point the name array1 is bound to an instance of the array object. The array is completely empty at this
point. The array object executes
multiple messages. It accepts the
following messages:
type returns
“array”.
empty? returns
“true” if the array is empty.
set-name<msg> sets the name of the window to “msg”.
set-size<num> sets the size of the array.
add<msg><num> adds the “msg” to the “num” position
in the array.
get<num> gets the msg at the “num” position
of the array.
empty-all sets the array to empty.
Examples
of syntax:
(assign
array1 make-array)
(send array1 set-size 5)
(send array1 add 5 4)
6.5 A Complete BNF
Grammar for SOOP
|
<soop> |
:
: = |
<soop_command> |
|
<soop_command> |
:
: = |
help |
clear | list
| <soop_stmt_list> |
|
<soop_stmt_list> |
:
: = |
<soop_stmt> |
<soop_stmt> <soop_stmt_list> |
|
<soop_stmt> |
:
: = |
(
assign <id> <makes> )
| ( send <id>
<obj> ) |
|
<makes> |
:
: = |
make-block | make-stack | make-if | make-loop | make-box | make-queue | make
– array |
|
<obj> |
:
: = |
<obj_expr> |
<obj_msg> |
|
<obj_expr> |
:
: = |
<block_expr> | <stack_expr> | <if_expr> | <loop_expr> | <box_expr> | <queue_expr> | <array_expr>
|
|
<obj_msg> |
:
: = |
<block_msg> | <stack_msg> | <if_msg> | <loop_msg> | <box_msg> | <queue_msg> | <array_msg>
|
|
<block_msg> |
:
: = |
set-name
<id> | reset | empty
–all | <set_expression>
<block_msg> | delete-expression | <set_execute>
<block_msg> |
|
<block_expr> |
:
: = |
type |
empty? |
|
<set_expression> |
:
: = |
add-expression
<block> | add-expression
send <id> <obj> |
|
<set_execute> |
:
: = |
send
<id> execute |
|
<block> |
:
: = |
<block_msg> |
<block_expr> |
|
<stack_msg> |
:
: = |
set-name
<id> | push
<obj_expr> reset | pop | empty-all
|
|
<stack_expr> |
:
: = |
top |
type | empty? |
|
<if_msg> |
:
: = |
set-name
<id> | <set_test>
<if_msg> | reset | <set_true>
<if_msg> | <set_false>
<if_msg> | <set_execute>
<if_msg> | empty-all |
|
<if_expr> |
:
: = |
type |
empty? |
|
<set_test> |
:
: = |
add-test
<bool_expr> |
|
<set_true> |
:
: = |
add-true
send <id> <obj> | add-true
<block> |
|
<set_false> |
:
: = |
add-false
send <id> <obj> | add-false
<block> |
|
<loop_msg> |
:
: = |
set-name
<id> | empty-all | reset | <set_test>
<loop_msg> | <set_body>
<loop_msg> | <set_execute>
<loop_msg> |
|
<loop_expr> |
:
: = |
type |
empty? |
|
<set_body> |
:
: = |
add-body
send <id> <obj> | add-body
<block> |
|
<box_msg> |
:
: = |
set-name
<id> | set-val
<number> | reset
|
|
<box_expr> |
:
: = |
type |
empty? | get
| send <id> <op>
<obj_expr> |
|
<op> |
:
: = |
+ |
- | * | /
| > |
< | |
|
<queue_msg> |
:
: = |
set-name
<id> | enqueue
<obj_expr> | reset | dequeue | empty-all
|
|
<queue_expr> |
:
: = |
atFront |
type | empty? |
|
<array_msg> |
:
: = |
set-name
<id> | add
<obj_expr> <number> | reset | set-size
<number> | empty-all
|
|
<array_expr> |
:
: = |
type |
empty? | get <number> |
6.6 Also See
References Attached.