JaM


Introduction

This document is a brief description of a Mesa based interactive programming environment called "JaM". In this document three general topics will be discussed: What JaM is; what applications lend themselves to the use of JaM; and how JaM interacts and is used with Mesa.

Basic Operation

To answer the question: "What is JaM?", several properties of the system will be discussed.

1. JaM implements a basic stack oriented, virtual machine. This machine operates on entities called "objects" which are found on one or more of the machine’s three stacks. In a common sense sort of way JaM can be thought of as an extremely flexible programmable Hewlett Packard type calculator that can handle a wide variety of objects in a powerful way.

2. An integral part of the JaM machine is a virtual memory system that has addressing capacity of 2
24 words. This virtural memory is used to store various definitions and objects created by the user.

3. An interactive user interface to the JaM machine is provided. The interface is implemented as a language having a simple syntax. This language is interpreted by a scanner and transformed into a sequence of objects that are, in turn, executed by the JaM machine.


The JaM machine basically consists of its virtual memory, three stacks, and the instruction set. The three stacks are: The operand stack, the dictionary (or context) stack, and the execution stack. Under most circumstances the user is concerned only with the operand stack. The description of the dictionary stack can be put off until later, although the understanding of its function and use is important. The function of the execution stack need not be of direct concern to the user. However it is required for the internal execution control of the machine.

When the JaM machine is in its initial state, the operand stack is empty, the dictionary stack contains one dictionary called the system dictionary, and the machine is executing the keyboard stream (waiting for the user to type something.) As the user types, the characters are buffered until a carraige return is typed. At this point the line is passed to the JaM scanner to be broken into tokens. The tokens are converted into objects and executed in the order they are delivered to the JaM machine.

To understand what happens when the user types it is important to understand what the scanner recognizes, and what objects are generated for execution.

There are three kinds of things recognized by the scanner and converted into objects. These are: numbers, strings, and identifiers.

Numbers are of three types: integers, reals, and long integers.

23 -465--Examples of integers.
-23.4 1. 0.00034--Examples of reals.
-123456 and 1000000--Examples of long integers.

Strings are enclosed in balanced parentheses. For example:

(Hello. How are you)

(strings may consist
of more than one line
of information)

(strings may (contain nested (balanced parentheses)))

(strings may contain all manner of garbage @#$$$%%~~~&&**~%$$1233;;;
except for unbalanced parens)

(Strings may contain as many as 32767 characters)

Identifiers consist of any string of characters not containing parentheses, spaces, commas, or carraige returns. For example:

.add
.print
abc
$$$
123a
abc.111
-.aaa

are all examples of valid identifiers.


When the scanner encounters something that it recognizes, it converts it into an object. In the case of numbers, the scanner converts the number into: a integer object, a long integer object, or a real object based on the syntax or length of the number. In the case of strings, the scanner creates a string object. When the scanner encounters an identifier, it "looks up" the identifier using the dictionary stack as a context (described later), and uses the associated object.

As each object is generated by the scanner, it is passed to the JaM machine for execution.

To see how this all works, several simple examples will be given.

Example 1.

Suppose I type the following:

123 456 .add .cvs .print

1. The scanner will recognize
123 as a number, convert it to an integer object and pass it to the JaM machine for execution. The JaM machine executes integers by putting them on the operand stack.

2. In a similar way,
456 will be pushed on the operand stack.

3. The scanner will recognize
.add as an identifier. ".add" is known in the system dictionary as a command object which, when executed will add two numbers on the operand stack, and leave the resulting integer object on the operand stack.

4. After the
.add command is executed, the operand stack will contain the integer object: 579.

5. The scanner will recognize
.cvs as an identifier. ".cvs" is known in the system dictionary as a command object which, when executed will convert an object on the operand stack into its string object equivalent. e.g. the integer 579 will be converted to the string "579", and put on the operand stack.

6. In a similar way,
.print will be a command object which will
print the string found on the operand stack. The result will be that

579

will appear on the screen.

Example 2.

If I type:

(hello there -- how are you) .print

then:

hello there -- how are you

will appear on the screen.

When the JaM machine first starts, the system dictionary contains about sixty definitions. Most of the definitions associate identifiers with command objects. These commands provide the primitive functions of the machine. Included in the primitive operations are commands that allow new definitions to be made into the current dictionary. For example:

Example 3.

If I type:

(a) 123 .def

then the
.def command will associate the string object a with the integer object 123 in the current dictionary. With this definition made, if I type:

a 1 .add .cvs .print

then the scanner will recognize
a as an identifier, look up its definition, and execute the integer object 123, which will put the integer on the operand stack. When the rest of the line is executed, then:

124

Will be printed.

Example 4.

If I type:

(a)(hello -- how are you) .def

