mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-04 01:11:44 +00:00
Check in patch that Reid submitted
llvm-svn: 10505
This commit is contained in:
parent
9b9d3e0bef
commit
754c9b8b69
@ -57,7 +57,7 @@
|
||||
<div class="doc_text">
|
||||
<p>This document is another way to learn about LLVM. Unlike the
|
||||
<a href="LangRef.html">LLVM Reference Manual</a> or
|
||||
<a href="ProgrammersManual.html">LLVM Programmer's Manual</a>, we learn
|
||||
<a href="ProgrammersManual.html">LLVM Programmer's Manual</a>, here we learn
|
||||
about LLVM through the experience of creating a simple programming language
|
||||
named Stacker. Stacker was invented specifically as a demonstration of
|
||||
LLVM. The emphasis in this document is not on describing the
|
||||
@ -70,11 +70,10 @@ compiler system.</p>
|
||||
<p>Amongst other things, LLVM is a platform for compiler writers.
|
||||
Because of its exceptionally clean and small IR (intermediate
|
||||
representation), compiler writing with LLVM is much easier than with
|
||||
other system. As proof, the author of Stacker wrote the entire
|
||||
compiler (language definition, lexer, parser, code generator, etc.) in
|
||||
about <em>four days</em>! That's important to know because it shows
|
||||
how quickly you can get a new
|
||||
language up when using LLVM. Furthermore, this was the <em >first</em>
|
||||
other system. As proof, I wrote the entire compiler (language definition,
|
||||
lexer, parser, code generator, etc.) in about <em>four days</em>!
|
||||
That's important to know because it shows how quickly you can get a new
|
||||
language running when using LLVM. Furthermore, this was the <em >first</em>
|
||||
language the author ever created using LLVM. The learning curve is
|
||||
included in that four days.</p>
|
||||
<p>The language described here, Stacker, is Forth-like. Programs
|
||||
@ -136,7 +135,7 @@ expressed in stacker as: <code>1 + SWAP 1 + / ROT2 OR *</code>.
|
||||
You could write a function using LLVM that computes this expression like this: </p>
|
||||
<pre><code>
|
||||
Value*
|
||||
expression(BasicBlock*bb, Value* a, Value* b, Value* x, Value* y )
|
||||
expression(BasicBlock* bb, Value* a, Value* b, Value* x, Value* y )
|
||||
{
|
||||
Instruction* tail = bb->getTerminator();
|
||||
ConstantSInt* one = ConstantSInt::get( Type::IntTy, 1);
|
||||
@ -154,14 +153,16 @@ expression(BasicBlock*bb, Value* a, Value* b, Value* x, Value* y )
|
||||
return mult1;
|
||||
}
|
||||
</code></pre>
|
||||
<p>"Okay, big deal," you say. It is a big deal. Here's why. Note that I didn't
|
||||
<p>"Okay, big deal," you say? It is a big deal. Here's why. Note that I didn't
|
||||
have to tell this function which kinds of Values are being passed in. They could be
|
||||
<code>Instruction</code>s, <code>Constant</code>s, <code>GlobalVariable</code>s,
|
||||
etc. Furthermore, if you specify Values that are incorrect for this sequence of
|
||||
<code>Instruction</code>s, <code>Constant</code>s, <code>GlobalVariable</code>s, or
|
||||
any of the other subclasses of <code>Value</code> that LLVM supports.
|
||||
Furthermore, if you specify Values that are incorrect for this sequence of
|
||||
operations, LLVM will either notice right away (at compilation time) or the LLVM
|
||||
Verifier will pick up the inconsistency when the compiler runs. In no case will
|
||||
you make a type error that gets passed through to the generated program.
|
||||
This <em>really</em> helps you write a compiler that always generates correct code!<p>
|
||||
Verifier will pick up the inconsistency when the compiler runs. In either case
|
||||
LLVM prevents you from making a type error that gets passed through to the
|
||||
generated program. This <em>really</em> helps you write a compiler that
|
||||
always generates correct code!<p>
|
||||
<p>The second point is that we don't have to worry about branching, registers,
|
||||
stack variables, saving partial results, etc. The instructions we create
|
||||
<em>are</em> the values we use. Note that all that was created in the above
|
||||
@ -235,26 +236,26 @@ BasicBlock*
|
||||
MyCompiler::handle_if( BasicBlock* bb, SetCondInst* condition )
|
||||
{
|
||||
// Create the blocks to contain code in the structure of if/then/else
|
||||
BasicBlock* then = new BasicBlock();
|
||||
BasicBlock* else = new BasicBlock();
|
||||
BasicBlock* exit = new BasicBlock();
|
||||
BasicBlock* then_bb = new BasicBlock();
|
||||
BasicBlock* else_bb = new BasicBlock();
|
||||
BasicBlock* exit_bb = new BasicBlock();
|
||||
|
||||
// Insert the branch instruction for the "if"
|
||||
bb->getInstList().push_back( new BranchInst( then, else, condition ) );
|
||||
bb->getInstList().push_back( new BranchInst( then_bb, else_bb, condition ) );
|
||||
|
||||
// Set up the terminating instructions
|
||||
then->getInstList().push_back( new BranchInst( exit ) );
|
||||
else->getInstList().push_back( new BranchInst( exit ) );
|
||||
then->getInstList().push_back( new BranchInst( exit_bb ) );
|
||||
else->getInstList().push_back( new BranchInst( exit_bb ) );
|
||||
|
||||
// Fill in the then part .. details excised for brevity
|
||||
this->fill_in( then );
|
||||
this->fill_in( then_bb );
|
||||
|
||||
// Fill in the else part .. details excised for brevity
|
||||
this->fill_in( else );
|
||||
this->fill_in( else_bb );
|
||||
|
||||
// Return a block to the caller that can be filled in with the code
|
||||
// that follows the if/then/else construct.
|
||||
return exit;
|
||||
return exit_bb;
|
||||
}
|
||||
</pre>
|
||||
<p>Presumably in the foregoing, the calls to the "fill_in" method would add
|
||||
@ -264,15 +265,17 @@ terminator). Furthermore, they could even recurse back to <code>handle_if</code>
|
||||
should they encounter another if/then/else statement and it will just work.</p>
|
||||
<p>Note how cleanly this all works out. In particular, the push_back methods on
|
||||
the <code>BasicBlock</code>'s instruction list. These are lists of type
|
||||
<code>Instruction</code> which also happen to be <code>Value</code>s. To create
|
||||
<code>Instruction</code> (which is also of type <code>Value</code>). To create
|
||||
the "if" branch we merely instantiate a <code>BranchInst</code> that takes as
|
||||
arguments the blocks to branch to and the condition to branch on. The blocks
|
||||
act like branch labels! This new <code>BranchInst</code> terminates
|
||||
the <code>BasicBlock</code> provided as an argument. To give the caller a way
|
||||
to keep inserting after calling <code>handle_if</code> we create an "exit" block
|
||||
which is returned to the caller. Note that the "exit" block is used as the
|
||||
terminator for both the "then" and the "else" blocks. This guarantees that no
|
||||
matter what else "handle_if" or "fill_in" does, they end up at the "exit" block.
|
||||
arguments the blocks to branch to and the condition to branch on. The
|
||||
<code>BasicBlock</code> objects act like branch labels! This new
|
||||
<code>BranchInst</code> terminates the <code>BasicBlock</code> provided
|
||||
as an argument. To give the caller a way to keep inserting after calling
|
||||
<code>handle_if</code> we create an <code>exit_bb</code> block which is returned
|
||||
to the caller. Note that the <code>exit_bb</code> block is used as the
|
||||
terminator for both the <code>then_bb</code> and the <code>else_bb</code>
|
||||
blocks. This guarantees that no matter what else <code>handle_if</code>
|
||||
or <code>fill_in</code> does, they end up at the <code>exit_bb</code> block.
|
||||
</p>
|
||||
</div>
|
||||
<!-- ======================================================================= -->
|
||||
@ -318,8 +321,8 @@ pointer. The second index subscripts the array. If you're a "C" programmer, this
|
||||
will run against your grain because you'll naturally think of the global array
|
||||
variable and the address of its first element as the same. That tripped me up
|
||||
for a while until I realized that they really do differ .. by <em>type</em>.
|
||||
Remember that LLVM is a strongly typed language itself. Everything
|
||||
has a type. The "type" of the global variable is [24 x int]*. That is, its
|
||||
Remember that LLVM is strongly typed. Everything has a type.
|
||||
The "type" of the global variable is [24 x int]*. That is, its
|
||||
a pointer to an array of 24 ints. When you dereference that global variable with
|
||||
a single (0) index, you now have a "[24 x int]" type. Although
|
||||
the pointer value of the dereferenced global and the address of the zero'th element
|
||||
@ -332,7 +335,7 @@ a lot of compiler writing headaches down the road.</p>
|
||||
<div class="doc_subsection"><a name="linkage"></a>Getting Linkage Types Right</div>
|
||||
<div class="doc_text">
|
||||
<p>Linkage types in LLVM can be a little confusing, especially if your compiler
|
||||
writing mind has affixed very hard concepts to particular words like "weak",
|
||||
writing mind has affixed firm concepts to particular words like "weak",
|
||||
"external", "global", "linkonce", etc. LLVM does <em>not</em> use the precise
|
||||
definitions of say ELF or GCC even though they share common terms. To be fair,
|
||||
the concepts are related and similar but not precisely the same. This can lead
|
||||
@ -342,16 +345,19 @@ different. I recommend you read the
|
||||
carefully. Then, read it again.<p>
|
||||
<p>Here are some handy tips that I discovered along the way:</p>
|
||||
<ul>
|
||||
<li>Unitialized means external. That is, the symbol is declared in the current
|
||||
<li><em>Unitialized means external.</em> That is, the symbol is declared in the current
|
||||
module and can be used by that module but it is not defined by that module.</li>
|
||||
<li>Setting an initializer changes a global's linkage type from whatever it was
|
||||
to a normal, defind global (not external). You'll need to call the setLinkage()
|
||||
method to reset it if you specify the initializer after the GlobalValue has been
|
||||
constructed. This is important for LinkOnce and Weak linkage types.</li>
|
||||
<li>Appending linkage can be used to keep track of compilation information at
|
||||
runtime. It could be used, for example, to build a full table of all the C++
|
||||
virtual tables or hold the C++ RTTI data, or whatever. Appending linkage can
|
||||
only be applied to arrays. The arrays are concatenated together at link time.</li>
|
||||
<li><em>Setting an initializer changes a global' linkage type.</em> Setting an
|
||||
initializer changes a global's linkage type from whatever it was to a normal,
|
||||
defind global (not external). You'll need to call the setLinkage() method to
|
||||
reset it if you specify the initializer after the GlobalValue has been constructed.
|
||||
This is important for LinkOnce and Weak linkage types.</li>
|
||||
<li><em>Appending linkage can keep track of things.</em> Appending linkage can
|
||||
be used to keep track of compilation information at runtime. It could be used,
|
||||
for example, to build a full table of all the C++ virtual tables or hold the
|
||||
C++ RTTI data, or whatever. Appending linkage can only be applied to arrays.
|
||||
All arrays with the same name in each module are concatenated together at link
|
||||
time.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======================================================================= -->
|
||||
@ -423,7 +429,7 @@ the stack manipulting words that you wish define <code>name</code> as. <p>
|
||||
# This is a comment to end of line
|
||||
( This is an enclosed comment )
|
||||
</code></pre>
|
||||
<p>See the <a href="#example">example</a> program to see how this works in
|
||||
<p>See the <a href="#example">example</a> program to see comments in use in
|
||||
a real program.</p>
|
||||
</div>
|
||||
<!-- ======================================================================= -->
|
||||
@ -446,9 +452,9 @@ the stack. It is assumed that the programmer knows how the stack
|
||||
transformation he applies will affect the program.</p>
|
||||
<p>Words in a definition come in two flavors: built-in and programmer
|
||||
defined. Simply mentioning the name of a previously defined or declared
|
||||
programmer-defined word causes that word's definition to be invoked. It
|
||||
programmer-defined word causes that word's stack actions to be invoked. It
|
||||
is somewhat like a function call in other languages. The built-in
|
||||
words have various effects, described below.</p>
|
||||
words have various effects, described <a href="#builtins">below</a>.</p>
|
||||
<p>Sometimes you need to call a word before it is defined. For this, you can
|
||||
use the <code>FORWARD</code> declaration. It looks like this:</p>
|
||||
<p><code>FORWARD name ;</code></p>
|
||||
@ -472,7 +478,8 @@ depending on what they do. The groups are as follows:</p>
|
||||
<li><em>Arithmetic</em>These words perform arithmetic computations on
|
||||
their operands. <br/> The words are: ABS NEG + - * / MOD */ ++ -- MIN MAX</li>
|
||||
<li><em>Stack</em>These words manipulate the stack directly by moving
|
||||
its elements around.<br/> The words are: DROP DUP SWAP OVER ROT DUP2 DROP2 PICK TUCK</li>
|
||||
its elements around.<br/> The words are: DROP DROP2 NIP NIP2 DUP DUP2
|
||||
SWAP SWAP2 OVER OVER2 ROT ROT2 RROT RROT2 TUCK TUCK2 PICK SELECT ROLL</li>
|
||||
<li><em>Memory</em>These words allocate, free and manipulate memory
|
||||
areas outside the stack.<br/>The words are: MALLOC FREE GET PUT</li>
|
||||
<li><em>Control</em>These words alter the normal left to right flow
|
||||
@ -500,311 +507,331 @@ using the following construction:</p>
|
||||
<li><em>p</em> - a pointer to a malloc'd memory block</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="doc_text">
|
||||
<table class="doc_table" >
|
||||
<tr class="doc_table"><td colspan="4">Definition Of Operation Of Built In Words</td></tr>
|
||||
<tr class="doc_table"><td colspan="4">LOGICAL OPERATIONS</td></tr>
|
||||
<tr class="doc_table"><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr class="doc_table"><td><</td>
|
||||
<td>LT</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<div class="doc_text" >
|
||||
<table class="doc_table" style="border: 2px solid blue; border-collapse: collapse;" >
|
||||
<tr class="doc_table"><td colspan="4" style="border: 2px solid blue">Definition Of Operation Of Built In Words</td></tr>
|
||||
<tr class="doc_table"><td colspan="4" style="border: 2px solid blue"><b>LOGICAL OPERATIONS</b></td></tr>
|
||||
<tr class="doc_table">
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr class="doc_table"><td style="border: 2px solid blue"><</td>
|
||||
<td style="border: 2px solid blue">LT</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is less than w2, TRUE is pushed back on
|
||||
the stack, otherwise FALSE is pushed back on the stack.</td>
|
||||
</tr>
|
||||
<tr><td>></td>
|
||||
<td>GT</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<tr><td style="border: 2px solid blue">></td>
|
||||
<td style="border: 2px solid blue">GT</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is greater than w2, TRUE is pushed back on
|
||||
the stack, otherwise FALSE is pushed back on the stack.</td>
|
||||
</tr>
|
||||
<tr><td>>=</td>
|
||||
<td>GE</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<tr><td style="border: 2px solid blue">>=</td>
|
||||
<td style="border: 2px solid blue">GE</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is greater than or equal to w2, TRUE is
|
||||
pushed back on the stack, otherwise FALSE is pushed back
|
||||
on the stack.</td>
|
||||
</tr>
|
||||
<tr><td><=</td>
|
||||
<td>LE</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<tr><td style="border: 2px solid blue"><=</td>
|
||||
<td style="border: 2px solid blue">LE</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is less than or equal to w2, TRUE is
|
||||
pushed back on the stack, otherwise FALSE is pushed back
|
||||
on the stack.</td>
|
||||
</tr>
|
||||
<tr><td>=</td>
|
||||
<td>EQ</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<tr><td style="border: 2px solid blue">=</td>
|
||||
<td style="border: 2px solid blue">EQ</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is equal to w2, TRUE is
|
||||
pushed back on the stack, otherwise FALSE is pushed back
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><></td>
|
||||
<td>NE</td>
|
||||
<td>w1 w2 -- b</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack and
|
||||
<tr><td style="border: 2px solid blue"><></td>
|
||||
<td style="border: 2px solid blue">NE</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- b</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack and
|
||||
compared. If w1 is equal to w2, TRUE is
|
||||
pushed back on the stack, otherwise FALSE is pushed back
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td>FALSE</td>
|
||||
<td>FALSE</td>
|
||||
<td> -- b</td>
|
||||
<td>The boolean value FALSE (0) is pushed onto the stack.</td>
|
||||
<tr><td style="border: 2px solid blue">FALSE</td>
|
||||
<td style="border: 2px solid blue">FALSE</td>
|
||||
<td style="border: 2px solid blue"> -- b</td>
|
||||
<td style="border: 2px solid blue">The boolean value FALSE (0) is pushed onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td>TRUE</td>
|
||||
<td>TRUE</td>
|
||||
<td> -- b</td>
|
||||
<td>The boolean value TRUE (-1) is pushed onto the stack.</td>
|
||||
<tr><td style="border: 2px solid blue">TRUE</td>
|
||||
<td style="border: 2px solid blue">TRUE</td>
|
||||
<td style="border: 2px solid blue"> -- b</td>
|
||||
<td style="border: 2px solid blue">The boolean value TRUE (-1) is pushed onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">BITWISE OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td><<</td>
|
||||
<td>SHL</td>
|
||||
<td>w1 w2 -- w1<<w2</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack. The w2
|
||||
<tr><td colspan="4"><b>BITWISE OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue"><<</td>
|
||||
<td style="border: 2px solid blue">SHL</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w1<<w2</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack. The w2
|
||||
operand is shifted left by the number of bits given by the
|
||||
w1 operand. The result is pushed back to the stack.</td>
|
||||
</tr>
|
||||
<tr><td>>></td>
|
||||
<td>SHR</td>
|
||||
<td>w1 w2 -- w1>>w2</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack. The w2
|
||||
<tr><td style="border: 2px solid blue">>></td>
|
||||
<td style="border: 2px solid blue">SHR</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w1>>w2</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack. The w2
|
||||
operand is shifted right by the number of bits given by the
|
||||
w1 operand. The result is pushed back to the stack.</td>
|
||||
</tr>
|
||||
<tr><td>OR</td>
|
||||
<td>OR</td>
|
||||
<td>w1 w2 -- w2|w1</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack. The values
|
||||
<tr><td style="border: 2px solid blue">OR</td>
|
||||
<td style="border: 2px solid blue">OR</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2|w1</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack. The values
|
||||
are bitwise OR'd together and pushed back on the stack. This is
|
||||
not a logical OR. The sequence 1 2 OR yields 3 not 1.</td>
|
||||
</tr>
|
||||
<tr><td>AND</td>
|
||||
<td>AND</td>
|
||||
<td>w1 w2 -- w2&w1</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack. The values
|
||||
<tr><td style="border: 2px solid blue">AND</td>
|
||||
<td style="border: 2px solid blue">AND</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2&w1</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack. The values
|
||||
are bitwise AND'd together and pushed back on the stack. This is
|
||||
not a logical AND. The sequence 1 2 AND yields 0 not 1.</td>
|
||||
</tr>
|
||||
<tr><td>XOR</td>
|
||||
<td>XOR</td>
|
||||
<td>w1 w2 -- w2^w1</td>
|
||||
<td>Two values (w1 and w2) are popped off the stack. The values
|
||||
<tr><td style="border: 2px solid blue">XOR</td>
|
||||
<td style="border: 2px solid blue">XOR</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2^w1</td>
|
||||
<td style="border: 2px solid blue">Two values (w1 and w2) are popped off the stack. The values
|
||||
are bitwise exclusive OR'd together and pushed back on the stack.
|
||||
For example, The sequence 1 3 XOR yields 2.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">ARITHMETIC OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td>ABS</td>
|
||||
<td>ABS</td>
|
||||
<td>w -- |w|</td>
|
||||
<td>One value s popped off the stack; its absolute value is computed
|
||||
<tr><td colspan="4"><b>ARITHMETIC OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue">ABS</td>
|
||||
<td style="border: 2px solid blue">ABS</td>
|
||||
<td style="border: 2px solid blue">w -- |w|</td>
|
||||
<td style="border: 2px solid blue">One value s popped off the stack; its absolute value is computed
|
||||
and then pushed onto the stack. If w1 is -1 then w2 is 1. If w1 is
|
||||
1 then w2 is also 1.</td>
|
||||
</tr>
|
||||
<tr><td>NEG</td>
|
||||
<td>NEG</td>
|
||||
<td>w -- -w</td>
|
||||
<td>One value is popped off the stack which is negated and then
|
||||
<tr><td style="border: 2px solid blue">NEG</td>
|
||||
<td style="border: 2px solid blue">NEG</td>
|
||||
<td style="border: 2px solid blue">w -- -w</td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack which is negated and then
|
||||
pushed back onto the stack. If w1 is -1 then w2 is 1. If w1 is
|
||||
1 then w2 is -1.</td>
|
||||
</tr>
|
||||
<tr><td> + </td>
|
||||
<td>ADD</td>
|
||||
<td>w1 w2 -- w2+w1</td>
|
||||
<td>Two values are popped off the stack. Their sum is pushed back
|
||||
<tr><td style="border: 2px solid blue"> + </td>
|
||||
<td style="border: 2px solid blue">ADD</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2+w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. Their sum is pushed back
|
||||
onto the stack</td>
|
||||
</tr>
|
||||
<tr><td> - </td>
|
||||
<td>SUB</td>
|
||||
<td>w1 w2 -- w2-w1</td>
|
||||
<td>Two values are popped off the stack. Their difference is pushed back
|
||||
<tr><td style="border: 2px solid blue"> - </td>
|
||||
<td style="border: 2px solid blue">SUB</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2-w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. Their difference is pushed back
|
||||
onto the stack</td>
|
||||
</tr>
|
||||
<tr><td> * </td>
|
||||
<td>MUL</td>
|
||||
<td>w1 w2 -- w2*w1</td>
|
||||
<td>Two values are popped off the stack. Their product is pushed back
|
||||
<tr><td style="border: 2px solid blue"> * </td>
|
||||
<td style="border: 2px solid blue">MUL</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2*w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. Their product is pushed back
|
||||
onto the stack</td>
|
||||
</tr>
|
||||
<tr><td> / </td>
|
||||
<td>DIV</td>
|
||||
<td>w1 w2 -- w2/w1</td>
|
||||
<td>Two values are popped off the stack. Their quotient is pushed back
|
||||
<tr><td style="border: 2px solid blue"> / </td>
|
||||
<td style="border: 2px solid blue">DIV</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2/w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. Their quotient is pushed back
|
||||
onto the stack</td>
|
||||
</tr>
|
||||
<tr><td>MOD</td>
|
||||
<td>MOD</td>
|
||||
<td>w1 w2 -- w2%w1</td>
|
||||
<td>Two values are popped off the stack. Their remainder after division
|
||||
<tr><td style="border: 2px solid blue">MOD</td>
|
||||
<td style="border: 2px solid blue">MOD</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2%w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. Their remainder after division
|
||||
of w1 by w2 is pushed back onto the stack</td>
|
||||
</tr>
|
||||
<tr><td> */ </td>
|
||||
<td>STAR_SLAH</td>
|
||||
<td>w1 w2 w3 -- (w3*w2)/w1</td>
|
||||
<td>Three values are popped off the stack. The product of w1 and w2 is
|
||||
<tr><td style="border: 2px solid blue"> */ </td>
|
||||
<td style="border: 2px solid blue">STAR_SLAH</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 -- (w3*w2)/w1</td>
|
||||
<td style="border: 2px solid blue">Three values are popped off the stack. The product of w1 and w2 is
|
||||
divided by w3. The result is pushed back onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td> ++ </td>
|
||||
<td>INCR</td>
|
||||
<td>w -- w+1</td>
|
||||
<td>One value is popped off the stack. It is incremented by one and then
|
||||
<tr><td style="border: 2px solid blue"> ++ </td>
|
||||
<td style="border: 2px solid blue">INCR</td>
|
||||
<td style="border: 2px solid blue">w -- w+1</td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack. It is incremented by one and then
|
||||
pushed back onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td> -- </td>
|
||||
<td>DECR</td>
|
||||
<td>w -- w-1</td>
|
||||
<td>One value is popped off the stack. It is decremented by one and then
|
||||
<tr><td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">DECR</td>
|
||||
<td style="border: 2px solid blue">w -- w-1</td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack. It is decremented by one and then
|
||||
pushed back onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td>MIN</td>
|
||||
<td>MIN</td>
|
||||
<td>w1 w2 -- (w2<w1?w2:w1)</td>
|
||||
<td>Two values are popped off the stack. The larger one is pushed back
|
||||
<tr><td style="border: 2px solid blue">MIN</td>
|
||||
<td style="border: 2px solid blue">MIN</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- (w2<w1?w2:w1)</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. The larger one is pushed back
|
||||
onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td>MAX</td>
|
||||
<td>MAX</td>
|
||||
<td>w1 w2 -- (w2>w1?w2:w1)</td>
|
||||
<td>Two values are popped off the stack. The larger value is pushed back
|
||||
<tr><td style="border: 2px solid blue">MAX</td>
|
||||
<td style="border: 2px solid blue">MAX</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- (w2>w1?w2:w1)</td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack. The larger value is pushed back
|
||||
onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">STACK MANIPULATION OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td>DROP</td>
|
||||
<td>DROP</td>
|
||||
<td>w -- </td>
|
||||
<td>One value is popped off the stack.</td>
|
||||
<tr><td colspan="4"><b>STACK MANIPULATION OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td>DROP2</td>
|
||||
<td>DROP2</td>
|
||||
<td>w1 w2 -- </td>
|
||||
<td>Two values are popped off the stack.</td>
|
||||
<tr><td style="border: 2px solid blue">DROP</td>
|
||||
<td style="border: 2px solid blue">DROP</td>
|
||||
<td style="border: 2px solid blue">w -- </td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack.</td>
|
||||
</tr>
|
||||
<tr><td>NIP</td>
|
||||
<td>NIP</td>
|
||||
<td>w1 w2 -- w2</td>
|
||||
<td>The second value on the stack is removed from the stack. That is,
|
||||
<tr><td style="border: 2px solid blue">DROP2</td>
|
||||
<td style="border: 2px solid blue">DROP2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- </td>
|
||||
<td style="border: 2px solid blue">Two values are popped off the stack.</td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue">NIP</td>
|
||||
<td style="border: 2px solid blue">NIP</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2</td>
|
||||
<td style="border: 2px solid blue">The second value on the stack is removed from the stack. That is,
|
||||
a value is popped off the stack and retained. Then a second value is
|
||||
popped and the retained value is pushed.</td>
|
||||
</tr>
|
||||
<tr><td>NIP2</td>
|
||||
<td>NIP2</td>
|
||||
<td>w1 w2 w3 w4 -- w3 w4</td>
|
||||
<td>The third and fourth values on the stack are removed from it. That is,
|
||||
<tr><td style="border: 2px solid blue">NIP2</td>
|
||||
<td style="border: 2px solid blue">NIP2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 -- w3 w4</td>
|
||||
<td style="border: 2px solid blue">The third and fourth values on the stack are removed from it. That is,
|
||||
two values are popped and retained. Then two more values are popped and
|
||||
the two retained values are pushed back on.</td>
|
||||
</tr>
|
||||
<tr><td>DUP</td>
|
||||
<td>DUP</td>
|
||||
<td>w1 -- w1 w1</td>
|
||||
<td>One value is popped off the stack. That value is then pushed onto
|
||||
<tr><td style="border: 2px solid blue">DUP</td>
|
||||
<td style="border: 2px solid blue">DUP</td>
|
||||
<td style="border: 2px solid blue">w1 -- w1 w1</td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack. That value is then pushed onto
|
||||
the stack twice to duplicate the top stack vaue.</td>
|
||||
</tr>
|
||||
<tr><td>DUP2</td>
|
||||
<td>DUP2</td>
|
||||
<td>w1 w2 -- w1 w2 w1 w2</td>
|
||||
<td>The top two values on the stack are duplicated. That is, two vaues
|
||||
<tr><td style="border: 2px solid blue">DUP2</td>
|
||||
<td style="border: 2px solid blue">DUP2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w1 w2 w1 w2</td>
|
||||
<td style="border: 2px solid blue">The top two values on the stack are duplicated. That is, two vaues
|
||||
are popped off the stack. They are alternately pushed back on the
|
||||
stack twice each.</td>
|
||||
</tr>
|
||||
<tr><td>SWAP</td>
|
||||
<td>SWAP</td>
|
||||
<td>w1 w2 -- w2 w1</td>
|
||||
<td>The top two stack items are reversed in their order. That is, two
|
||||
<tr><td style="border: 2px solid blue">SWAP</td>
|
||||
<td style="border: 2px solid blue">SWAP</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2 w1</td>
|
||||
<td style="border: 2px solid blue">The top two stack items are reversed in their order. That is, two
|
||||
values are popped off the stack and pushed back onto the stack in
|
||||
the opposite order they were popped.</td>
|
||||
</tr>
|
||||
<tr><td>SWAP2</td>
|
||||
<td>SWAP2</td>
|
||||
<td>w1 w2 w3 w4 -- w3 w4 w2 w1</td>
|
||||
<td>The top four stack items are swapped in pairs. That is, two values
|
||||
<tr><td style="border: 2px solid blue">SWAP2</td>
|
||||
<td style="border: 2px solid blue">SWAP2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 -- w3 w4 w2 w1</td>
|
||||
<td style="border: 2px solid blue">The top four stack items are swapped in pairs. That is, two values
|
||||
are popped and retained. Then, two more values are popped and retained.
|
||||
The values are pushed back onto the stack in the reverse order but
|
||||
in pairs.</p>
|
||||
</tr>
|
||||
<tr><td>OVER</td>
|
||||
<td>OVER</td>
|
||||
<td>w1 w2-- w1 w2 w1</td>
|
||||
<td>Two values are popped from the stack. They are pushed back
|
||||
<tr><td style="border: 2px solid blue">OVER</td>
|
||||
<td style="border: 2px solid blue">OVER</td>
|
||||
<td style="border: 2px solid blue">w1 w2-- w1 w2 w1</td>
|
||||
<td style="border: 2px solid blue">Two values are popped from the stack. They are pushed back
|
||||
onto the stack in the order w1 w2 w1. This seems to cause the
|
||||
top stack element to be duplicated "over" the next value.</td>
|
||||
</tr>
|
||||
<tr><td>OVER2</td>
|
||||
<td>OVER2</td>
|
||||
<td>w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2</td>
|
||||
<td>The third and fourth values on the stack are replicated onto the
|
||||
<tr><td style="border: 2px solid blue">OVER2</td>
|
||||
<td style="border: 2px solid blue">OVER2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2</td>
|
||||
<td style="border: 2px solid blue">The third and fourth values on the stack are replicated onto the
|
||||
top of the stack</td>
|
||||
</tr>
|
||||
<tr><td>ROT</td>
|
||||
<td>ROT</td>
|
||||
<td>w1 w2 w3 -- w2 w3 w1</td>
|
||||
<td>The top three values are rotated. That is, three value are popped
|
||||
<tr><td style="border: 2px solid blue">ROT</td>
|
||||
<td style="border: 2px solid blue">ROT</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 -- w2 w3 w1</td>
|
||||
<td style="border: 2px solid blue">The top three values are rotated. That is, three value are popped
|
||||
off the stack. They are pushed back onto the stack in the order
|
||||
w1 w3 w2.</td>
|
||||
</tr>
|
||||
<tr><td>ROT2</td>
|
||||
<td>ROT2</td>
|
||||
<td>w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2</td>
|
||||
<td>Like ROT but the rotation is done using three pairs instead of
|
||||
<tr><td style="border: 2px solid blue">ROT2</td>
|
||||
<td style="border: 2px solid blue">ROT2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2</td>
|
||||
<td style="border: 2px solid blue">Like ROT but the rotation is done using three pairs instead of
|
||||
three singles.</td>
|
||||
</tr>
|
||||
<tr><td>RROT</td>
|
||||
<td>RROT</td>
|
||||
<td>w1 w2 w3 -- w2 w3 w1</td>
|
||||
<td>Reverse rotation. Like ROT, but it rotates the other way around.
|
||||
<tr><td style="border: 2px solid blue">RROT</td>
|
||||
<td style="border: 2px solid blue">RROT</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 -- w2 w3 w1</td>
|
||||
<td style="border: 2px solid blue">Reverse rotation. Like ROT, but it rotates the other way around.
|
||||
Essentially, the third element on the stack is moved to the top
|
||||
of the stack.</td>
|
||||
</tr>
|
||||
<tr><td>RROT2</td>
|
||||
<td>RROT2</td>
|
||||
<td>w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2</td>
|
||||
<td>Double reverse rotation. Like RROT but the rotation is done using
|
||||
<tr><td style="border: 2px solid blue">RROT2</td>
|
||||
<td style="border: 2px solid blue">RROT2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2</td>
|
||||
<td style="border: 2px solid blue">Double reverse rotation. Like RROT but the rotation is done using
|
||||
three pairs instead of three singles. The fifth and sixth stack
|
||||
elements are moved to the first and second positions</td>
|
||||
</tr>
|
||||
<tr><td>TUCK</td>
|
||||
<td>TUCK</td>
|
||||
<td>w1 w2 -- w2 w1 w2</td>
|
||||
<td>Similar to OVER except that the second operand is being
|
||||
<tr><td style="border: 2px solid blue">TUCK</td>
|
||||
<td style="border: 2px solid blue">TUCK</td>
|
||||
<td style="border: 2px solid blue">w1 w2 -- w2 w1 w2</td>
|
||||
<td style="border: 2px solid blue">Similar to OVER except that the second operand is being
|
||||
replicated. Essentially, the first operand is being "tucked"
|
||||
in between two instances of the second operand. Logically, two
|
||||
values are popped off the stack. They are placed back on the
|
||||
stack in the order w2 w1 w2.</td>
|
||||
</tr>
|
||||
<tr><td>TUCK2</td>
|
||||
<td>TUCK2</td>
|
||||
<td>w1 w2 w3 w4 -- w3 w4 w1 w2 w3 w4</td>
|
||||
<td>Like TUCK but a pair of elements is tucked over two pairs.
|
||||
<tr><td style="border: 2px solid blue">TUCK2</td>
|
||||
<td style="border: 2px solid blue">TUCK2</td>
|
||||
<td style="border: 2px solid blue">w1 w2 w3 w4 -- w3 w4 w1 w2 w3 w4</td>
|
||||
<td style="border: 2px solid blue">Like TUCK but a pair of elements is tucked over two pairs.
|
||||
That is, the top two elements of the stack are duplicated and
|
||||
inserted into the stack at the fifth and positions.</td>
|
||||
</tr>
|
||||
<tr><td>PICK</td>
|
||||
<td>PICK</td>
|
||||
<td>x0 ... Xn n -- x0 ... Xn x0</td>
|
||||
<td>The top of the stack is used as an index into the remainder of
|
||||
<tr><td style="border: 2px solid blue">PICK</td>
|
||||
<td style="border: 2px solid blue">PICK</td>
|
||||
<td style="border: 2px solid blue">x0 ... Xn n -- x0 ... Xn x0</td>
|
||||
<td style="border: 2px solid blue">The top of the stack is used as an index into the remainder of
|
||||
the stack. The element at the nth position replaces the index
|
||||
(top of stack). This is useful for cycling through a set of
|
||||
values. Note that indexing is zero based. So, if n=0 then you
|
||||
get the second item on the stack. If n=1 you get the third, etc.
|
||||
Note also that the index is replaced by the n'th value. </td>
|
||||
</tr>
|
||||
<tr><td>SELECT</td>
|
||||
<td>SELECT</td>
|
||||
<td>m n X0..Xm Xm+1 .. Xn -- Xm</td>
|
||||
<td>This is like PICK but the list is removed and you need to specify
|
||||
<tr><td style="border: 2px solid blue">SELECT</td>
|
||||
<td style="border: 2px solid blue">SELECT</td>
|
||||
<td style="border: 2px solid blue">m n X0..Xm Xm+1 .. Xn -- Xm</td>
|
||||
<td style="border: 2px solid blue">This is like PICK but the list is removed and you need to specify
|
||||
both the index and the size of the list. Careful with this one,
|
||||
the wrong value for n can blow away a huge amount of the stack.</td>
|
||||
</tr>
|
||||
<tr><td>ROLL</td>
|
||||
<td>ROLL</td>
|
||||
<td>x0 x1 .. xn n -- x1 .. xn x0</td>
|
||||
<td><b>Not Implemented</b>. This one has been left as an exercise to
|
||||
<tr><td style="border: 2px solid blue">ROLL</td>
|
||||
<td style="border: 2px solid blue">ROLL</td>
|
||||
<td style="border: 2px solid blue">x0 x1 .. xn n -- x1 .. xn x0</td>
|
||||
<td style="border: 2px solid blue"><b>Not Implemented</b>. This one has been left as an exercise to
|
||||
the student. See <a href="#exercise">Exercise</a>. ROLL requires
|
||||
a value, "n", to be on the top of the stack. This value specifies how
|
||||
far into the stack to "roll". The n'th value is <em>moved</em> (not
|
||||
@ -814,20 +841,25 @@ using the following construction:</p>
|
||||
how much to rotate. That is, ROLL with n=1 is the same as ROT and
|
||||
ROLL with n=2 is the same as ROT2.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">MEMORY OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td>MALLOC</td>
|
||||
<td>MALLOC</td>
|
||||
<td>w1 -- p</td>
|
||||
<td>One value is popped off the stack. The value is used as the size
|
||||
<tr><td colspan="4"><b>MEMORY OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue">MALLOC</td>
|
||||
<td style="border: 2px solid blue">MALLOC</td>
|
||||
<td style="border: 2px solid blue">w1 -- p</td>
|
||||
<td style="border: 2px solid blue">One value is popped off the stack. The value is used as the size
|
||||
of a memory block to allocate. The size is in bytes, not words.
|
||||
The memory allocation is completed and the address of the memory
|
||||
block is pushed onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td>FREE</td>
|
||||
<td>FREE</td>
|
||||
<td>p -- </td>
|
||||
<td>One pointer value is popped off the stack. The value should be
|
||||
<tr><td style="border: 2px solid blue">FREE</td>
|
||||
<td style="border: 2px solid blue">FREE</td>
|
||||
<td style="border: 2px solid blue">p -- </td>
|
||||
<td style="border: 2px solid blue">One pointer value is popped off the stack. The value should be
|
||||
the address of a memory block created by the MALLOC operation. The
|
||||
associated memory block is freed. Nothing is pushed back on the
|
||||
stack. Many bugs can be created by attempting to FREE something
|
||||
@ -839,20 +871,20 @@ using the following construction:</p>
|
||||
the stack (for the FREE at the end) and that every use of the
|
||||
pointer is preceded by a DUP to retain the copy for FREE.</td>
|
||||
</tr>
|
||||
<tr><td>GET</td>
|
||||
<td>GET</td>
|
||||
<td>w1 p -- w2 p</td>
|
||||
<td>An integer index and a pointer to a memory block are popped of
|
||||
<tr><td style="border: 2px solid blue">GET</td>
|
||||
<td style="border: 2px solid blue">GET</td>
|
||||
<td style="border: 2px solid blue">w1 p -- w2 p</td>
|
||||
<td style="border: 2px solid blue">An integer index and a pointer to a memory block are popped of
|
||||
the block. The index is used to index one byte from the memory
|
||||
block. That byte value is retained, the pointer is pushed again
|
||||
and the retained value is pushed. Note that the pointer value
|
||||
s essentially retained in its position so this doesn't count
|
||||
as a "use ptr" in the FREE idiom.</td>
|
||||
</tr>
|
||||
<tr><td>PUT</td>
|
||||
<td>PUT</td>
|
||||
<td>w1 w2 p -- p </td>
|
||||
<td>An integer value is popped of the stack. This is the value to
|
||||
<tr><td style="border: 2px solid blue">PUT</td>
|
||||
<td style="border: 2px solid blue">PUT</td>
|
||||
<td style="border: 2px solid blue">w1 w2 p -- p </td>
|
||||
<td style="border: 2px solid blue">An integer value is popped of the stack. This is the value to
|
||||
be put into a memory block. Another integer value is popped of
|
||||
the stack. This is the indexed byte in the memory block. A
|
||||
pointer to the memory block is popped off the stack. The
|
||||
@ -862,28 +894,33 @@ using the following construction:</p>
|
||||
pushed back on the stack so this doesn't count as a "use ptr"
|
||||
in the FREE idiom.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">CONTROL FLOW OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td>RETURN</td>
|
||||
<td>RETURN</td>
|
||||
<td> -- </td>
|
||||
<td>The currently executing definition returns immediately to its caller.
|
||||
<tr><td colspan="4"><b>CONTROL FLOW OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue">RETURN</td>
|
||||
<td style="border: 2px solid blue">RETURN</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">The currently executing definition returns immediately to its caller.
|
||||
Note that there is an implicit <code>RETURN</code> at the end of each
|
||||
definition, logically located at the semi-colon. The sequence
|
||||
<code>RETURN ;</code> is valid but redundant.</td>
|
||||
</tr>
|
||||
<tr><td>EXIT</td>
|
||||
<td>EXIT</td>
|
||||
<td>w1 -- </td>
|
||||
<td>A return value for the program is popped off the stack. The program is
|
||||
<tr><td style="border: 2px solid blue">EXIT</td>
|
||||
<td style="border: 2px solid blue">EXIT</td>
|
||||
<td style="border: 2px solid blue">w1 -- </td>
|
||||
<td style="border: 2px solid blue">A return value for the program is popped off the stack. The program is
|
||||
then immediately terminated. This is normally an abnormal exit from the
|
||||
program. For a normal exit (when <code>MAIN</code> finishes), the exit
|
||||
code will always be zero in accordance with UNIX conventions.</td>
|
||||
</tr>
|
||||
<tr><td>RECURSE</td>
|
||||
<td>RECURSE</td>
|
||||
<td> -- </td>
|
||||
<td>The currently executed definition is called again. This operation is
|
||||
<tr><td style="border: 2px solid blue">RECURSE</td>
|
||||
<td style="border: 2px solid blue">RECURSE</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">The currently executed definition is called again. This operation is
|
||||
needed since the definition of a word doesn't exist until the semi colon
|
||||
is reacher. Attempting something like:<br/>
|
||||
<code> : recurser recurser ; </code><br/> will yield and error saying that
|
||||
@ -891,24 +928,24 @@ using the following construction:</p>
|
||||
to:<br/>
|
||||
<code> : recurser RECURSE ; </code></td>
|
||||
</tr>
|
||||
<tr><td>IF (words...) ENDIF</td>
|
||||
<td>IF (words...) ENDIF</td>
|
||||
<td>b -- </td>
|
||||
<td>A boolean value is popped of the stack. If it is non-zero then the "words..."
|
||||
<tr><td style="border: 2px solid blue">IF (words...) ENDIF</td>
|
||||
<td style="border: 2px solid blue">IF (words...) ENDIF</td>
|
||||
<td style="border: 2px solid blue">b -- </td>
|
||||
<td style="border: 2px solid blue">A boolean value is popped of the stack. If it is non-zero then the "words..."
|
||||
are executed. Otherwise, execution continues immediately following the ENDIF.</td>
|
||||
</tr>
|
||||
<tr><td>IF (words...) ELSE (words...) ENDIF</td>
|
||||
<td>IF (words...) ELSE (words...) ENDIF</td>
|
||||
<td>b -- </td>
|
||||
<td>A boolean value is popped of the stack. If it is non-zero then the "words..."
|
||||
<tr><td style="border: 2px solid blue">IF (words...) ELSE (words...) ENDIF</td>
|
||||
<td style="border: 2px solid blue">IF (words...) ELSE (words...) ENDIF</td>
|
||||
<td style="border: 2px solid blue">b -- </td>
|
||||
<td style="border: 2px solid blue">A boolean value is popped of the stack. If it is non-zero then the "words..."
|
||||
between IF and ELSE are executed. Otherwise the words between ELSE and ENDIF are
|
||||
executed. In either case, after the (words....) have executed, execution continues
|
||||
immediately following the ENDIF. </td>
|
||||
</tr>
|
||||
<tr><td>WHILE (words...) END</td>
|
||||
<td>WHILE (words...) END</td>
|
||||
<td>b -- b </td>
|
||||
<td>The boolean value on the top of the stack is examined. If it is non-zero then the
|
||||
<tr><td style="border: 2px solid blue">WHILE (words...) END</td>
|
||||
<td style="border: 2px solid blue">WHILE (words...) END</td>
|
||||
<td style="border: 2px solid blue">b -- b </td>
|
||||
<td style="border: 2px solid blue">The boolean value on the top of the stack is examined. If it is non-zero then the
|
||||
"words..." between WHILE and END are executed. Execution then begins again at the WHILE where another
|
||||
boolean is popped off the stack. To prevent this operation from eating up the entire
|
||||
stack, you should push onto the stack (just before the END) a boolean value that indicates
|
||||
@ -924,60 +961,65 @@ using the following construction:</p>
|
||||
the top of stack is decremented to 0 at which the WHILE test fails and control is
|
||||
transfered to the word after the END.</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">INPUT & OUTPUT OPERATIONS</td></tr>
|
||||
<tr><td>Word</td><td>Name</td><td>Operation</td><td>Description</td></tr>
|
||||
<tr><td>SPACE</td>
|
||||
<td>SPACE</td>
|
||||
<td> -- </td>
|
||||
<td>A space character is put out. There is no stack effect.</td>
|
||||
<tr><td colspan="4"><b>INPUT & OUTPUT OPERATORS</b></td></tr>
|
||||
<tr>
|
||||
<td style="border: 2px solid blue"><u>Word</u></td>
|
||||
<td style="border: 2px solid blue"><u>Name</u></td>
|
||||
<td style="border: 2px solid blue"><u>Operation</u></td>
|
||||
<td style="border: 2px solid blue"><u>Description</u></td>
|
||||
</tr>
|
||||
<tr><td>TAB</td>
|
||||
<td>TAB</td>
|
||||
<td> -- </td>
|
||||
<td>A tab character is put out. There is no stack effect.</td>
|
||||
<tr><td style="border: 2px solid blue">SPACE</td>
|
||||
<td style="border: 2px solid blue">SPACE</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A space character is put out. There is no stack effect.</td>
|
||||
</tr>
|
||||
<tr><td>CR</td>
|
||||
<td>CR</td>
|
||||
<td> -- </td>
|
||||
<td>A carriage return character is put out. There is no stack effect.</td>
|
||||
<tr><td style="border: 2px solid blue">TAB</td>
|
||||
<td style="border: 2px solid blue">TAB</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A tab character is put out. There is no stack effect.</td>
|
||||
</tr>
|
||||
<tr><td>>s</td>
|
||||
<td>OUT_STR</td>
|
||||
<td> -- </td>
|
||||
<td>A string pointer is popped from the stack. It is put out.</td>
|
||||
<tr><td style="border: 2px solid blue">CR</td>
|
||||
<td style="border: 2px solid blue">CR</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A carriage return character is put out. There is no stack effect.</td>
|
||||
</tr>
|
||||
<tr><td>>d</td>
|
||||
<td>OUT_STR</td>
|
||||
<td> -- </td>
|
||||
<td>A value is popped from the stack. It is put out as a decimal integer.</td>
|
||||
<tr><td style="border: 2px solid blue">>s</td>
|
||||
<td style="border: 2px solid blue">OUT_STR</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A string pointer is popped from the stack. It is put out.</td>
|
||||
</tr>
|
||||
<tr><td>>c</td>
|
||||
<td>OUT_CHR</td>
|
||||
<td> -- </td>
|
||||
<td>A value is popped from the stack. It is put out as an ASCII character.</td>
|
||||
<tr><td style="border: 2px solid blue">>d</td>
|
||||
<td style="border: 2px solid blue">OUT_STR</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A value is popped from the stack. It is put out as a decimal integer.</td>
|
||||
</tr>
|
||||
<tr><td><s</td>
|
||||
<td>IN_STR</td>
|
||||
<td> -- s </td>
|
||||
<td>A string is read from the input via the scanf(3) format string " %as". The
|
||||
<tr><td style="border: 2px solid blue">>c</td>
|
||||
<td style="border: 2px solid blue">OUT_CHR</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">A value is popped from the stack. It is put out as an ASCII character.</td>
|
||||
</tr>
|
||||
<tr><td style="border: 2px solid blue"><s</td>
|
||||
<td style="border: 2px solid blue">IN_STR</td>
|
||||
<td style="border: 2px solid blue"> -- s </td>
|
||||
<td style="border: 2px solid blue">A string is read from the input via the scanf(3) format string " %as". The
|
||||
resulting string is pushed onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td><d</td>
|
||||
<td>IN_STR</td>
|
||||
<td> -- w </td>
|
||||
<td>An integer is read from the input via the scanf(3) format string " %d". The
|
||||
<tr><td style="border: 2px solid blue"><d</td>
|
||||
<td style="border: 2px solid blue">IN_STR</td>
|
||||
<td style="border: 2px solid blue"> -- w </td>
|
||||
<td style="border: 2px solid blue">An integer is read from the input via the scanf(3) format string " %d". The
|
||||
resulting value is pushed onto the stack</td>
|
||||
</tr>
|
||||
<tr><td><c</td>
|
||||
<td>IN_CHR</td>
|
||||
<td> -- w </td>
|
||||
<td>A single character is read from the input via the scanf(3) format string
|
||||
<tr><td style="border: 2px solid blue"><c</td>
|
||||
<td style="border: 2px solid blue">IN_CHR</td>
|
||||
<td style="border: 2px solid blue"> -- w </td>
|
||||
<td style="border: 2px solid blue">A single character is read from the input via the scanf(3) format string
|
||||
" %c". The value is converted to an integer and pushed onto the stack.</td>
|
||||
</tr>
|
||||
<tr><td>DUMP</td>
|
||||
<td>DUMP</td>
|
||||
<td> -- </td>
|
||||
<td>The stack contents are dumped to standard output. This is useful for
|
||||
<tr><td style="border: 2px solid blue">DUMP</td>
|
||||
<td style="border: 2px solid blue">DUMP</td>
|
||||
<td style="border: 2px solid blue"> -- </td>
|
||||
<td style="border: 2px solid blue">The stack contents are dumped to standard output. This is useful for
|
||||
debugging your definitions. Put DUMP at the beginning and end of a definition
|
||||
to see instantly the net effect of the definition.</td>
|
||||
</tr>
|
||||
@ -989,9 +1031,9 @@ using the following construction:</p>
|
||||
<p>The following fully documented program highlights many features of both
|
||||
the Stacker language and what is possible with LLVM. The program has two modes
|
||||
of operations. If you provide numeric arguments to the program, it checks to see
|
||||
if those arguments are prime numbers, prints out the results. Without any
|
||||
if those arguments are prime numbers and prints out the results. Without any
|
||||
aruments, the program prints out any prime numbers it finds between 1 and one
|
||||
million (there's a log of them!). The source code comments below tell the
|
||||
million (there's a lot of them!). The source code comments below tell the
|
||||
remainder of the story.
|
||||
</p>
|
||||
</div>
|
||||
@ -1321,7 +1363,13 @@ this exercise.<p>
|
||||
interested, here are some things that could be implemented better:</p>
|
||||
<ol>
|
||||
<li>Write an LLVM pass to compute the correct stack depth needed by the
|
||||
program.</li>
|
||||
program. Currently the stack is set to a fixed number which means programs
|
||||
with large numbers of definitions might fail.</li>
|
||||
<li>Enhance to run on 64-bit platforms like SPARC. Right now the size of a
|
||||
pointer on 64-bit machines will cause incorrect results because of the 32-bit
|
||||
size of a stack element currently supported. This feature was not implemented
|
||||
because LLVM needs a union type to be able to support the different sizes
|
||||
correctly (portably and efficiently).</li>
|
||||
<li>Write an LLVM pass to optimize the use of the global stack. The code
|
||||
emitted currently is somewhat wasteful. It gets cleaned up a lot by existing
|
||||
passes but more could be done.</li>
|
||||
@ -1335,10 +1383,10 @@ interested, here are some things that could be implemented better:</p>
|
||||
technique out until I was nearly done with LLVM. As it is, its a bad example
|
||||
of how to insert instructions!</li>
|
||||
<li>Provide for I/O to arbitrary files instead of just stdin/stdout.</li>
|
||||
<li>Write additional built-in words.</li>
|
||||
<li>Write additional built-in words; with inspiration from FORTH</li>
|
||||
<li>Write additional sample Stacker programs.</li>
|
||||
<li>Add your own compiler writing experiences and tips in the <a href="#lessons">
|
||||
Lessons I Learned About LLVM</a> section.</li>
|
||||
<li>Add your own compiler writing experiences and tips in the
|
||||
<a href="#lessons">Lessons I Learned About LLVM</a> section.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<!-- ======================================================================= -->
|
||||
|
Loading…
Reference in New Issue
Block a user