Formal Whirl Program Definition Formal Whirl Program Definition
The execution model of a Whirl program ("Whirl program" is a term
that means either the execution model or the sequence of
instructions which is a composition of "0" and "1" symbols) depend
on the instructions themselves as well as two levels of state:
one state level determines which table to use to determine the
instruction's command (these tables are called the "ops ring" and
the "math ring"), the other state level determines for that table
a set of conditions that determine which command with which
argument (if any) is to be selected for execution. A Whirl
program also contains "memory" of an indeterminate number of
mutable cells, each cell contains a numeric value initialized to
0.
Program
The above description can be summarized precisely by the
following tuple equivalence:
PWhirl |
= { |
Ring-typeactive, Hist, Rings, MemHT(indexed), InstHT(indexed) } |
| where: |
|
PWhirl | is | the execution model of this Whirl Program ("the program") | Ring-typeactive | one-of([ops, math]) | indicates which ring is currently active | Hist | hist(State, last_instruction(Inst)) | the results of interpretation of the previous instruction | | where: | | | State | one-of([quescient, executed]) | was a command selected for execution? | | 'quescient' means a command was not selected for execution | | 'executed' means a command was selected and executed | Inst | one-of(["0", "1"]) | the last interpreted instruction |
| Rings | { Ringops, Ringmath } | the current state of each ring (rings described below) | MemHT(indexed) | is | A list of memory cells (described below); current active one at the head |
InstHT(indexed) | is | Indexed (unsorted) program instructions; current active one at the head (structure described below). |
|
Instructions
Semantics
Whirl has two instructions "0", and "1". The meanings of these
instructions are captured here:
1 |
Rotate the currently active ring in its indicated direction and set the history to "hist(quescient, last_instruction(1))" ex 1: GIVEN | the current ring is "ops" |
---|
| and | its direction is "clockwise spin" |
---|
| and | the currectly selected command is "3 - zero" |
---|
THEN | the ops ring's newly selected command is "4 - load" |
---|
ex 2: GIVEN | the current ring is "math" |
---|
| and | its direction is "counterclockwise spin" |
---|
| and | the currectly selected command is "0 - noop" |
---|
THEN | the math ring's newly selected command is "11 - neg" |
---|
|
---|
0 |
First, | Reverse the spin of the currently active ring |
---|
And then, | perform the test: |
---|
| IF | the last instruction was "0", |
---|
| and | the last instruction did not result in a command execution, | | (i.e.: the command history is "hist(quescient, last_instruction(0))") | THEN | execute the currently selected command |
---|
| and | activate the inactive ring and deactivate this one (i.e.: switch rings) |
| and | set the history to "hist(executed, last_instruction(0))" | OTHERWISE | set the history to "hist(quescient, last_instruction(0))" |
---|
|
ex 1: | |
---|
| GIVEN | the current ring is "math" |
---|
| and | its direction is "counterclockwise spin" |
---|
| and | the command history is "hist(executed, last_instruction(0))" |
---|
THEN | the math ring's new direction is "clockwise spin" |
---|
| and | the command history is set to "hist(quescient, last_instruction(0))" |
---|
| ex 2: | |
---|
| GIVEN | the current ring is "ops" |
---|
| and | its direction is "clockwise spin" |
---|
| and | the currently selected command is "2 - one" |
---|
| and | the command history is "hist(quescient, last_instruction(0))" |
---|
THEN | the ops ring's new direction is "counterclockwise spin" |
---|
| and | the "one" command is executed |
---|
| (i.e.: the ops Accumulator is set to 1) | | and | the ops ring is deactivated; the math ring, activated |
---|
| and | the command history is set to "hist(executed, last_instruction(0))" |
---|
| ex 3: | |
---|
| GIVEN | the current ring is "math" |
---|
| and | its direction is "clockwise spin" |
---|
| and | the command history is "hist(quescient, last_instruction(1))" |
---|
THEN | the math ring's new direction is "counterclockwise spin" |
---|
| and | the command history is set to "hist(quescient, last_instruction(0))" |
---|
|
|
---|
Whirl instructions are executed in sequence (a
padd command alters the sequence by a
relative amount for the next instruction to be executed), and to
enforce this discipline, we store the sequence of instructions
decorated with an index (such storage is normally referred to as an
"array", but such a term has a grossly overloaded meaning
(particularly when it comes to element access) in the software
engineering field). Individual elements are of the form:
{ Index, Instruction }
where: | |
| Index indicates this instruction is ith in the program source |
| Instruction is one-of(["0", "1"]) |
These elements are stored in a list with the only ordering being
that the current instruction is at the head of the list. The
next instruction is obtained by incrementing the Index by an
offset (the offset is either 1 or the amount in the ops
accumulator if the command executed is a 'padd') and then moving
that corresponding element to the head of the list.
Program Termination
The program will terminate when any of the following conditions
are met:
- The exit command is executed; or,
- The next index sought is not in
InstHT(indexed); or,
- The program encounters an error (e.g. the user enters
non-numeric input on a intIO input
command)
Whirl programs interact with two rings, the "ops" ring and the
"math" ring. Each ring has its own
(not necessarily orthogonal) set of commands, a selector pointing
to the command to be executed, an accumulator, and a (reversible)
direction of spin. The general structure of each ring is as
follows:
RingType | = { |
CommandsHT, Direction, Accumulator } |
| where: |
| Type | one-of([ops, math]) | which ring this tuple represents | CommandsHT | is | List of indexed (unsorted) commands; the command at the head is considered selected for execution | Direction | one-of([clockwise spin, counterclockwise spin]) | the direction in which the ring rotations for next command selection | Accumulator | value(Number) | Number is initially 0 and changes when commands are executed |
|
The indexed commands for the ops ring are: |
The indexed commands for the math ring are: |
|
|
Ring Command Semantics
Not only is command selection dependent on a dual state layer from the instruction, but also
the command itself may have meaning dependent on the state. The commands are described as follows:
Index | Command | Preconditions | Effect |
---|
Ops Ring |
---|
0 | noop | n/a | (no effect) |
---|
1 | exit | n/a | program halts |
---|
2 | one | Accumulator = any value | Accumulator = 1 |
---|
3 | zero | Accumulator = any value | Accumulator = 0 |
---|
4 | load |
Accumulator = any value; Current Memory cell = Num | Accumulator = Num |
---|
5 | store |
Accumulator = Num; Current Memory cell = any value | Current Memory cell = Num |
---|
6 | padd |
Accumulator = Num1; program index = Num2 |
program index = Num1 + Num2 (relative jump) |
---|
7 | dadd |
Accumulator = Num1; memory index = Num2 |
memory index = Num1 + Num2 (relative access) |
---|
8 | logic |
current memory index = 0 | otherwise (Accumulator = Val) |
|
Accumulator = 0 | Accumulator = Val & 1 |
|
---|
9 | if |
current memory index = 0 | otherwise |
|
|
---|
10 | intIO |
Accumulator = 0 | otherwise |
|
current memory value = input integer | current memory value printed as an integer |
|
---|
11 | ascIO |
Accumulator = 0 | otherwise |
|
current memory value = input ASCII character | current memory value printed as an ASCII character |
|
---|
Math Ring |
---|
0 | noop |
n/a | (no effect) |
---|
1 | load |
Accumulator = any value; Current Memory cell = Num |
Accumulator = Num |
---|
2 | store |
Accumulator = Num; Current Memory cell = any value |
Current Memory cell = Num |
---|
3 | add |
Accumulator = A; Current Memory cell = B |
Accumulator = A + B |
---|
4 | mult |
Accumulator = A; Current Memory cell = B |
Accumulator = AB |
---|
5 | div |
Accumulator = A; Current Memory cell = B |
Accumulator = A / B |
---|
6 | zero |
Accumulator = any value | Accumulator = 0 |
---|
7 | < |
Accumulator < current memory value | otherwise |
|
Accumulator = 1 | Accumulator = 0 |
|
---|
8 | > |
Accumulator > current memory value | otherwise |
|
Accumulator = 1 | Accumulator = 0 |
|
---|
9 | = |
Accumulator = current memory value | otherwise |
|
Accumulator = 1 | Accumulator = 0 |
|
---|
10 | not |
Accumulator = 0 | otherwise |
|
Accumulator = 1 | Accumulator = 0 |
|
---|
11 | neg |
Accumulator = Num | Accumulator = -Num |
---|
The Whirl specification states that Whirl program memory is
infinite; we obey by accumulating memory on an as-needed basis
("lazily"). Memory follows a similar structural and allocation
scheme as with program
instruction storage: decorated with an index when the head
element being the currently selected one.
The difference with memory is that:
- instructions are of the binary form "0" or "1", but memory may
store any (Rational) numeric value; and,
- it starts initially with one tuple: { 0, 0.0 }; and,
- when another element is selected (with
dadd) that is not present, that element
is added to the memory store, initialized to { Index, 0.0 }
It is implementation-dependent as to how memory values are
converted to integral or to (ASCII) character
near-equivalents.
author: | Douglas M. Auclair |
---|
date: | November 28, 2005 |
---|
whirl@ |
href="http://www.bigzaphod.org/whirl">http://www.bigzaphod.org/whirl |
---|
No comments:
Post a Comment