then
a is defined to be the string object: hello -- how are you
If I now type:

a .print

then:

hello -- how are you

is printed.

Most objects when executed are put on the operand stack. Command objects are an exception. Command objects are treated as verbs by the execution machinery. In a similar way, other objects can be treated as verbs. For example:

Example 5.

If I type:

(average)(.add 2. .div) .cvx .def

then the .cvx command will make the string object:
.add 2. .div
executable before it is defined as the value of
average. Therefore when I type:

123 456 average .cvs .print

the identifier
average will be defined as the executable string object: .add 2. .div. This string object will not be put on the operand stack, but instead will be passed to the scanner and executed as though it replaced average. The result will be that:

289.5

will be printed.

It can be seen from the above simple examples, that the user may assign values to identifiers, or assign procedures (executable objects) to identifiers. This ability to extend the JaM machine is the primary feature that allows complex systems to be built in the JaM environment.

To appreciate how this extensibility may be used, a more complete description of the primitive command set, and its relationship to the machine structure will be given.


JaM Command Catagories

There are roughly nine catagories of JaM commands. These include:

Arithmetic Commands

The arithmetic commands provide for the basic arithmetic operations between mixed types of numbers. These commands take their operands from the operand stack, and leave the results on the operand stack. Included are:

.add
: <n><m> .add => <n+m>
.sub
: <n><m> .sub => <n-m>
.mul
: <n><m> .mul => <n*m>
.div
: <n><m> .div => <n/m>
.neg
: <n> .neg => <-n>


Boolean and Relational Commands

These commands include commands that generate boolean constants, perform relational tests between numeric objects, and perform boolean operations between boolean objects. Included are:

.true
: .true => <.true>
.false
: .false => <.false>
.eq
: <n><m> .eq => <.true> if n = m
<.false> if n # m
.gt
: <n><m> .gt => <.true> if n > m
<.false> if n <= m
.lt
: <n><m> .lt => <.true> if n < m
<.false> if n >= m
.not
: <b> .not => <~b>
.and
: <b1><b2> .and => <b1 AND b2>
.or
: <b1><b2> .or => <b1 OR b2>
.xor
: <b1><b2> .xor => <b1 XOR b2>

Stack Manipulation Commands

These commands provide a set of functions that allow the user to manipulate the operand stack. These functions include facilities to duplicate portions of the stack, rearrange portions of the stack, eliminate portions of the stack, and count the entries on the stack. Included are:

.pop
: <x> .pop => --
.copy
: <x1><x2> ... <xi><i> .copy => <x1><x2> ... <xi><x1><x2> ... <xi>
.cntstk
: | <x1><x2> ... <xi> .cntstk => <i>
.roll
: <x1><x2> ... <xi><i><j> .roll => <x(j+1) mod i> ... <xi><x1>...<xj mod i>
.dup
: <x> .dup => <x><x>
.clrstk
: | <x1><x2> ... <xi> .clrstk => |
.exch
: <x><y> .exch => <y><x>


Execution Control Commands

This set of commands provides for control of execution. JaM has no "go to" type of command. Instead heavy use is made of "if - else", "looping", and "select" kinds of control mechanisms. Most execution control commands expect objects on the operand stack. These objects are executed as a function of other objects on the stack. For example: The .if command expects a boolean object and any other object on the operand stack. If the boolean equals .true then the other object is executed, otherwise the .if command pops the object from the stack. The execution control commands include:

.exec
: <x> .exec => -- (executes object x)
.if
: <b><x> .if => -- (if b = .true then execute x)
.ifelse
: <b><x><y> .ifelse => -- (if b = .true then execute x else execute y)
.rept
: <i><x> .rept => -- (execute x -- i times)
.loop
: <x> .loop => -- (execute x until a .exit command is executed)
.exit
: .exit => -- (exit from the current .rept, .loop, .dictforall, .arrayforall commands)
.stop
: .stop => -- (clear the execution stack.)
.singlestep: .singlestep => -- (put execution control into singlestep mode.)
.runfree
: .runfree => -- (take execution control out of singlestep mode.)
.quit
: .quit => -- (save virtual memory and exit to the operating system.)


Dictionary Related Commands

Dictionary objects are general symbol tables that may be used either as data structures or as part of the user’s execution context.

As we learned earlier, the scanner, when it encounters an identifier, looks up the identifier in the dictionaries on the dictionary stack. What actually happens in this case is quite simple. The unknown identifier is first looked up in the dictionary on the top of the dictionary stack. If the identifier has a value in this dictionary, then the value is returned. If the identifier has no entry in this dictionary, then each dictionary on the dictionary stack is searched until the entry is found. At this point the value associated with the identifier is returned. The user has control over the contents of the dictionary stack via the
.begin and .end commands, and therefore the user has control over his execution context. Later we will see how this control may be used.

When dictionaries are used as data structures, they are loaded, as objects, onto the operand stack. Various commands can then operate on these objects to store new definitions, or to retrieve definitions found in the dictionaries. Also a command exists for creating new dictionaries.

The dictionary related commands are:

.dict
: <i> .dict => <d> (dictionary with capacity of i entries)
.def
: <k><v> .def => -- (associates the value v with the key k in the current dictionary)
.del
: <d><k> .del => -- (deletes the key k from the dictionary d)
.load
: <k> .load => <v> (loads the value associated with k in the current dictionary)
.store
: <k><v> .store => -- (finds a definition of k in the current context and replaces that
definition with value v. If no definition of k exists then the
definition is placed in the current dictionary.)
.put
: <d><k><v> .put => -- (associates value v with key k in dictionary d.)
.get
: <d><k> .get => <v> (retrieves the value associated with k in dictionary d.)
.known
: <d><k> .known => <.true> if key k is in dictionary d.
<.false> if key k is not in dictionary d.
.where
: <k> .where => <.true><d> if k is found in some dictionary d.
<.false> if k is not found in any dictionary.
.clrdict
: <d> .clrdict => -- (clears all entries from dictionary d.)
.dictforall: <d><x>.dictforall => -- (puts <k><v> on the stack, and then executes <x>. This is done
for every k,v pair in dictionary d)
.begin
: <d> .begin => -- (makes d the current dictionary on the dictionary stack.)
.end
: .end => -- (pops the current dictionary from the dictionary stack.)
.sysdict
: .sysdict => <systemdictionary>


Array Related Commands

Array objects are linear arrays of objects. Commands exist to create arrays, store into arrays, retrieve objects from arrays etc. Most of these commands either expect array objects on the operand stack or return array objects on the operand stack.

In addition to their usefulness as data structures, arrays can also be executed directly. In some sense the array form of a procedure corresponds to the compiled form of a procedure in other machines.

The array related commands consist of:


.array
: <i> .array => <a> (new array of length i.)
.subarray
: <a><i><j> .subarray => <a’> (a’ is the subarray of a starting at position i and with
length j.)
.aput
: <a><i><v> .aput => -- (store v in the ith position of a.)
.aget
: <a><i> .aget => <v> (get v from the ith position of a.)
.aload
: <a> .aload =>
.astore
: <x1><x2> ... <xi><a> .astore => <a> (store x1 ... xi into array a of length i.)
.arrayforall: <a><x>.dictforall => -- (puts the contents of a
i on the stack, and then executes <x>.
This is done for every ai pair in array a)


Input/Output and Stream Related Commands

This catagory of commands deals primarily with string objects and stream objects. There exist primitive JaM commands to create streams, execute streams, read streams, write streams, and distroy streams. These commands include:

.print
: <s> .print => -- (.prints the string s on the current output stream.)
.bytestream: <filename> <access> .bytestream => <bs> (this command creates a bytestream with the
access characteristics represented by <access>. Here
<access> = 1 for read, 2 for write, 4 for append -- or
the sum of any of these. The created stream type object
is left on the operand stack.)
.keystream : .keystream => <ks> (this command creates a keystream and leaves it on the operand
stack.)
.killstream: <t> .killstream => (this command kills the given stream.)
.writebytes: <t><s> .writebytes => -- (write bytes in string s appended to stream t.)
.loadbcd
: <filename> .loadbcd => -- (load mesa bcd and start.)


Attribute and Conversion Commands

These commands allow the user to determine the types of objects and to convert from one object type to another. This command set is not complete as yet, but the currently provided commands include:

.type
: <x> .type => <NameOfType> (deliver the name of the type on top of operand stack.
Current types include. .nulltype, .intergertype,
.longintegertype, .realtype, .booleantype, .stringtype,
.stringlittype, .streamtype, .streamlittype, .arraytype,
.arraylittype, .dicttype, .commandtype, .stacktype,
.frametype.)
.length
: <x> .length => <i> (length of: string (in characters); array (in elements); dictionary
(in entries).)
.cvs
: <x> .cvs => <s> (convert to string equivalent.)
.cvis
: <x><s> .cvis => <s> (convert into given string space. This command will use s for all
number and boolean conversions.)
.cvx
: <x> .cvx => <x’> (convert into executable equivalent.)
.cvlit
: <x> .cvlit => <xl> (convert into literal form -- works for strings, and arrays.)


Scanner and String Manipulation Commands

As of now, the only command in this group is the
.token command which gives the user access to the JaM machine scanner. In the future, commands will be added to this group which will allow for string searching and manipulation.

.token
: <s> .token => <sr><t> (strip first token from given stream or string. Return remainder
and token on the stack. If no token, then return only a NullType
Object.)